罕用的数据结构及函数
地址转换类
主机字节序与网络字节序的转换
主机序通常为小端,网络字节序为大端。下列函数在 <netinet/in.h> 包中:
- usinged long int htonl(unsigned long int hostlong) —— 主机序转网络序(host to network long)
- usinged short int htons(unsigned short int hostlong) —— 主机序转网络序(host to network short)
- usinged long int ntohl(unsigned long int hostlong) —— 网络序转主机序(network to host long)
- usinged short int ntohl(unsigned short int hostlong) —— 网络序转主机序(network to host short)
IP 地址转换函数
计算机可能辨认二进制的 IP 地址,但生存中咱们罕用点分十进制来示意 IPv4 地址,用十六进制示意 IPv6 地址,于是须要一些函数对他们进行一些转换,这些函数位于 <arpa/inet.h> 包中。
- in_addr_t inet_addr(const char* strprt) —— 将点分十进制 IPv4 地址转化成网络字节序的地址
- int inet_aton(const char cp, struct in_addr inp) —— 同上,将后果存在指针里
- char* inet_ntoa(struct in_addr in) —— 将二进制后果转为点分十进制
- int inet_pton(int af, const char src, void dst) —— 将十六进制地址转为二进制地址,并存在指针。其中 af 示意地址族,能够是 AF_NET 或 AF_NET6。
- const char inet_ntop(int af, const void src, char* dst, socklen_t cnt) —— 将二进制地址转换为十六进制地址,其中 cnt 指定指标存储单元大小
socket 地址构造
通用 socket 地址——sockaddr
#include <bits/socket.h>
struct sockaddr {
sa_family_t sa_family;
char sa_data[14];
}
其中,sa_family 是地址族,包含:PF_UNIX(UNIX 本地区协定族)、PF_INET(TCP/IPv4 地址协定族)、PF_INET6(IPv6 地址协定族)。留神:AF_xxx 和 PF_xxx 在 socket.h 中值雷同,因而常混用。
sa_data 用于寄存 socket 地址值,不同协定的地址具备不同含意和长度。PF_UNIX 寄存的是文件的路径名(疑难:在 PF_UNIX 中,socket 是以一个什么样的模式存在的?),长度可达到 108 字节;在 PF_INET 中,寄存 16bit 的端口号和 32bit 的 IPv4 地址;在 AF_INET6 中,寄存的是 128bit 的 IPv6 地址、16bit 端口号以及 32bit 的 ID。
因为 14 字节显然无奈容下所有地址,因而 linux 中 sockaddr 定义为:
#include <bits/socket.h>
struct sockaddr {
sa_family_t sa_family;
unsigned long int __ss_align;
char __ss_padding[128-sizeof(__ss_align)];
}
linux 下各协定的 socket 地址
- PF_UNIX 的 socket 地址构造:
#include <sys/un.h>
struct sockaddr_un {
sa_family_t sin_family;
char sun_path[108]; // 文件路径名
}
- PF_INET 的 socket 地址构造;
struct sockaddr_in {
sa_family_t sin_family;
u_int16_t sin_port; // 端口号
struct in_addr sin_addr; //IPv4 构造体
}
struct in_addr {u_int32_t s_addr;}
- PF_INET6 的 socket 地址构造;
struct sockaddr_in6 {
sa_family_t sin_family;
u_int16_t sin_port; // 端口号
u_int32_t sin6_flowinfo; // 流信息,应设置为 0
struct in6_addr sin6_addr; //IPv4 构造体
u_in32_t sin6_scope_id;
}
struct in_addr {unsigned char sa_addr[16];
}
留神:所有专用 socket 地址在理论应用时都须要强制转换为通用 sockaddr!
socket 通信罕用根底函数
创立 socket
int socket(int domain, int type, int protocol);
其中 domain 为底层协定族,即 PF_UNIX, AF_INET, AF_NET6;
type 为服务类型,次要分为 SOCK_STREAM(流服务)和 SOCK_UGRAM(数据报服务),TCP 面向流,UDP 面向数据报。
protocol 示意在前两个参数形成的汇合下,再抉择一个具体的协定。但因为这个汇合通常只有一个值,个别状况下 protocol 都设置为 0。
该函数设置胜利时会返回一个 socket 文件描述符,失败时会返回 - 1 并设置 errno
留神:若设置失败,能够应用 perror()来打印具体的错误信息
socket 命名(绑定)—— 仅服务端应用
int bind(int sockfd, const struct sockaddr* my_addr, socklen_t addrlen);
bind 作用是将由 socket()创立后的未经调配的文件描述符与一个 ip 地址绑定。留神:下面提到的须要强制地址转换就是在这里进行。addrlen 间接用 sizeof 即可。
监听 socket —— 仅服务端应用
int listen(int sockfd, int backlog)
此处的 backlog 指所有处于齐全连贯和半连贯状态的客户端 socket 下限。最多可有 backlog+ 1 个 socket 申请连贯。
接管连贯 —— 仅服务端应用
int accept(int sockfd, struct sockaddr addr, socklen_t addrlen)
该函数作用是从 listen()监听的队列中接管一个连贯,接管后返回一个新的 连贯 socket,服务器可通过读写该 socket 与客户端进行通信。
留神:对于客户端来说,accept 仅仅只是从申请连贯的 socket 当选一个进去进行连贯,而不论客户端是否放弃连贯
发动连贯 —— 仅客户端应用
int accept(int sockfd, struct sockaddr serv_addr, socklen_t addrlen)
敞开连贯
int close(int fd)