`
licjava
  • 浏览: 14280 次
  • 性别: Icon_minigender_1
  • 来自: 深圳
社区版块
存档分类
最新评论

关于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仍是最优解。

 


我在写 PHPRPC 客户端时,就是用这种方法来跟服务器通讯的,实践证明是很有效的。

1 为什么网络流不建议用字节读取行 line = bufferreader.readLine()
2 起初我也为如何判断读取完成而恼火,读取文件流可以用(line = br.readLine()) != null(按字节读取用-1判断),但是在网络流里面这个怎么也读不对,后来别人告诉我在服务器发送完信息后用socket.shutdownOutput(),之后!= null可以判断了


你用它读网络流它仍然是按照它的 Buffer 大小来读入字节数的,所以读多了就会有麻烦了。
< 你每次都读取<="size的数据 " 不要按行去读取,你可以定义一个缓冲区byte[size] 这12个字节就表示你要接收的数据大小.如果读满了这12个字节的数据那么就读完了. 建议你先固定读取12个字节(包头定义)>(不用mina的时候项目中就这么做。)

1 缓存中有多于一行(\r\n)的纪录,那么readLine()读取一行,buff里还剩下一些
2 缓存中有不到一行的记录,那么readLine()
  (1)是阻塞,直到缓存中出现\r\n为止 ?
  (2)现在缓存中有多少就认为是一行?

我觉得很可能是第2个情况,因为一个网络流很可能没有换行,那么不可能直到超时才继续执行。

情况一:你只是希望你文件所有的内容都传到服务器上而已,那么一行读取是否为实际真的一行就不重要了,因为最终拼成的文件是完整的就够了。

情况二:你的客户端基于服务器段传输信息格式,比如说第一行是命令,第二行是版本号,那么你需要明确知道读多少是一行,那可能buff就有你说的问题了,总之仅仅需要传输完整的文件,无所谓读多读少问题。
< 命令用4个字节 令牌用12个字节  发送长度用4个字节  比如 包头可以用固定字节  你的发送包数据格式和回复包数据格式 以上连接你可以定义出 注明该次任务情况等等   就是断开连接 第三 你可以进行多次的交互 这个步骤是不确定 要编码的编码等等 要分包的分包 这个和你具体业务有关  发送请求 第二次 服务端返回任务令牌  请求连接 第一 大概可以分为以下几个步骤 你可以靠令牌去实现这个.>

 

分享到:
评论

相关推荐

    c_socket编程入门

    传输层位于这个结构的最底层,当其上面的应用协议层和请求/响应层不能满足应用程序的特殊需要时,就需要使用这一层进行Socket套接字编程。 而在.Net中,System.Net.Sockets 命名空间为需要严密控制网络访问的...

    NettySocket同步数据获取实现

    NettySocket同步数据获取实现,并实现了心跳检测,客户端连接控制,客户端登陆等。 Demo代码

    C++开发基于TCPsocket实现的web服务器源码.zip

    基于TCP socket实现的支持报文解析并返回响应报文的Web服务器,可以响应多种文件需求并能够处理特定的错误情况 服务器实现及其功能: 1、读取配置文件,为服务器自身设置IP地址、端口号、阻塞模式、最大连接数目并...

    安卓java读取网页源码-Socket:使用Golang+uniapp基于websocket的通信软件

    安卓java读取网页源码 基于Socket的聊天程序设计与实现 摘要 本论文主要阐述了为什么使用Golang与uni-app及redis数据库。以及如何使用他们来作为Socket通信服务。 随着21世纪的信息化的快速发展与迭代。 Golang作为...

    Python Socket编程入门教程

    例如当你在浏览器地址栏中输入 www.jb51.net 时,你会打开一个套接字,然后连接到 www.jb51.net 并读取响应的页面然后然后显示出来。而其他一些聊天客户端如 gtalk 和 skype 也是类似。任何网络通讯都是通过 Socket ...

    KMS+管理系统+最终结果

     6、socket编程集成信息系统实现网络通信; 成果: 1、信息系统运行情况; 2、设计简单的通信协议,检查运行情况  3、网络通信C/S系统:请求、响应密钥并保存;  4、信息系统读取密钥实现加解密(加密算法自选)...

    httpserver:学习socket网络编程,学习C++类的封装

    学习socket网络编程,学习C++类的封装 参考我总结的网络编程实践 试图解决其中提到的一些问题。...处理socket fd引用次数问题(完成) 解析HTTP协议的时候使用缓存 解决一些语法层面的问题(完成) 增加

    Android移动开发-使用多线程进行网络聊天室通信的实现

    程序Demo是实现一个简单的C/S聊天室的应用,每个客户端该包含两条线程:一条负责生成主界面,响应用户动作,并将用户输入的数据写入Socket对应的输出流中;另一条负责读取Socket对应的输入流中的数据(从服务器发送...

    MFC网络编程之自制浏览器

     CAsyncSocket类在较低层次上封装了Windows Socket API,并且通过内建一个(隐藏的)窗口,实现了适合Windows应用的异步机制(Windows Socket API默认情况下工作在阻塞模式,不方便直接在消息驱动的Windows程序上使用)...

    vc实例精通源码,windows基本控件的使用Demo

    示例描述:本章介绍在应用程序中使用Windows基本设备的方法和技巧。 01_MouseSample 处理鼠标消息。 02_KeyTest 处理键盘消息。 03_MouseMoving 利用客户区鼠标消息拖动无边框窗体。 04_NCMsg 利用非...

    MiniExercise.rar

    此项目为课堂练习项目,供参考使用。 手写服务器httpserver 1. 获取请求协议 (1)创建ServerSocket (2)建立连接获取Socket (3)通过输入流获取请求协议 (注意:GET与POST不一致的地方) 2. 返回响应协议 (1)...

    基础深化和提高-网络编程

    Java网络编程是指使用Java编程语言进行网络通信和相关操作的技术。通过Java的网络编程能力,开发人员可以创建客户端-服务器应用程序、实现数据传输、远程调用等功能。 Java的网络编程通常涉及以下几个方面: ...

    【最新版】wechat_devtools_1.02.2004020.dmg【亲测可用】最好的微信开发者工具

    F 修复 使用 cli 打开 project.config.json 中 projectname 为中文的项目时会一直卡在初始化应用通信能力的问题 反馈详情 F 修复 ts 项目编译前命令无限执行的问题 反馈详情 F 修复 PC 端模拟器的 touchend 事件回...

    Java在线聊天系统.rar

    一、搭建服务器端 a)、创建ServerSocket对象绑定监听端口。...d)、关闭响应资源这个项目非常适合学完Java基础来练手,该项目就是对Socket网络编程、IO流、线程及线程池等知识进行一些实战综合运用。

    Quectel BC95中文AT指令集 NB-IoT

    +NSONMI 指示 Socket 消息到达(只响应) B350+ AT+NPING 测试 IP 网络连接到远程主机 B350+ AT+NBAND 设置频段 B600+ AT+NLOGLEVEL 设置日志级别 B600+ AT+NCONFIG 配置模块的功能 B650+ AT+NATSPEED 配置 UART 端口...

    flex3的cookbook书籍完整版dpf(包含目录)

    在Flash中使用ContainerMovieClip创建Flex容器 21.3节.导入FlashCS3的组件 21.4节.认识Cairngorm小型结构 21.5节.创建Cairngorm视图、事件和模型 21.6节.创建Cairngorm命令和事务代理类 21.7节.创建...

    实验报告模版_实验2.doc

    计算机网络实验报告 一、 实验目的 ... 二、 实验内容 ... 使用标准的浏览器,如IE、Chrome或者Safari,输入服务... 本实验可以在前一个Socket编程实验的基础上继续,也可以使用第三方封装好的TCP类进行网络数据的收发

    JAVA上百实例源码以及开源项目

     Java非对称加密源程序代码实例,本例中使用RSA加密技术,定义加密算法可用 DES,DESede,Blowfish等。  设定字符串为“张三,你好,我是李四”  产生张三的密钥对(keyPairZhang)  张三生成公钥(publicKeyZhang...

    基于vue+node+socket+vant+mysql实现的在线客服系统.zip

    前后端分离,浏览器指纹作为访客唯一id,内置chatGPT智能回复,采用RSA加解密数据,防sql注入,xss,可发送图片表情、查询历史消息、留言、踢人等,更多功能等待后续更新。 简单快速部署,基本… MySQL 是一款广受...

Global site tag (gtag.js) - Google Analytics