大多数套接字函数都需要一个指向套接字地址结构的指针作为参数。
IPV4套接字地址结构
struct in_addr { in_addr_t s_addr; //32bits }; struct sockaddr_in { uint8_t sin_len; //8bits; sa_family_t sin_family; //8bits or 16bits in_port_t sin_port; //16bits struct in_addr sin_addr; //32bits char sin_zero[8]; //unused 8 * 8bits};
但是一般的函数不接受这个struct类型的,为了接受其他类型如IPV6等通常定义一个通用的套接字结构
struct sockaddr { uint8_t sa_len; sa_family_t sa_famlily; char sa_data[14]; };
bind(sockfd, (struct sockaddr *)&servaddr, sizeof(servaddr));
网络字节序是大端的,对于小端的机器来说,必须将其转换成大端后再发送,为了可移植,无论大小端都使用一下函数进行变换
htons和htonl
h for host
n for network
s for short 16bit
l for long 32bits //
使用以下函数将ascii字符串与网络字节序的二进制值进行转换
inet_pton 和 inet_ntop
n for numric 数值
p for presentation 表达
基本的套接字编程:
int socket(int family, int type, int protocol);
为了执行网络I/O,一个进程必须调用socket函数,指定期望的通信协议类型:如ipv4 tcp等
为了使用ipv4的tcp协议
需指定family = AF_INET, type 为SOCK_STREAM, 而protocol为0表示前面2个参数的默认组合,其默认组合为0.
socket成功返回时返回一个小的非负整数。与文件描述符类似,称为套接字描述符。
int connect(int sockfd, const struct sockaddr *servaddr, socklen_t addrlen);
失败情形:
1. 若TCP发送的SYN分组没有回应,则出现ETIMEOUT错误。
2. 若对客户端的响应是RST表示对端没有servaddr指定的端口上的进程,应错误,立马返回,errno设为ECONNREFUSED
3. 若客户发出的SYN在中间的路由器上引发一个destination unreachable 的ICMP错误,认为是一种软错误,在规定时间内仍为收到ack和syn响应后,则将ICMP错误作为
EHOSTUNREACH或者ENETUNREACH错误返回给进程。可由以下两种情形引发:
(1) 按照本地系统的转发表,根本无法达到远程系统的路径;
(2) connect调用根本不等待就返回
注意:
若connect失败则该套接字不再可用,必须关闭,不能对该套接字再次调用connect,必须重新调用socket函数。
int bind(int sockfd. const struct sockaddr *myaddr, socklen_t addrlen);
bind函数把一个本地协议地址赋予一个套接字
int listen(int sockfd, int backlog);
1. 将一个未连接的套接字转换成被动套接字,指示内核应接受指向该套接字的连接请求。该套接字状态由CLOSED变成LISTEN。
2. 规定了内核应该为响应套接字排队的最大连接个数。(backlog指定)
int accept(int sockfd, struct sockaddr *cliaddr, socklen_t *addrlen);
参数cliaddr和addrlen用来返回已连接的对端进程的协议地址。如果成功则返回由内核自动生成的一个全新的描述符。代表与所返回的客户的TCP连接。