1.套接字结构
多数套接字函数都有套接字结构参数,每个协议族都定义了自己的套接字结构,以 sockaddr_ 开始,并对应协议族的唯一后缀。
如 IPv4 sockaddr_in
IPv6 sockaddr_in6
Unix sockaddr_un
链路 sockaddr_dl
存储 sockaddr_storage
struct sockaddr_in { uint8_t sin_len; sa_family_t sin_family; in_port_t sin_port; struct in_addr sin_addr; char sin_zero[8]; }
其中 sin_len 用于内核层,在应用读写都无意义。
sin_zero 没有用处。
POSIX也要求要定义 sin_family, sin_addr, sin_port
2.传参
套接字调用,参数以引用方式,在内核和应用传递。
当参数 ,应用 ----> 内核,需要传 len_of_socket
如: bind, connect, sendto
内核 -----> 应用,需要传 &len_of_socket
即 len_of_socket 做输入,输出参数。
3.字节序
网络字节序为大端,即先存储数据高位。
小端,则为 先存储数据地位。
可以如下判断主机字节序:
union { short a; char b[sizeof(short)]; }c = {0x01, 0x00}; if (c[0] == 0 && c[1] == 1) { printf("小端\n"); } else if (c[0] == 1 && c[1] == 0) { printf("大端\n"); } else { printf("未知\n") }
对于大小端转换函数,推荐 inet_pton, inet_ntop
不推荐 inet_aton, inet_ntoa,因为不支持 IPv6
3.封装api
为了兼容多种情况,可以进行如下封装:
char * sock_ntop(const struct sockaddr *sa, socklen_t salen) { switch(sa->sa_family) { case AF_INET: ..... beak; .... } }
另外,对套接字的读写不同于一般文件读写,套接字读写,即使返回值未达到预期,也不一定错误,因为可能是缓冲区满了,就需要将剩下的数据继续操作。
类似的,其他缓冲区(如管道)读写也是这样。
所以需要封装 readn, writen 等函数。
来源:https://www.cnblogs.com/yangxinrui/p/12219581.html