socket

int socket(int domain, int type, intprotocol);

    监听套接字描述符由socket创建,随后用作bind和listen的第一个参数。一个服务器通常仅创建一个监听套接字,他在该服务器的生命周期内一直存在。


connect

int connect(intsockfd, const struct sockaddr *addr,socklen_t addrlen);

如果是TCP套接字,调用connect将激发TCP的三路握手,仅在连接建立成功或出错时才返回。

         1.若TCP客户没有收到SYN分节响应,返回ETIMEOUT错误,例如调用connect后,内核发送SYN后无响应重传多次后仍未有响应则返回本错误。

         2.若对客户的SYN响应是RST,则表明该服务器主机在我们指定的端口没有进程在等待与之连接(服务器进程也许没有在运行)。客户一接收到

         RST马上返回ECONNREFUSED。

         3.RST是TCP在发生错误时发送的一种TCP分节。产生RST的单个条件是

         3.1 目的地为某端口的SYN到达,而该端口上没有正在监听的服务器;

         3.2 TCP想取消一个已有的连接;

         3.3 TCP接收到一个根本不存在的连接上的分节。

         4.按照TCP状态转换图,connect导致当前套接字从CLOSED状态转移到SYN_SENT状态,若成功则转移至ESTABLISHED状态。若connect失败则该套接字不再可用,必须关闭套接字,重新调用socket。

bind

int bind(intsockfd, const struct sockaddr *addr,socklen_t addrlen);

         1.服务器在启动时捆绑他们的众所周知的端口,如果一个TCP客户/服务未曾调用bind捆绑一个端口,当调用connect/listen时,内核就要为相应套接字选择一个临时端口。让内核来选临时端口对于TCP客户来说时正常的,除非应用需要一个预留端口,然而对于TCP服务器来说罕见,因为服务器是通过众所周知端口被大家认识的。

    2.进程可以把一个特定的IP地址绑定到套接字上,这个IP地址必须属于其所在主机的网络接口之一。对于TCP客户即为套接字上发送的IP数据报指派了源IP地址。对于TCP服务器,限定该套接字只接收目的为该IP地址的客户连接。TCP客户通常不把IP地址捆绑到套接字,当连接时内核根据所用外出网络接口来选择源IP地址,外出接口取决于到达服务器所需的路径。TCP服务器若没有把IP地址绑定到套接字上,内核就把客户发送的SYN的目的IP地址作为源IP地址。例如指定IP地址为通配地址,那么内核将等到套接字已连接(TCP)或已在套接字上发出数据报(UDP)时才选择一个本地IP地址。

         3.运行绑定通配地址服务器,当一个连接到达时,服务器调用getsockname获取来自客户的目的IP地址,然后根据这个客户连接所发往的IP地址来处理客户的请求。

    4.捆绑非通配IP地址的好处是把一个给定目的IP地址解复用到一个给定的服务器进程是由内核而不是服务器进程本身完成。

listen

int listen(intsockfd, int backlog);

         1.当socket创建一个套接字时,他被假设为一个主动套接字,即一个将调用connect发起连接的客户套接字,listen把一个未连接套接字转换为一个被动套接字,指示内核应接收套接字的连接请求。套接字从CLOSED状态转换为LISTEN状态。

         2.本函数第二个参数规定了内核为套接字排队的最大连接个数。内核为任何一个给定的监听套接字维护两个队列:


         2.1 未完成连接队列

         已由某个客户端发出并到达服务器的的SYN分节对应其中一项,服务器正在等待完成相应的TCP三路握手过程。这些套接字处于SYN_RCVD状态。

         2.2 已完成连接队列

         每个已完成TCP三路握手过程的客户对应其中一项,这些套接字处于ESTABLISHED状态。

         每当在未完成连接队列中创建一项时,来自监听套接字的参数就复制到即将建立的连接中。连接的创建机制时完全自动的,无需服务起进程插手。

    当来自客户的SYN到达,TCP在未完成队列中创建一个新项,然后响应以三路握手的第二个分节即服务器的SYN响应,其中捎带对客户SYN的ACK。这一项一直保留在未完成连接队列中,直到三路握手的第三个分节(客户对服务器SYN的ACK)到达或者该项超时(75s)为止。三路握手正常完成,该项就从未完成连接队列移至已完成连接队列的对尾。


         3.对于繁忙的web服务器,对着客户SYN分节的到达,未完成连接队列中的项数可能增大,等着三路握手完成,所以backlog值应该设置大一些,默认最大值见/proc/sys/net/core/somaxconn。

         4.当一个客户SYN到达时,若这些队列时满的,TCP就忽略该分节(不发送RST),因为这种情况时暂时的,客户TCP将重发SYN,期望不久就能在这些队列中找到可用空间,若服务器TCP立即响应一个RST,客户的connect调用就会立即返回一个错误,强制应用进程处理这种情况,而不是让TCP的正常重传机制来处理。客户无法区分响应SYN的RST是因为“服务进程在监听”还是“该端口有服务器在监听但是他的队列满了”。

         5.在三路握手完成之后,但是在服务器调用accept之前到达的数据应由服务器TCP排队,最大数据量为相应已连接套接字的接收缓冲区大小。

accept

int accept(intsockfd, struct sockaddr *addr, socklen_t *addrlen);

用于从已完成连接队列队头返回下一个已完成连接,若已完成连接队列为空,进程被投入睡眠。

    accept成功,其返回值是由内核自动生成的一个全新描述符称为已连接套接字,代表与所返回客户的TCP连接。也就是说对于服务器进程与客户之间的TCP三路握手过程已经完成。当服务器完成对某个给定客户的服务时,相应的已连接套接字就被关闭。

 

 

 

Logo

更多推荐