注册 登录  
 加关注
   显示下一条  |  关闭
温馨提示!由于新浪微博认证机制调整,您的新浪微博帐号绑定已过期,请重新绑定!立即重新绑定新浪微博》  |  关闭

还东国的博客

行之苟有恒,久久自芬芳

 
 
 

日志

 
 

closesocket的过程  

2014-06-05 09:17:34|  分类: 网络服务编程技术 |  标签: |举报 |字号 订阅

  下载LOFTER 我的照片书  |

closesocket的过程

在一些SOCKET操作的细节上,还是有一些认知不太清楚的地方,也有的是看了就忘记,所以还是要总结出来,以咨为记。

今天在走查代码时发现,一段代码中的SOCKET没有被关闭,这是会引起资源泄露的,所以就增加了closesocket这个函数。然后把它的工作流程在网上找了些资料:

简述:

关闭一个套接口。

#include <winsock.h>

int PASCAL FAR closesocket( SOCKET s);

s:一个套接口的描述字。

注释:

本函数关闭一个套接口。更确切地说,它释放套接口描述字s,以后对s的访问均以WSAENOTSOCK错误返回。若本次为对套接口的最后一次访问,则相应的名字信息及数据队列都将被释放。closesocket()的语义受SO_LINGERSO_DONTLINGER选项影响,对比如下:

选项 间隔 关闭方式 等待关闭与否

SO_DONTLINGER 不关心 优雅

SO_LINGER 强制

SO_LINGER 非零 优雅

若设置了SO_LINGER(亦即linger结构中的l_onoff域设为非零),并设置了零超时间隔,则closesocket()不被阻塞立即执行,不论是否有排队数据未发送或未被确认。这种关闭方式称为“强制”或“失效”关闭,因为套接口的虚电路立即被复位,且丢失了未发送的数据。在远端的recv()调用将以WSAECONNRESET出错。

若设置了SO_LINGER并确定了非零的超时间隔,则closesocket()调用阻塞进程,直到所剩数据发送完毕或超时。这种关闭称为“优雅的”关闭。请注意如果套接口置为非阻塞且SO_LINGER设为非零超时,则closesocket()调用将以WSAEWOULDBLOCK错误返回。

若在一个流类套接口上设置了SO_DONTLINGER(也就是说将linger结构的l_onoff域设为零;则closesocket()调用立即返回。但是,如果可能,排队的数据将在套接口关闭前发送。请注意,在这种情况下WINDOWS套接口实现将在一段不确定的时间内保留套接口以及其他资源,这对于想用所以套接口的应用程序来说有一定影响。

返回值:

如无错误发生,则closesocket()返回0。否则的话,返回SOCKET_ERROR错误,应用程序可通过WSAGetLastError()获取相应错误代码。

错误代码:

WSANOTINITIALISED:在使用此API之前应首先成功地调用WSAStartup()

WSAENETDOWNWINDOWS套接口实现检测到网络子系统失效。

WSAENOTSOCK:描述字不是一个套接口。

WSAEINPROGRESS:一个阻塞的WINDOWS套接口调用正在运行中。

WSAEINTR:通过一个WSACancelBlockingCall()来取消一个(阻塞的)调用。

WSAEWOULDBLOCK:该套接口设置为非阻塞方式且SO_LINGER设置为非零超时间隔。

   一般来说,tcp正常关闭需要四个包。比如ab关闭连接,a b发一个finb会进行确认ack,然后b也会发出fin,当a接受到这个fin,并发出最后一个ack后,就会处于time_wait状态。这个时 间长短跟操作系统有关,一般会在1-4分钟,也就是两倍的数据包(2msl:标准文档的建议值是2min)最大生存时间。TCP主动关闭方采用TIME_WAIT主要是为了实现终止 TCP全双工连接的可靠性及允许老的重复分节在网络中消逝,等过了2msl(大约1~4分钟)TIME_WAIT就会消失。TIME_WAIT状态的目的是为了防止最后a发出的ack丢失,让b处于LAST_ACK超时重发FIN

   所以说,主动发起关闭连接的一方会进入time_wait状态,这个时候,进程所占用的端口号不能被释放。除非在你的程序中用setsockopt设置端口可重用(SOCK_REUSE)的选项,但这不是所有操作系统都支持的。

 

   解决TIME_WAIT的办法主要有以下几种:  

 

   1、修改LINGER值,缩短关闭时间;

   LINGER    lingerStruct;

   lingerStruct.l_onoff    =    1;

   lingerStruct.l_linger     =    0;

   setsockopt(m_socket,SOL_SOCKET,SO_LINGER,(char *)&lingerStruct,sizeof(lingerStruct));

   不过这种办法不是很安全的,不过现在网络都很好啦,不会有问题的。

 

   2、修改注册表;

   [HKEY_LOCAL_MACHINE\SYSTEM\ControlSet001\Services\Tcpip\Parameters]

   "TcpTimedWaitDelay"=dword:00000005

   这个值好像是300秒到30秒之间,改成30秒后你会发现TIME_WAIT很快就会消失了。

 

   3、禁用LINGER

   //如果你使用的是Socket API,可以这样

   BOOL bDontLinger=FALSE;     

   setsockopt(m_socket,SOL_SOCKET,SO_DONTLINGER,(LPCTSTR)&bDontLinger,sizeof(BOOL));

   closesocket(s);

   //如果你使用的是CAsyncSocket,需要响应的修改,例如禁用LINGER可以这样

   BOOL bDontLinger=FALSE;  

   m_socket->SetSockOpt(SO_DONTLINGER,(const char *)&bDontLinger,sizeof(bDontLinger),SOL_SOCKET);

   m_socket->Close();

 

   4、客户端可以不BIND(),这样,即使断开连接后再次连接,SOCKET将使用不同的端口(1025-5000) 等几分钟后,原有的端口就会自动关闭。

 

从网上找了些资料,算是对closesocket的一个总结吧。

  评论这张
 
阅读(481)| 评论(0)
推荐 转载

历史上的今天

在LOFTER的更多文章

评论

<#--最新日志,群博日志--> <#--推荐日志--> <#--引用记录--> <#--博主推荐--> <#--随机阅读--> <#--首页推荐--> <#--历史上的今天--> <#--被推荐日志--> <#--上一篇,下一篇--> <#-- 热度 --> <#-- 网易新闻广告 --> <#--右边模块结构--> <#--评论模块结构--> <#--引用模块结构--> <#--博主发起的投票-->
 
 
 
 
 
 
 
 
 
 
 
 
 
 

页脚

网易公司版权所有 ©1997-2017