近来在做项目的时候,用到了Socket,遇到了点问题,写出来给大家分享。
我们原先采用阻塞模式的Socket,但对该Socket进行Send操作时,发生了任务挂死的现象。经定位,因为该任务的优先级较低,一旦Socket在别处出现问题被关闭重建的当口抢占了该任务,将导致操作系统内部的资源死锁。当然,windows系统可能没这个毛病,没试过,我们的系统是个实时操作系统。我们特殊的需求,不能更改任务的优先级,也不想对该段需要高效执行的代码人为地加上信号量,这样会影响性能。于是我们决定做一系列的修改,其中最重要的修改就是将Socket的IO模式改为非阻塞模式,这样会完全防止任务的挂死。因为非阻塞的Sockect调用Send时会立即返回而不管是否发送成功。
于是,问题就出现了。大家可参考Unix下的Socket编程,看看关于非阻塞模式下的Socket的connect函数行为的解释(我们用到的Socket模式是流套接字)。
原来connect也是一被调用就直接返回个值为-36的错误码,然后再去进行三次握手,建立TCP连接,虽然有可能一被调用就直接建立好了连接而返回成功码0,但这个概率很小。按照我们惯常的思维,认为connect返回成功则连接建立(这是缺省模式——阻塞模式下的方法)。于是我们的异常处理机制立即启动,将该在后台建立连接的Socket关闭了。这样导致我们的连接一直建立不起来。
因此,在非阻塞模式下对Socket的操作应慎重,因为它的行为很像一个多线程的东东,不好控制。后来我们的方案是舍弃IO模式的修改,因为这样可能引入的缺陷是未可知的。不过,做为一个解决方案,我们可以用select对该Socket进行IO操作,给一个等待时间,一旦该时间超时,连接还没建立,再关闭之。当然,在对一个Socket进行其他的,比如recv/read操作的时候,执行一下select是必要的,不论其模式是阻塞还是非阻塞,这样可以防止很多错误。