套接字地址结构
该结构在两个方向上传递:从进程到内核和从内核到进程。
适用于IPV4的地址转换函数为:inet_addr、inet_ntoa
适用于IPV4和IPV6的地址转换函数:inet_pton, inet_ntop
每个协议族都定义它自己的套接字地址结构,它们均以sockaddr_开头,并以协议族的唯一后缀结尾。
如IPV4套接字地址结构同城称为:“网际套接字地址结构”,它的名字为 socketaddr_in,头文件是<netinet/in.h>
struct sockaddr_in { sa_family_t sin_family; /* address family: AF_INET */ in_port_t sin_port; /* port in network byte order */ struct in_addr sin_addr; /* internet address */ }; /* Internet address. */ struct in_addr { uint32_t s_addr; /* address in network byte order */ }; sin_family is always set to AF_INET.
套接字地址结构仅在给定主机上使用:虽然结构中的某些字段(如IP地址和端口号)用在不同主机之间的通信中,但是结构本身并不在主机之间传递。
通用套接字地址结构
在作为参数传递给套接字函数时,套接字地址结构总是以指针形式来传递。
struct sockaddr { sa_family_t sa_family; char sa_data[14]; }
因此,在使用套接字函数时,需要将特定协议的套接字地址的指针进行强制类型转换。如:
struct sockaddr_in my_addr bind(sfd, (struct sockaddr *) &my_addr, sizeof(struct sockaddr_un)
不进行转换的话,编译器会产生警告信息:提示把不兼容的指针类型传递给 bind函数的第二个参数。
所以,通用地址结构的唯一用途就是进行类型转换。
IPV6地址结构
struct sockaddr_in6 { sa_family_t sin6_family; /* AF_INET6 */ in_port_t sin6_port; /* port number */ uint32_t sin6_flowinfo; /* IPv6 flow information */ struct in6_addr sin6_addr; /* IPv6 address */ uint32_t sin6_scope_id; /* Scope ID (new in 2.4) */ }; struct in6_addr { unsigned char s6_addr[16]; /* IPv6 address */ }; sin6_family is always set to AF_INET6;
新的通用套接字地址结构
略
地址结构的传递
方式1:从进程到内核 bind connect sendto
方式2:从内核到进程 accept recvfrom getsockname getpeername
字节序:
小端:低位字节放在低地址
大端:于小端相反
(如何判断一个机器的字节序?)
主机字节序:某个给定系统所用的字节序
网络字节序:网络协议指定的字节序
网际协议字节序为大端字节序
字节序转换函数
htons htonl ntohs ntohl h:host n:network s:short l:long
那些与网络字节序(大端)相同的系统中,这四个函数通常被定义为空宏
字节操作函数
bzero bcmp bcopy
memset memcpy memcmp
地址转换函数
将字符串形式的ip地址与网络字节序的二进制(存放在套接字地址结构中的值)之间转换
inet_aton inet_addr(被废弃) inet_ntoa : 适用于ipv4
inet_pton inet_ntop :适用于 ipv4 ipv6 。 p: presentation 表达(字符串形式) n:numeric 数值
字节流操作函数
字节流套接字(如TCP套接字)上进行read、write不同于通常文件上的I/O。字节流套接字上调用read、write输入输出的字节数可能比请求的数量少
然而这并不是出错状态。这个现象的原因在于内核中用于套接字的缓冲区可能已经到达了极限。此时需要再次调用read或write函数,以处理剩余的字节。
这个现象在read一个字节流套接字时很常见,但是write一个字节流套接字时只能在该套接字为非阻塞的前提下才出现。