套接字描述符
套接字是通信端点的抽象,和文件描述符类似,程序通过套接字描述符访问套接字。事实上,套接字在UNIX中就是一种文件描述符,许多处理文件描述符的函数(如read、write)也可以用于处理套接字。
socket函数创建一个套接字。
1 |
|
参数domain(域)描述了通行的特性,有以下取值:
- AF_INET:IPv4因特网域
- AF_INET6:IPv6因特网域
- AF_UNIX:UNIX域
- AF_UPSPEC:未指定
参数type确定套接字类型,POSIX.1定义了以下套接字类型:
- SOCK_DGRAM:固定长度、无连接的、不可靠的报文传递
- SOCK_RAW:IP协议的数据报接口(POSIX.1中可选)
- SOCK_SEQPACKET:固定长度的、有序的、可靠的、面向连接的报文传递
- SOCK_STREAM:有序的、可靠的、双向的、面向连接的字节流
SOCK_STREAM提供字节流服务,应用程序分辨不出报文界限,从该套接字读取数据时,不会返回发送进程的所有字节数,需要多次函数调用才能获得所有数据。
SOCK_SEQPACKET提供基于报文服务,从该套接字获取的数据量与发送方一致。SCTP提供因特网域上的顺序数据包服务。
SOCK_RAW提供数据报接口,直接访问下层网络层(即IP层),应用程序自己负责构造协议头部。
参数protocol通常为0,表示给定的域和套接字类型选择默认协议。AF_INET中,type为SOCK_STREAM默认协议为TCP;AF_INET中,type为SOCK_DGRAM默认协议为UDP。
调用close可以关闭对套接字的访问,释放该套接字以重新使用。
函数shutdown可以禁止一个套接字的I/O
1 |
|
参数how为SHUT_RD,表示关闭读端,无法从套接字读取数据;若为SHUT_WR,表示关闭写端,无法向套接字发送数据;若为SHUT_RDWR,表示即无法读取数据,也无法发送数据。
寻址
进程标识用于标志一个通行目标进程,由两部分组成:一部分为计算机的网络地址,标识了想要通信的计算机;另一部分为端口号,标识了特定的进程。
字节序
与不同计算机的进程通信,需要考虑字节序,字节序有大端法和小端法。Linux、FreeBSD、MAC OS为小端法,Solaris为大端法。
网络协议指定了字节序,因此计算机通信时不会被字节序混淆。TCP/IP协议为大端字节序。
对于TCP/IP应用程序,有4个函数用于主机字节序与网络字节序之间的转换。
1 |
|
h表示主机,n表示网络,l表示长(4字节)整数、s表示短(2字节)整数。
地址格式
为使不同地址能够传入套接字函数,地址会被强制转换成一个通用地址结构sockaddr:
1 | struct sockaddr { |
套接字实现可以自由添加额外成员。
在IPv4因特网域(AF_INET)中,套接字结构为sockaddr_in:
1 | struct in_addr { |
IPv6因特网域(AF_INET6)套接字结构为sockaddr_in6:
1 | struct in6_addr { |
尽管sockaddr_in和sockaddr_in6结构相差较大,但它们均被强制转换成sockaddr结构输入套接字程序中。
函数inet_ntop和inet_pton用于二进制地址格式和点分十进制表示(a.b.c.d)之间的转换,并且同时支持IPv4和IPv6。
1 |
|
inet_ntop将网络字节序的二进制地址转换成文本字符串格式,inet_pton将文本字符串格式转换成网络字节序的二进制地址。
参数domain只支持AF_INET和AF_INET6。
参数size指定了保存文本字符串的str的大小,INET_ADDRSTRLEN定义了足够存放IPv4的大小,INET6_ADDRSTRLEN定义了足够存放IPv6的大小。