相关函数
socket
作用
建立一个套接字,并将相应的资源分配给它,同时返回一个整型套接字号。
函数
// socket(协议族, socket类型, 具体协议)
int socket(int protofamily, int so_type, int protocol);
bind
作用
将创建的socket绑定到指定的IP地址和端口上。
函数
// bind(socket, 本地IP+端口号, 地址长度)
int bind(int sockfd, const struct sockaddr *addr, socklen_t addrlen);
客户端为什么不用bind
因为可以在connect时由系统自动分配地址
listen
作用
服务器调用listen函数实现监听服务
函数
// listen(sockfd, 最大连接个数)
int listen(int sockfd, int backlog)
connect
作用
由客户端调用,用来与服务器建立TCP连接,实际是发起3次握手过程
函数
// connect(客户端sockfd, 服务器协议地址, 地址缓冲区长度)
int connect(int sockfd, struct sockaddr *serv_addr, int addrlen)
UDP的connect
●UDP可以使用connect(),作用是在UDP套接字中记住目的地址和目的端口
●connect可以让UDP性能提升,因为如果不调用connect,每次sendto发送完数据,内核都会将临时保存的对端地址删除掉。
●connect后如果数据报不是指定的地址和端口,将被丢弃。
accept
作用
服务器调用,从已完成连接队列中返回下一个建立成功的连接,如果已完成连接队列为空,线程阻塞
函数
int accept (int sockfd, struct sockaddr *addr, socklen_t *addrlen)
执行流程
(1)服务器端在调用listen之后,内核会建立两个队列,SYN队列和ACCEPT队列,其中ACCPET队列的长度由backlog指定。
(2)服务器端在调用accpet之后,将阻塞,等待ACCPT队列直到有元素。
(3)客户端在调用connect之后,将开始发起SYN请求,请求与服务器建立连接,此时称为第一次握手。
(4)服务器端在接受到SYN请求之后,把请求方放入SYN队列中,并给客户端回复一个确认帧ACK,此帧还会携带一个请求与客户端建立连接的请求标志,也就是SYN,这称为第二次握手
(5)客户端收到SYN+ACK帧后,connect返回,并发送确认建立连接帧ACK给服务器端。这称为第三次握手
(6)服务器端收到ACK帧后,会把请求方从SYN队列中移出,放至ACCEPT队列中,而accept函数也等到了自己的资源,从阻塞中唤醒,从ACCEPT队列中取出请求方,重新建立一个新的sockfd,并返回。
send()
主要是进行TCP类型的数据发送。
// send(发送端sockfd, 待发送数据的缓冲区, 待发送的数据长度, flags)
int send(int sockfd, const void *msg, int len, int flags)
recv()
主要用于TCP类型的数据接收。
// recv(接收方sockfd, 接收缓冲区地址, 接收缓冲区长度, flags)
int recv(int sockfd, void *buf, int len, unsigned int flags)