罕用的数据结构及函数
地址转换类
主机字节序与网络字节序的转换
主机序通常为小端,网络字节序为大端。下列函数在<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)