1、Socket Descriptor(1)socket是一个抽象的通信endpoint,许多对fd有效的函数比如read write对soket descriptor同样有效
(2)socket()创建一个socket
#include <sys/socket.h>
int socket(int domain, int type, int protocol);
Returns: file(socket) descriptor if OK, -1 on error
|
domain:
Domain |
Description |
|
|
AF_INET |
IPv4 Internet domain |
AF_INET6 |
Ipv6 Internet domain |
AF_UNIX |
UNIX domain |
AF_UNSPEC |
unspecified |
type: Type | Description |
| |
SOCK_DGRAM | fixed-length, connectionless, unreliable message |
SOCK_RAW | datagram interface to IP (optional in POSIX.1) |
SOCK_SEQPACKET | fixed-length, sequenced, reliable, connection-oritentd messages |
SOCK_STREAM | sequenced, reliable, bidirectional, connection-oritentd byte streams
|
protocol:通常为0 AF_INET,SOCK_STREAM默认协议为TCP
AF_INET,SOCK_DGRAM默认协议为UDP
(3)作用于FD的函数在SOCKET上的表现
Functon |
Behavior with socket |
|
|
close |
deallocates the socket |
dup, dup2 |
duplicates the file descriptor as normal |
fchdir |
失败,errno==ENOTDIR |
fchmod |
unspecified |
fchown |
implementation defined |
fcntl |
支持一些命令: F_DUPFD, F_GETFD, F_GETFL, F_GETOWN, F_SETFD, F_SETFL 和 F_SETOWN |
fdatasync, fsync |
implementation defined |
fstat | 支持一些struct stat成员,但是怎么支持留给了配置 |
ftruncate |
unspecified |
getmsg, getpmsg |
如果配置成STREAMS,则支持 |
ioctl |
根据底层驱动,一些命令支持 |
lseek |
implemetation defined(一般失败,errno == ESPIPE) |
mmap |
unspecified |
poll |
正常工作 |
putmsg, putpmsg |
如果配置成STREAMS,则支持 |
read, readv |
等同于不带任何flag的recv |
select |
正常工作 |
write, writev |
等同于不带任何flag的send |
(4)disable I/O on a socket#include <sys/socket.h>
int shutdown(int sockfd, int how);
Returns: 0 if OK, -1 on error
|
how: SHUT_RD:关闭read
SHUT_WR:关闭write
SHUT_RDWR:关闭读写
注:close只有在最后一个活动reference关闭,才会deallocate网络endpoint;而shutdown没有这个限制,立即deactive,同时,shutdown可以只关闭读或者写
2、Addressing
(1)big-endian and little-endian
表达数字:0x11223344
低地址 |
0x |
|
|
|
高地址 |
big-endian |
11 |
22 |
33 |
44 |
|
little-endian |
44 |
33 |
22 |
11 |
|
MSB(Most Significant Byte):最高有效位0x11,跟byte order没关系
LSB(Least Significant Byte):最低有效位0x44,跟byte order没关系
Operating system |
Processor architecture |
Byte order |
| |
|
FreeBSD 5.2.1 |
Intel Pentium |
little-endian |
Linux 2.4.22 |
Intel Pentium |
little-endian |
Mac OS X 10.3 |
PowerPC |
big-endian |
Solaris 9 |
Sun SPARC |
big-endian |
(2)转换函数
#include <appa/inet.h>
uint32_t htonl(uint32_t hostint32);
Returns: 32-bit integer in network byte order
uint16_t htons(uint16_t hostint 16);
Returns: 16-bit integer in network byte order
uint32_t ntohl(uint32_t netint32);
Returns: 32-bit integer in host byte order
uint16_t ntohs(uint16_t netint 16);
Returns: 16-bit integer in host byte order
|
(3)Address Formats(linux)
struct sockaddr {
sa_family_t sa_family; // address family
char sa_data[14]; // variable-length address
};
#include <netinet/in.h>
struct in_addr{
in_addr_t s_addr; // Ipv4 address
};
struct sockaddr_in {
sa_family_t sin_family;// address family
in_port_t sin_port; // port number
struct in_addr sin_addr;// Ipv4 address
unsigned char sin_zero[8]; // filler
};
|
(4)ip地址(a.b.c.d)和二进制地址转换只针对IPV4
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
int inet_aton(const char *cp, struct in_addr *inp);
//转换网络主机地址cp为二进制数值,并存储在struct in_addr结构中,即第二个参数*inp,函数返回非0表示cp主机有地有效,返回0表示主机地址无效
in_addr_t inet_addr(const char *cp);
//转换网络主机地址(如192.168.1.10)为网络字节序二进制值,如果参数char *cp无效,函数返回-1(INADDR_NONE),这个函数在处理地址为255.255.255.255时也返回- 1,255.255.255.255是一个有效的地址,不过inet_addr无法处理
char *inet_ntoa(struct in_addr in);
//转换网络字节排序的地址为标准的ASCII以点分开的地址,该函数返回指向点分开的字符串地址指针。该字符串的空间为静态分配,这意味着在第二次调用该函数时,上一次调用会被重写(覆盖),所以如果需要保存该串最后复制出来自己管理
|
针对IPV4和IPV6
#include <arpa/inet.h>
const char *inet_ntop(int domain, const void *restrict addr, char *restrict str, socklen_t size);
Returns: pointer to address string on success, NULL on error
int inet_pton(int domain, const char *restrict str, void *restrict addr);
Returns: 1 on success, 0 if the format is invalid, or -1 on error
|
domain: AF_INET or AF_INET6size:存储str的buffer大小,一般设置为INET_ADDRSTRLEN或者INET6_ADDRSTRLEN
inet_pton的addr: 必须大到容纳IPV4或者IPV6的地址
(5)获取host database file
#include <netdb.h>
struct hostent *gethostent(void);
Returns: pointer if OK, NULL on error
void sethostent(int stayopen);
void endhostent(void);
|
gethostent返回文件的下一个entry; sethostent打开文件,如果已经打开了,回绕(rewind)它; endhostent关闭文件。struct hostent {
char *h_name; // name of host
char **h_aliases; // pointer to alternate host name array
int h_addrtype; // address type
int h_length; // length in bytes of address
char **h_addr_list; // pointer to array of network address
.
.
.
};
|
(6)获取主机名字旧函数
#include <unistd.h>
int gethostname(char *name, size_t len);
参数说明:
这个函数需要两个参数:
接收缓冲区name,其长度必须为len字节或是更长
接收缓冲区name的最大长度
返回值:
如果函数成功,则返回0。如果发生错误则返回-1。错误号存放在外部变量errno中。
int getdomainname(char *name,size_t len);
参数说明:
这个函数的用法也gethostname相同。
struct hostent *gethostbyaddr(const char *name)
传入值是IP地址(注意,这里不是简单的字符串,需要先将字符串形式的IP地址由inet_aton转化一下),然后经过函数处理,将结果由返回值传出。返回值是一个hostent结构.因为有了hosten这个传出的结构,我们可以在这个结构里面找到我们想需要的信息。
#include <netdb.h>
#include <sys/socket.h>
struct hostent *gethostbyname(const char *name);
这个函数的传入值是域名或者主机名,例如"","wpc"等等。
传出值,是一个hostent的结构。如果函数调用失败,将返回NULL。
|
取代函数#include <netdb.h>
struct netent *getnetbyaddr(uint32_t net, int type);
struct netent *getnetbyname(const char *name);
struct netent *getnetent(void);
All return: pointer if OK, NULL on error
void setnetent(int stayopen);
void endnetent(void);
struct netent{
char *name; // network name
char **n_aliases; // alternate network name array pointer
int n_addrtype; // address type
uint32_t network number;
.
.
.
};
|
(7)map between protocol names and numbers
#include <netdb.h>
struct protoent *getprotobyname(const char *name);
struct protoent *getprotobynumber(int proto);
struct protoent(void);
All return: pointer if OK, NULL on error
void setprotoent(int stayopen);
void endprotoent(void);
|
stuct protoent:struct protoent{
char *p_name; //protocol name
char **p_aliases; // pointer to alternate protocol name array
int p_proto; //protocol number
.
.
.
} ;
|
(8)map between server name and port number#include <netdb.h>
struct servent *getservbyname(const char *name, const char *proto);
struct servent *getservbyport(int port, const char *proto);
struct servent *getservent(void);
All return: pointer if OK, NULL on error
void setservent(int stayopen);
void endservent(void);
struct servent {
char *s_name; //server name
char **s_aliases; // pointer to alternate service name array
int s_port; // port number
char *s_proto; // name of protocol
.
.
.
};
|
(9)map “主机名or服务名” to “地址”
#include <sys/socket.h>
#include <netdb.h>
int getaddrinfo(const char *restrict host, const char *restrict service, const struct addrinfo *restrict hint, struct addrinfo **restrict res);
Returns: 0 if OK, nonzero error code on error
void freeaddrinfo(struct addrinfo *ai);
struct addrinfo{
int ai_flags; // customize behavior,P556
int ai_family; // address family
int ai_socktype; // socket type
int ai_protocol; // protocol
socklen_t ai_addrlen; // length in bytes of address
struct sockaddr *ai_addr; // address
char *ai_canonname; // canonical name of host
struct addrinfo *ai_next; // next in list
.
.
.
};
|
getaddrinfo返回的是一个struct addrinfo的链表
如果返回错误,必须用gai_strerror转换error code到error message
#include <netdb.h>
const char *gai_strerror(int error);
Returns: a pointer to a string describing the error
|
(9)map "地址" to "主机名+服务名"#include <sys/socket.h>
#include <netdb.h>
int getnameinfo(const struct sockaddr *restrict addr, socklen_t alen, char *restrict host, socklen_t host_len, char *restrict service, socklen_t servlen, unsigned int flags); P557
Returns: 0 if OK, nonzero on error
|
(10)Associate Addresses with Sockets
#include <sys/socket.h>
int bind(int sockfd, const struct sockaddr *addr, socklen_t len);
Returns: 0 if OK, -1 on error
|
注:1、地址端口号不能小于1024,除非是superuser才能这么设定; 2、只能是1个socket endpoint绑定到给定地址,虽然有一些协议允许duplicate bindings
3、如果地址设置为INADDR_ANNY,则socket endpoint绑定到系统上所有的network interface上,这样可以接受从系统上所有网卡传送过来的包
#include <sys/socket.h>
int getsockname(int sockfd, struct sockaddr *restrict addr, socklen_t *restrict alenp);
Returns: 0 if OK, -1 on error
|
注:1、查看绑定到socket的地址 2、alenp:指向一个整数,包含sockaddr buffer的大小,一旦函数返回,就被设置返回的地址大小; 如果buffer太小,返回的地址会被truncated
#include <sys/socket.h>
int getpeername(int sockfd, struct sockaddr *restrict addr, socklen_t *restrict alenp)
|
注:1、获取peer地址,其它同getsockname
阅读(1207) | 评论(0) | 转发(0) |