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

本文探讨了Java系统开发中系统间信息交互的主要技术实现方式,重点介绍了基于HTTP与Socket的交互区别,并详细阐述了不同链接组合下Socket编程的注意事项。通过实例分析了错误代码,并指出了其可能导致的问题。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

     在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正确编程的第一步!


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值