您的位置:首页 > 编程语言

关于socket短链接和长链接在编程时要注意问题

2015-03-02 09:55 218 查看
     在JAVA系统开发中,经常会遇到和周边系统进行信息交互,目前在系统间进行信息交互时,一般采用的技术实现分为基于http形式的交互和基于socket的交互,http本质也是基于socket通讯,只是对于客户端和服务端来说,屏蔽了很多socket通讯中的复杂度,如长短链接、报文流格式等,因此在系统间的交互中,如果有可能,一般采用基于http的通讯交互方式,如webservice,restful等,但是不幸的是,有很多传统系统还都只能直接采用socket进行通讯,这时,对于开发人员来说,特别是客户端开发人员来说,就要注意在进行socket编程时的一些问题,尤其是要注意服务端是长链接还是短链接,以下是针对几种短长链接组合的说明:

  1、客户端是短链接,服务端是短链接:这种模式是最简单的情况,双方在发送完毕报文后,就要关闭写通道,通知报文已经结束,因此对报文流没有格式上的要求,双方只要通过判断流是否可读(判断读的值是否为-1)就可以正确获取完整的socket报文,因此在双方短链接通讯时,可以通过报文的起始和结束符来获取完整报文,也可以通过判断流关闭方式来获取完整报文。

  2、客户端是短链接,服务端是长链接:这种模式必须通过报文的起始结束符来获取完整的报文,由于服务端是长链接,是不会主动关闭读写通道的,如果客户端还是采用通道关闭方式判断报文完整性,那么就会导致等待超时,现象上就类似没有收到报文(异常为read timeount)

  3、客户端是长链接,服务端是短链接:这种模式必须通过报文的起始结束符来获取完整的报文,情况同(二),否则服务端就会超时异常。

  4、客户端是长链接,服务端是长链接:这种模式必须通过报文的起始结束符来获取完整的报文,否则客户端和服务端都会超时异常。

       通过上面几个组合说明,因为socket是以流方式传输数据的,对于socket流的截取需要由应用程序来完成,要么双方都是短链接,通过关闭写通道提示对方流已经结束,要么根据报文的起始结束符来通知对方流已经结束,所以在进行socket通讯中,需要搞清楚报文起始结束符以及长短链接方式,才能正确发送和接收相关报文,目前JAVA主流的netty和mina框架都提供了报文截取的对象,可以很方便的实现完整报文的截取,如果没有框架支持,自己实现就要非常小心,另外要注意在客户端进行长链接通讯时,往往采用的是异步通讯,请求和响应是异步的,所以必须注意请求和响应报文之间必须建立起关联,比如在报文中增加一个消息关联号。

        以下是一个案例,由于客户端把服务端当成短链接来处理,导致对于特定长度的报文就会出现超时:

           socket = new Socket(host, port);

            socket.setSoTimeout(15000);

            socket.setTcpNoDelay(true);

            socket.setReceiveBufferSize(2000);

            logger.info("{} 开始发送报文", reqSerialNo);

            // 发送

            out = socket.getOutputStream();

            out.write(bytes);

            out.flush();

            logger.info("{} 发送完毕,开始接收", reqSerialNo);

            // 接收

            in = socket.getInputStream();

            swapStream = new ByteArrayOutputStream();

            byte[] buffer = new byte[50]; //buff用于存放循环读取的临时数据

            int count;

            //以下为问题代码

            while ((count = in.read(buffer, 0, 50)) != -1)
{//判断对方写通道是否关闭,

                swapStream.write(buffer, 0, count);

                if (count < 50)                                                
 //循环判断对方写缓存是否满50个字节

                    break;

            }
     以上代码有两个问题,
     第一个问题:就是通过对方是否关闭写通道,来判断是否报文完整

     第二个问题:判断对方在缓存中写的数据是否满50个字节,来判断报文循环读是否结束

     由于服务端是长链接,不会关闭通道,因此对于长度为50倍数的报文,都会发生读超时的情况,而且一般测试很难发现。

   

    因此对于socket编程来说,一定要正确处理报文的完整性,这是socket正确编程的第一步!
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: