分类: 嵌入式
2015-06-21 19:01:43
原文地址:Linux中如何优雅的关闭Socket通信 作者:sinbingzoo
close和shutdown的区别:
int close(int sockfd);
close(fd)调用会将描述字的引用计数减1,只有当socket描述符的引用计数为0时,才关闭socket,即发送FIN包,因此,在fork()模式中,父进程在accept()返回后,fork()子进程,由子进程处理connfd,而父进程将close(connfd);由于connfd这个socket描述符的引用计数不为0,因此并不引发FIN,所以就没有关闭和客户端的连接。
int shutdown(int sockfd, int howto);#include
int shutdown(int sockfd,int how);
how的方式有三种分别是
SHUT_RD(0):关闭sockfd上的读功能,此选项将不允许sockfd进行读操作。
SHUT_WR(1):关闭sockfd的写功能,此选项将不允许sockfd进行写操作。
SHUT_RDWR(2):关闭sockfd的读写功能。
close()引发的4次交互:(这里的close是client发起的) client server
FIN_WAIT_1 ---- FIN M ------>
//(Server端操作系统的TCP层(网络协议栈)响应ACK包)
FIN_WAIT_2 <---- ACK M+1---- CLOSE_WAIT
//(这里必须调用close,才能从CLOSE_WAIT到LAST_ACK)
TIME_WAIT <------ FIN N ----- LAST_ACK
//(TIME_WAIT有一个重要的作用就是防止最后一个ACK丢失)
------- ACK N+1 ----> CLOSE
TIME_WAIT 是主动关闭链接时形成的,等待2MSL时间,约4分钟。
主要是防止最后一个ACK丢失。 由于time_wait的时间会非常长,因此server端应尽量减少主动关闭连接
CLOSE_WAIT是被动关闭链接是形成的 ,
按状态机,我方收到FIN,则由TCP实现发送ACK,因此进入CLOSE_WAIT状态。
但如果我方不执行close(),就不能由CLOSE_WAIT迁移到LAST_ACK,则系统中会存在很多CLOSE_WAIT状态的连接。
此时,可能是系统忙于处理读、写操作,而未将已收到FIN的连接,进行close。此时,recv/read已收到FIN的连接socket,会返回0。
大量TIME_WAIT和CLOSE_WAIT的存在,会产生怎样的影响?
内核维护更多的状态。收到ip包,做hash运算,hlist冲突的概率更大。close-----关闭本进程的socket id,但链接还是开着的,用这个socket id的其它进程还能用这个链接,能读或写这个socket id
shutdown--则破坏了socket 链接,读的时候可能侦探到EOF结束符,写的时候可能会收到一个SIGPIPE信号,这个信号可能直到
socket buffer被填充了才收到,shutdown还有一个关闭方式的参数,0 不能再读,1不能再写,2 读写都不能。
目前遇到的问题
单个进程里的close 关闭不会出问题,不管是客户端还是服务器端主动发起(已经验证)
在多进程的socket通信中(接收和读取分不同进程进行),对socket关闭在某个进程中出现问题,error:bad file descriptor。
学习使用close和shutdown来关闭socket。特别是多个客户端连接着服务器端时
问题起源:多个客户端连接着服务器时,出现一个客户端退出时,在服务进程中会频繁recv 0.如何处理客户端退出收到后收到的这个0,是直接退出exit吗?
答:还是需要close后再退出较为合理
在多进程中采用采用协议退出的办法,可以无问题地close掉,并将子进程关闭掉,否则会出现很多漏退出的子程序
具体是:客户端需要退出,发送进程发协议码告诉服务器,此时客户端可以close,但等待几秒退出发送进程,服务器接收进程回应协议码,然后close,等待几秒exit接收进程
然后客户端接收进程接收后调用close,等待几秒exit接收进程。
服务器的发送进程采用由其接收进程通过管道得知需要退出或测试时使用自动定时退出。