怎样简单检测socket的健康状态
开发程序经常用到socket,新手熟手一般都会用select、recv和send这样几个函数,而且大多数情况下,会用这几个函数也就差不多了。更深入的开发会发现,现成的socket函数并没有提供检测socket是否健康的函数,通常的资料也并没有现成的方法可用。本文提供了一个方案,在windows和linux下初步测试,效果良好。 必须先声明的是socket通信是双工的(如果读者对此不了解,可先查一下相关资料)。因此socket的健康状态是分两个方向的,一个是你发送(send)的方向,一个是你接收(recv)方向的。只有两个方向都是关闭的,这个socket才是真正关闭的,也只有这两个方向都是健康的,此socket才是真正健康的。真正难以检测的,其实就是这种半健康状态的socket。当然我们也可以认为,如果我们两个方向的状态都可以检测清楚,那么此socket的健康状态我们自然就清楚了。 好了,先认识一下上面提到的三个函数返回值的含义。函数名返回值select0 :超时-1 :socket出错>0 :有数据已到达send0 :发送缓冲区已满-1 :socket出错>0 :本次已发送到缓冲区的字节数recv0 :对方已主动关闭了此socket-1 :socket出错>0 :本次已成功接收的字节数 应该说,你发送(send)方向的健康是由你来控制的,只要你不主动调用close或closesocket,它就是健康的。如果你关闭了这个方向的socket,原则上你一定能记得住,如果实在记不住,getsockname/ getpeername可以帮你检测其状态,它们会返回此socket在本机的IP地址和端口号,如果它们返回-1,那就是你已经主动关闭了这个socket的发送(send)方向。 麻烦在另一端主动关闭了他的发送(send)方向,而这在你看来是你的接收(recv)方向被关闭了。另一端的这个关闭动作理论上是可以随时发生的,不需要事前通知,也没法事后通知,因此只能由你这一方想办法检测。 简单地说,当你的接收(recv)方被关闭后,你的select会返回>0的值(这说明对方有数据发送过来),你的recv会返回0(这说明对方已经主动关闭了你的接收recv方向)。这两个值联合起来,说明对方在主动断开后,确实向你这一方发送了数据,但不幸的是,你一接却是个0字节大小。有关socket的几种状态的资料,网上很多,大家可以自己去查。 上面的方法在通常的实践中就可以使用了,但如果你就想检测socket的接收(recv)方向的状态,就还需要另一个技巧。recv一般是会从缓冲区中拿走数据的,所以当你只想检测状态而又不想拿走数据时,得学会使用recv的第四个参数的用法。通常情况下它是0,但当它为MSG_PEEK时,它的意思是偷看,即看一下缓冲区前面的若干字节,但并不从缓冲区中拿走。在本方案中,只要偷看1个字节就好了,如果返回0,就说明对方已经主动发起关闭了。 我们来总结一下简单地检测socket健康状态的全过程。
1、用getsockname/ getpeername来检测你的发送(send)方向的状态,如果你不知道你是否主动关闭了这个方向;
2、用select和recv(,,1,MSG_PEEK)来共同检测你的接收(recv)方向的状态。 特别说明的是,socket的状态其实分好几种。