关于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框架都提供了报文截取的对象,可以很方便的实现完整报文的截取,如果没有框架支持,自己实现就要非常小心,另外要注意在客户端进行长链接通讯时,往往采用的是异步通讯,请求和响应是异步的,所以必须注意请求和响应报文之间必须建立起关联,比如在报文中增加一个消息关联号。
以下是一个案例,由于客户端把服务端当成短链接来处理,导致对于特定长度的报文就会出现超时:
以上代码有两个问题,
第一个问题:就是通过对方是否关闭写通道,来判断是否报文完整
第二个问题:判断对方在缓存中写的数据是否满50个字节,来判断报文循环读是否结束
由于服务端是长链接,不会关闭通道,因此对于长度为50倍数的报文,都会发生读超时的情况,而且一般测试很难发现。
因此对于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正确编程的第一步!
相关文章推荐
- 关于vs2008上的socket链接错误问题
- 关于vs2008上的socket链接错误问题(COM组件同理)
- Socket编程 关于缓冲区长度问题
- 关于socket编程的一些问题
- 关于vs2008上的socket链接错误问题
- 关于socket编程中的accept问题
- socket编程需要注意的问题
- Android中的socket编程-关于设置连接的ip问题
- Android Socket编程所注意的问题
- 【socket】关于socket链接错误问题
- 关于OPC自动化接口编程(OPCDAAuto.dll)几点注意问题
- 关于OPC自动化接口编程(OPCDAAuto.dll)几点注意问题
- Android4.0使用socket编程时要注意的问题
- 关于宽字符(_UNICODE||UNICODE)和windows套接(socket)字编程问题
- 关于socket编程的一个常坑问题,readLine()
- [原]关于socket编程中重用socket问题的备忘
- 关于vs2008上的socket链接错误问题
- 关于vs2008上的socket链接错误问题
- 问一个关于java Socket编程的问题。
- 关于php socket编程中遇到的一些问题