TCP Server和Client模型:linux
1 #include <sys/types.h> /* See NOTES */ 2 #include <sys/socket.h> 3 4 int bind(int sockfd, const struct sockaddr *addr,socklen_t addrlen);
做用是绑定addr中的<IP:PORT>, 对于tcp server通常port是固定的。当系统有多个IP(多网卡)时,把ip设置为INADDR_ANY, 内核会自动分配ip。若是只有单一的IP,选择服务器
机器IP和INADDR_ANY效果是同样的。app
客户和服务器经过调用函数bind时能够指定IP地址或端口号,能够都指定,也能够都不指定:异步
l 客户端
1. TCP客户端:socket
1) 当TCP客户未绑定IP地址,当它调用connect时内核会根据外出接口给它绑定一个IP地址和一个临时端口号。而且TCP服务器在接到这个链接后会以这个IP地址做为回应数据报的目的IP地址。 2) 当TCP客户绑定了IP地址,它就为发出的数据链接指定了一个源IP地址,而且TCP服务器在接到这个链接后会以这个IP地址做为回应数据报的目的IP地址。 3) TCP客户只能根据四元组(原端口号,原IP地址,目的端口号,目的IP地址)接受数据报。
2. UDP客户端:tcp
1) 当UDP客户未绑定IP地址,当它调用sendto时内核会根据外出接口给它绑定一个IP地址和一个临时端口号。(UDP客户能够接收到达它绑定的临时端口的任何UDP数据报)。 2) 当UDP客户绑定了IP地址,它就为发出的数据报指定了一个源IP地址,而且UDP服务器在接到这个数据报后会以这个IP地址做为回应数据报的目的IP地址。(UDP客户只能接收到达它绑定的临时端口而且目的地址为它绑定的IP地址的UDP数据报)。 3) 当UDP客户调用connect,内核记录下对方的IP地址和端口号,它们包含在传递给connect的套接口地址结构中,并为UDP客户绑定了一个临时端口号和IP地址。(UDP客户只能接收目的IP地址为它绑定的IP地址和端口号而且源IP地址为它指定对方的IP地址和端口号的数据报)。
l 服务器端
1. TCP服务器:ide
1) 当TCP服务器绑定通配IP地址,套接口会接收到达它绑定端口的任何TCP链接。并以接收的目的IP地址做为它的源IP地址(用以肯定四源组),以接收的源IP地址做为它的目的IP地址发回应答。 2) 当TCP服务器绑定本地IP地址,这就限制了套接口只接收到达它绑定端口而且目的地址为此IP地址的客户链接。以绑定的目的IP地址做为源IP地址(固然,绑定的IP地址确定与接收链接的目的IP地址相同,不然它不会接收),并以接收的源IP地址做为它的目的IP地址发回应答。
通常只有在本机有多个网卡(多IP)才有效。如服务器SERVER有IP地址IPA和IPB,服务bind了IPA,那么发送给IPB的数据SERVER不会接收。若是是bind IPADDR_ANY, 则发到该服务器上的请求都会接受。
2. UDP服务器:函数
1) 当UDP服务器绑定通配IP地址,套接口会接收到达它绑定端口的任何UDP数据报。并以数据报的外出接口的主IP地址为源IP地址,以接收到的源IP地址做为它的目的IP地址发回应答。 2) 当UDP服务器绑定本机IP地址,这就限制了套接口只接收到达它绑定端口而且目的地址为此IP地址的UDP数据报。并以绑定的IP地址做为源IP地址,以接收的源IP地址做为它的目的IP地址发回应答。 3) 当UDP服务器调用connect,内核记录下对方的IP地址和端口号,它们包含在传递给connect的套接口地址结构中,并为UDP服务器绑定了一个临时端口号和IP地址。(UDP服务器只能接收目的IP地址为它绑定的IP地址和端口号而且源IP地址为它指定对方的IP地址和端口号的数据报)。
二、connect函数this
1 #include <sys/types.h> /* See NOTES */ 2 #include <sys/socket.h> 3 4 int connect(int sockfd, const struct sockaddr *addr, socklen_t addrlen);
对于客户端的 connect() 函数,该函数的功能为客户端主动链接服务器,创建链接是经过三次握手,而这个链接的过程是由内核完成,不是这个函数完成的,这个函数的做用仅仅是通知 Linux 内核,让 linux 内核自动完成 TCP 三次握手链接,最后把链接的结果返回给这个函数的返回值(成功链接为0, 失败为-1)。spa
一般的状况,客户端的 connect() 函数默认会一直阻塞,直到三次握手成功或超时失败才返回(正常的状况,这个过程很快完成)。
三、
listen() 函数的主要做用就是将套接字( sockfd )变成被动的链接监听套接字(被动等待客户端的链接), listen()函数不会阻塞,它主要作的事情为,将该套接字和套接字对应的链接队列长度告诉 Linux 内核,而后,listen()函数就结束。
这样的话,当有一个客户端主动链接(connect()),Linux 内核就自动完成TCP 三次握手,将创建好的连接自动存储到队列中,如此重复。
因此,只要 TCP 服务器调用了 listen(),客户端就能够经过 connect() 和服务器创建链接,而这个链接的过程是由内核完成。
关于backlog,Linux内核中维护两个队列:SYN_queue(SYN报文接收)和 ACCEPT queue(Established, Server收到ACK,三次握手完成)
a) When a connection request arrives (i.e., the SYN segment), the system-wide parameter net.ipv4.tcp_max_syn_backlog is checked (default 1000).
If the number of connections in the SYN_RCVD state would exceed this threshold, the incoming connection is rejected
客户端connect发送SYN请求,服务端内核先检查是否超过了SYN,没有超过则加入到SYN queue,服务器的 SYN 响应,其中稍带对客户 SYN 的 ACK(即SYN+ACK)
b)Each listening endpoint has a fixed-length queue of connections that have been completely accepted by TCP (i.e., the three-way handshake is complete) but not yet accepted by the application
Accept queue中的tcp链接是内核创建完三次握手,可是应用程序尚未调用accept取出连接。这个队列的大小就是backlog
The application specifies a limit to this queue, commonly called the backlog. This backlog must be between 0 and a system-specific maximum called net.core.somaxconn,
inclusive (default 128)
backlog has no effect whatsoever on the maximum number of established connections allowed by the system, or on the number of clients that a concurrent server can handle concurrently.
accept queue和最大tcp链接数无关
c)If there is room on this listening endpoint’s queue for this new connection, the TCP module ACKs the SYN and completes the connection. The server application with the listening endpoint does not see this new connection until the third segment of the three-way handshake is received.
若是SYN队列未满,TCP接收SYN请求并返回SYN的ACK,服务器并不感知这一过程。
Also, the client may think the server is ready to receive data when the client’s active open completes successfully, before the server application has been notified of the new connection. If this happens, the server’s TCP just queues the incoming data.
客户端在Connect返回成功后(三次握手完成,连接已经进入服务端的Accept队列),就认为服务端准备好接收数据。此时服务端可能没有调用Accept函数把连接从Accept队列取出。此时服务端tcp内核只是把数据存入缓冲区。
d) If there is not enough room on the queue for the new connection, the TCP delays responding to the SYN, to give the application a chance to catch up .it persists in not ignoring incoming connections if it possibly can .
若是SYN队列满,TCP延迟响应客户端SYN请求。此时客户端会超时重试。
If the net.ipv4.tcp_abort_on_overflow system control variable is set, new incoming connections arereset with a reset segment.
若是服务端开启net.ipv4.tcp_abort_on_overflow,该SYN请求会被拒绝,服务端发送RST报文。
2、select/epoll区别