Socket Programming Considerations (2)

Posted on 2010-07-28 09:23 天快黑了 阅读(1653) 评论(1)  编辑  收藏 所属分类: Socket
 

1.       Socket ack (acknowledgement)

Socket ack是指当socket接收到数据之后,发送一个ack字符串(比如$ACK)socket发送方。这样,socket发送方可以根据是否收到了ack判断对方是否收到了数据。

Socket ack是显示的在应用程序中加入的一种通讯协议。如果不使用ack,在socket通讯中,可能会丢失数据。

比如,socket client要连续的给socket server发送100条消息。如果我们在server收到第50条消息的时候,强行killserver。那么查询client端发送的log,可能client端成功发送了51条。只有当client端发送第52条消息的时候才遇到异常。这样第51条消息就丢失了。

所以为了确保数据传输的准确性,我们可以引入ack协议。有时我们不仅要确保server不但收到了数据,而且还要保证server成功处理了数据。这时,可以等server成功处理完数据之后,再给clientack

2.       Socket Keep Alive

Socket连接像数据库连接一样,属于重量型资源。如果我们频繁的创建socket、发送/接收数据、关闭socket,那么会有很大一部分时间浪费在socket的创建和关闭上。

所以,如果我们经常需要与同一个socket地址发送/接收数据时,应该考虑只创建一次socket,然后一直使用这个socket对象发送/接收数据。

3.       Heartbeat

通常,我们会设置socketreceive timeout。这样,如果我们一直打开着socket (keep alive) 而很长时间又没有数据通讯,socket接收方就会timeout,最终导致打开的连接坏掉。

如果很长时间没有数据通讯,防火墙或代理服务器也可能会关闭打开的socket连接。

所以为了保证打开的socket连接一直可用,如果一段时间没有数据进行通讯(或指定一个时间间隔),我们可以显示的发送一个heartbeat消息(比如: $HRT)给对方,从而保证连接不会被异常关闭。

4.       Socket Close

每一个socket对象会持有一个socket descriptor (其实就是file descriptor),操作系统对于socket descriptor有一个最大限制。因此当socket不再使用时,一定要记得关闭,即使socket连接失败或出现异常,只要socket对象不为null,一定要记得关闭。

下面图显示了,当socket关闭时,socket的状态变化(socket状态可以通过netstat命令查看)。更详细的解释,可以google一下。


当主动一方调用close(先调用close)时的状态变化:

ESTABLISHED -> FIN_WAIT_1-> FIN_WAIT_2 -> TIME_WAIT -> CLOSED

当被动一方调用close(后调用close)时的状态变化:

ESTABLISHED -> CLOSE_WAIT -> LAST_ACK -> CLOSED

通常,TIME_WAIT 是正常状态,过一段时间(2MSL, 14分钟)就会自动消失.

我们需要特别注意CLOSE_WAIT 状态:

1.   如果很长时间才消失,表明socket server处理太慢,很多client已经连接到server,发送完数据并close了。

2.   如果一直也不消失,表明有socket没有正常close (对方已经close)

5.       SO_REUSEADDR Option

socket主动调用close的时候,从上面可以知道,它最终会进入TIME_WAIT 状态,需要过14分钟,才能完全close

socket处于TIME_WAIT 状态时,它仍然占用正在使用的IP/PORT。这样,如果我们的程序(比如socket server)使用了一个固定的IP/PORT,当socket处于TIME_WAIT 状态时,程序将不能立即重启,会出现端口占用错误。

Socket提供了一个setReuseAddress()方法,可以设置当socket处于TIME_WAIT 状态时,是否允许其它进程绑定这个端口。

如果我们正在开发socket server,一定要记得调用ServerSocket.setReuseAddress(true).

Client socket也有这个方法,而且有时可能需要指明client连接server时所使用的本地IP/PORT(一般不用指明,系统会随机选择一个PORT)。但实际测试,在client socket上设置这个方法在WindowsSolaris下并不起作用。当socket处于TIME_WAIT 状态时,重启client仍然出现端口占用错误。上网搜索了很长时间,很多人都碰到了这个问题,可能是操作系统底层socket实现问题。因为测试使用C语言开发的socket client,同样也有这个错误。有人说LINUX下好用,还有就是可以尝试修改tcp_time_wait_interval来减小TIME_WAIT等待时间

Feedback

# re: Socket Programming Considerations (2)[未登录]  回复  更多评论   

2010-07-28 17:35 by 匿名
总体来说写的不错,看来对socket还是有比较好的理解的。
关于setReuseAddress,这个还是设置成true比较好,
但是要做好地址和端口的检测工作。如果再加上跨平台
和多网卡就比较麻烦。

只有注册用户登录后才能发表评论。


网站导航:
 

posts - 5, comments - 25, trackbacks - 0, articles - 1

Copyright © 天快黑了