客户端在调用connect前,不必非得调用bind,因为如果需要的话,内核会确定源IP地址,并选择一个临时端口作为源端口。
如果是TCP套接字,调用connect会激发TCP的“三次握手”。
listen
调用listen后的套接字,称为监听套接字,listen把一个未连接的套接字转换成一个被动套接字,指示内核应接受指向该套接字的连接请求。
内核为监听套接字维护两个队列:
1、未完成连接队列, 每个SYN分节对应其中一项,SYN已由某个客户发出,并到达服务器,而服务器正在等待完成相应的TCP三次握手过程,这些套接字处于SNY_RCVD状态。
2、已完成连接队列,每个已经完成三次握手的客户对应其中一项。这些套接字处于ESTABLISHED状态
accept
int accept(int sockfd, struct sockaddr *cliaddr, socklen_t *addrlen);
由TCP服务器调用,用于从已完成队列头返回下一个已经完成连接。如果已完成连接队列为空,那么进程被投入睡眠(假定套接字为默认的阻塞方式)
cliaddr , addrlen 用来返回已连接的对端进程(客户)的协议地址。
如果accept成功,返回值为内核自动生成的一个全新描描述符,代表与所返回客户的TCP连接。
sockfd为:监听套接字描述符
accept的返回值:已连接套接字描述符。
一个服务器通常仅仅创建一个监听套接字描述符,它在该服务器的生命周期内一直存在。内核为每个由服务器进程接受的客户连接创建一个
已连接套接字(也就是说对于它的TCP三次握手过程已经完成)。当服务器完成对某个给定客户的服务时,相应的已连接套接字就关闭。
fork and exec
用于派生新进程。
fork调用一次,返回两次。
父进程中调用fork之前打开的所有描述符在fork返回之后由子进程分享。
迭代服务器
但个客户长期占用服务,结束后,才能允许其他客户连接。
并发服务器
通过fork,创建子进程来服务每个客户。
描述符引用计数
并发服务器中父进程关闭已连接套接字只是导致相应描述符的引用计数值减1。既然引用计数值大于0,这个close调用并不引发TCP的
四分组连接终止序列。
而调用shutdown汉书可以立即在某个TCP连接上发送一个FIN。
记住,任何进程在任何时刻可以拥有打开着的描述符数通常是有限制的。
getsockname getpeername