最近做了一个小型的通讯项目,有一点体会,在这里拿来和大家分享一下:
一:关于Socket的长连接
这个项目中,客户提出了“一次连接,10次交互”的需求,就是说创建一个Socket后,在客户端与服务端完成10次交互前(客户端请求,服务端响应算一次交互),不会被关掉。起初按照这种思路来做Socket的长连接,发现在使用阻塞IO的情况下,如果,在一次交互后不关闭Socket,那么下次客户端虽然可以正常发送请求,但是怎么也读不出服务端的响应信息,因为服务端的输入流被阻塞在上次读取后。如果,每次交互后都关掉Socket,就不符合客户的要求了。于是查资料,说是用异步输入输出流java.nio,于是将其引入项目中,结果发现,异步IO虽然为多个Socket提供了不同的通道,但是对一个Socket而言,依然存在上述问题。于是和客户沟通,客户问一技术牛人,结果得到“Socket长连接指的是服务端将消息往客户端推, 就是在一次连接下,客户端向服务端发多条消息, 服务端一次响应完毕,其间,客户端如果在一定的时间内没有消息发往服务端,服务端会主动断开连接”。
二:关于Socket使用中读取响应消息的方法
使用Socket进行通信会涉及到读取服务端的响应消息。读取的方法可分为2类三种。
类1:一次性全部读取。
代码:
方法一:public String getResultStr(Socket sourceSocket)
{
String resultStr = null;
InputStream in;
try {
in = sourceSocket.getInputStream();
int readIndex = 5 * 1024 * 1024;
BufferedReader bufferedReader = new BufferedReader(
new InputStreamReader(in), readIndex);
char[] charArray = new char[readIndex];
int read_rst = bufferedReader.read(charArray);
resultStr = new String(charArray, 0, read_rst);
bufferedReader.close();
} catch (IOException e) {
e.printStackTrace();
}
return resultStr;
}
类2:非一次性读取
方法二:一行行读
public String getResultStr(Socket sourceSocket)
{
String resultStr = null;
InputStream in;
try {
in = sourceSocket.getInputStream();
BufferedReader bufferedReader = new BufferedReader(
new InputStreamReader(in));
StringBuffer responseBuffer = new StringBuffer();
String line = bufferedReader.readLine();
while (null != line)
{
responseBuffer.append(line);
line = bufferedReader.readLine();
}
bufferedReader.close();
resultStr = responseBuffer.toString();
} catch (IOException e) {
e.printStackTrace();
}
return resultStr;
}
方法三:一字节一字节读
public String getResultStr(Socket sourceSocket)
{
String resultStr = null;
InputStream in = null;
try {
in = sourceSocket.getInputStream();
BufferedReader bufferedReader = new BufferedReader(
new InputStreamReader(in));
int read_rst = bufferedReader.read();
StringBuffer readBuffer = new StringBuffer();
while (-1 != read_rst)
{
char singleChar = (char) read_rst;
readBuffer.append(singleChar);
}
bufferedReader.close();
resultStr = readBuffer.toString();
} catch (IOException e) {
e.printStackTrace();
}
return resultStr;
}
其中方法一的优点是读取速度快,且不用被超时所扰。缺陷是,只能读取一定量的字节,虽然BufferedReader的构造方法提供了设置缓冲区大小的功能,但是不管设多大,都只能读取一定量的字节,据项目中的情况来看,是65536个。如果响应消息有几MB的话,这种方法是肯定不行的。但是如果读取的消息很小,在65536个字节以内,则可以使用。
方法二的优点是便于做读取后的算法操作,速度嘛也挺快。缺陷是不能精确读取。因为readLine的方法读不出’\n’,’\r\n’,所以读出来的内容其长度与实际长度有出入。
方法三是最优解。(以上只是三种方法的原型,具体业务还要具体实现)
三:关于解决Socket读取响应消息超时的分析及解决方法:
分析
在使用Socket的过程中会遇到读取响应消息超时的问题,这是为什么呢?就我现在的理解,一句话:在服务端还没有关闭连接前,客户端读取响应消息就会一直等待,直到超时。
解决方法:
1.Socket提供的setSoTimeout(int timeout) 方法
在获得Socket的实例后,设置下超时时间,然后当read或是readLine完最后一个字节或是字符串后,会抛一个InterruptedIOException,在catch里做你想做的事情,或break,或关掉连接。
2.如果服务端也是你设计的话(就是响应消息也是你拼接的),请看。
可以在服务端里拼接响应消息的方法里为响应消息加上一个‘\r\n‘,注意一定要加在消息末尾。然后用“二:关于Socket使用中读取响应消息的方法”里第三种方法来读取响应消息,注意,通信消息头中肯定会有“Content-Length“一项,先取出其值(Content-Length表示消息主体的字节长度),接着找出主体消息的起始位置(主体消息中的最前方一定要是个固定的内容),开始计算响应消息的实际字节长度,最后将取出的Content-Length的值与实际计算出的长度进行比较,如果相等就break掉,这样,就不会读到会引起超时消息末尾。
其方法1的优点时易于实现,缺陷是不安定因素太大。setSoTimeout里总要设个值,设多少呢?假设在网络正常情况下读一个1MB的响应消息需要1s,那么如果网络阻塞呢?如果你设一个很大的值,就会影响使用。
方法2的优点是不受网络因素的影响。缺陷是,如果服务端的中文字符编码与流中的中文字符编码不一致,会导致乱码,进而会影响计算的准确度。一旦计算的不准,就会超时。
不过,方法2仍是最优解。
以上就是自己对这个项目的一点体会,欢迎大家指正。
分享到:
相关推荐
内容包含Soket通讯测试客户端以及服务端的软件,以及Codesys工程项目的示例程序。 主要用设备用于相机以及上位机的Socket通讯
一个简单的SOCKET客户端与服务器通讯的程序
SuperSocket Socket C# 通讯详细介绍,不错的 Socket,学习很有用处SuperSocket Socket 技能
MFC socket通信,socket通讯 MFC socket通信,socket通讯 我是使用VS2012来做的,不知道其他的环境会不会有问题。 使用VS2012分别打开工程AppSocClient和AppSocServer, 分别build两个工程,启动AppSocServer工程...
Socket通信 网络通讯Socket通信 网络通讯Socket通信 网络通讯
C# Socket通讯/TCP通讯,完整代码demo
程序是把一个dll注入到远程进程,然后在该DLL中获取远程进程的相关信息,并通过socket通讯传输给服务器端
这个工具就是一个能在线模拟socket通讯工具,并且能检测通讯是否能正常响应和发送信息
自己刚刚写的一个C# TcpIP Socket 客服端和服务端通信的DEMO,原创,而且结构清晰,注释详细,明了,分享给想学习C#TcpIP Socket通讯的,本人主要做web的,头一次用这个花了不少时间,尤其服务端的实现,希望和我...
包含sockettool,FINS TCP案例,FINS UDP案例,SOCKET通讯案例等
【亲测实用】c# socket与基恩士plc通讯、和扫码枪通讯程序源码 文件类型:程序源代码 主要功能: 工业通讯,c# socket与基恩士plc通讯、和扫码枪通讯 适合人群:新手及有一定经验的开发人员
【程序老媛出品,必属精品...资源名:VB SOCKET一对多通讯 客户端和服务端程序源码 资源类型:程序源代码 源码说明: 基于VB编写的socket 一对多通信实例源码 包含客户端和服务端 适合人群:新手及有一定经验的开发人员
资源名字:基于java+mysql+socket的即时通讯软件设计与实现(源码+文档)_mysql_socket_即时通讯软件.zip 资源内容:项目全套源码+完整文档 源码说明: 全部项目源码都是经过测试校正后百分百成功运行。 适合场景:...
一手原创,内含程序注释、在项目上已经验证,通讯成功。 验证的硬件:1756-EN2T和1769-l30er 程序软件版本:RSlogix 20.01版本编写 AB PLC通过1756-en2t或者1769-l30er直接与PC或者其它直持socket的控制器实现数据...
bcb socket通讯实例
socket网络通讯原理ppt如何用socket实现局部通讯功能
EAST 装置中的LHCD 控制系统是一个基于多平台的分布式控制系统。由于控制系统中有多种应用需求, 因此 在系统中采用了QNX, Linux 和Windows 三种操作系统。文章主要介绍了在QNX, Linux,Windows 三种不同的操作系统平 ...
C# winform Socket 即时通讯,C# winform Socket 即时通讯
一个简单的socket通讯程序, 包括服务端和客户端程序。建立客户端和客户端c++空项目,分别添加socketClient.cpp和sockServer.cpp, 根据注释配置,编译生成后就可以执行。客户端程序在visual studio 2015和2013上编译...