在Java当中,所有对外设的操作都通过IO流来实现,不管是从磁盘中读取或写入文件,或者是从网络环境中接收或发送数据。IO流的基类有两个InputSstream和OutputStream,它们实现IO最基本的、无数据缓冲的、按节节流进行读写的操作功能。但是在实际的处理当中,为了数据读写的方便或提高读写的效率,往往会用到它们的子类,比如带缓冲区的类BufferedInputStream、BufferedOutputStream,DataInputStream、DataOutputStream等等。
现在,我要来模拟一个常见的网络模型:客户端/服务器模式,来了解网络IO流的具体操作。首先我定义数据包的格式分别为消息头和消息体,其中消息头由三部分组成:消息包的总长度、命令字、序列号,各为一个整形,消息体为一个Byte数组,由若干字节组成,长度由消息包的总长度减去12个消息头的长度得来,消息体当中有一部分是消息内容,这个具体的组成不再详述,消息包的定义不是我们关注的重点,我们着重来看一下数据发送、接收的实现及效率如何。
首先来写一个服务端的程序来接收数据,写一个客户端程序来发送数据,总共发送1万条数据进行测试,服务器端代码如下:
importjava.io.IOException;
importjava.net.ServerSocket;
importjava.net.Socket;

importcom.gftech.cmpp.bean.CmppBody;
importcom.gftech.cmpp.bean.CmppDeliver;
importcom.gftech.cmpp.bean.CmppHead;
importcom.gftech.cmpp.bean.CmppPack;
importcom.gftech.cmpp.bean.ICmppCmdID;
importcom.gftech.smp.SmpDeliverPack;


/***//**
*测试读取速度:使用Buffer和不使用Buffer的情况
*
*@authorsinboy
*@since2007.3.30
*
*/

publicclassServerDemo...{


publicstaticvoidmain(String[]args)...{
intlistenPort=2000;

try...{
Socketclient=null;
ServerSocketss=newServerSocket(listenPort);
System.out.println("侦听"+listenPort+"端口,等待客户端的连接...");

while(true)...{
client=ss.accept();
System.out.println("接收到通信平台或客服系统的连接"+client.toString());

read(client);
}

}catch(IOExceptione)...{
e.printStackTrace();
}
}


publicstaticvoidread(Socketsock)...{
if(sock!=null)

try...{

while(true)...{
CmppPackcp=CmppCommu.receive(sock);

if(cp!=null)...{
CmppHeadhead=cp.getHead();
CmppBodybody=cp.getBody();

if(head!=null)...{

switch(head.getCmdID())...{
caseICmppCmdID.CMPP_DELIVER:
CmppDelivercd=newCmppDeliver(body.getBody());

if(cd!=null)...{
SmpDeliverPackpack=newSmpDeliverPack(cd);
Stringcontent="cmppdeliver:"+pack.getSrcAddr()+""+pack.getDestAddr()+""+pack.getContent()+""
+pack.getLinkID();
System.out.println(content);

}
}
}
}
}

}catch(IOExceptione)...{
e.printStackTrace();
}
}

}


publicvoidsend(byte[]b)throwsIOException...{
if(sock==null)
thrownewIOException();

if(b!=null)...{

try...{
BufferedOutputStreamos=newBufferedOutputStream(sock.getOutputStream());

if(b!=null)...{
os.write(b);
os.flush();
}

}catch(IOExceptione)...{
throwe;
}
}
}
客户端代码如下:

publicclassClientDemo...{


publicstaticvoidmain(String[]args)...{

try...{
Socketclient=newSocket("192.168.10.8",2000);
write(client);

}catch(UnknownHostExceptione)...{
e.printStackTrace();

}catch(IOExceptione)...{
e.printStackTrace();
}

}


publicstaticvoidwrite(Socketclient)...{

try...{
ArrayList<CmppPack>cpList=newArrayList<CmppPack>();

for(inti=0;i<10000;i++)...{
SmpDeliverPackpack=newSmpDeliverPack("13612345678","01234",""+(i+1));
CmppDelivercd=pack.toCmppDeliver();

if(cd!=null)...{
CmppPackcp=newCmppPack(newCmppHead(12+cd.getBody().length,ICmppCmdID.CMPP_DELIVER,100),cd);
cpList.add(cp);
}
}


for(inti=0;i<cpList.size();i++)...{
CmppCommu.send(client,cpList.get(i));
System.out.println(i);
}
Thread.sleep(10000);

}catch(IOExceptione)...{
e.printStackTrace();
}

catch(InterruptedExceptione)...{

}
}
}
用到的发送和接入方法如下:

publicclassCmppCommu...{


publicstaticvoidsend(Socketsock,CmppPackpack)throwsIOException...{

if(sock!=null&&pack!=null)...{

try...{
byte[]b=pack.getBytes();
BufferedOutputStreamos=newBufferedOutputStream(sock.getOutputStream());

if(b!=null)...{
os.write(b);
os.flush();
}

}catch(IOExceptione)...{
throwe;
}
}

}

publicstaticCmppPackreceive(Socketsock)throwsIOException...{
finalintMAX_LEN=10000;
CmppPackpack=null;

if(sock==null)
thrownewIOException();

try...{
BufferedInputStreambis=newBufferedInputStream(sock.getInputStream());
DataInputStreamin=newDataInputStream(bis);

intlen=in.readInt();//读取消息头

if(len>=12&&len<MAX_LEN)...{
intcmd=in.readInt();
intseq=in.readInt();

intbodyLen=len-12;
byte[]msg=newbyte[bodyLen];
in.read(msg);//读取消息体

CmppHeadhead=newCmppHead(len,cmd,seq);
CmppBodybody=newCmppBody(msg);
pack=newCmppPack(head,body);
}

}catch(SocketTimeoutExceptione)...{
//logger.warn("timeout");

}catch(IOExceptione)...{
throwe;
}

returnpack;
}
}
使用Eclipse TPTP对程序的执行进行监控,结果如下:
<shapetype id="_x0000_t75" stroked="f" filled="f" path="m@4@5l@4@11@9@11@9@5xe" o:preferrelative="t" o:spt="75" coordsize="21600,21600"><a href="http://p.blog.csdn.net/images/p_blog_csdn_net/sinboy/293422/o_1.JPG"><img alt="" src="http://p.blog.csdn.net/images/p_blog_csdn_net/sinboy/293422/o_1.JPG"></a></shapetype>
<shapetype stroked="f" filled="f" path="m@4@5l@4@11@9@11@9@5xe" o:preferrelative="t" o:spt="75" coordsize="21600,21600"><span style="FONT-SIZE: 10.5pt; FONT-FAMILY: 宋体; mso-ascii-font-family: 'Times New Roman'; mso-hansi-font-family: 'Times New Roman'; mso-bidi-font-family: 'Times New Roman'; mso-ansi-language: EN-US; mso-fareast-language: ZH-CN; mso-bidi-language: AR-SA; mso-bidi-font-size: 12.0pt; mso-font-kerning: 1.0pt">如上图所示,服务器端程序在接收数据时总共花了</span><span lang="EN-US" style="FONT-SIZE: 10.5pt; FONT-FAMILY: 'Times New Roman'; mso-ansi-language: EN-US; mso-fareast-language: ZH-CN; mso-bidi-language: AR-SA; mso-fareast-font-family: 宋体; mso-bidi-font-size: 12.0pt; mso-font-kerning: 1.0pt">21</span><span style="FONT-SIZE: 10.5pt; FONT-FAMILY: 宋体; mso-ascii-font-family: 'Times New Roman'; mso-hansi-font-family: 'Times New Roman'; mso-bidi-font-family: 'Times New Roman'; mso-ansi-language: EN-US; mso-fareast-language: ZH-CN; mso-bidi-language: AR-SA; mso-bidi-font-size: 12.0pt; mso-font-kerning: 1.0pt">秒多。因为从理论上讲把输入流用</span><span lang="EN-US" style="FONT-SIZE: 10.5pt; FONT-FAMILY: 'Times New Roman'; mso-ansi-language: EN-US; mso-fareast-language: ZH-CN; mso-bidi-language: AR-SA; mso-fareast-font-family: 宋体; mso-bidi-font-size: 12.0pt; mso-font-kerning: 1.0pt">Buffer</span><span style="FONT-SIZE: 10.5pt; FONT-FAMILY: 宋体; mso-ascii-font-family: 'Times New Roman'; mso-hansi-font-family: 'Times New Roman'; mso-bidi-font-family: 'Times New Roman'; mso-ansi-language: EN-US; mso-fareast-language: ZH-CN; mso-bidi-language: AR-SA; mso-bidi-font-size: 12.0pt; mso-font-kerning: 1.0pt">包装一下接收的速度会更快一些,下面我们对它进行验证,把接收程序略做改动,增加一句</span><span lang="EN-US" style="FONT-SIZE: 10.5pt; FONT-FAMILY: 'Times New Roman'; mso-ansi-language: EN-US; mso-fareast-language: ZH-CN; mso-bidi-language: AR-SA; mso-fareast-font-family: 宋体; mso-bidi-font-size: 12.0pt; mso-font-kerning: 1.0pt">Buffer</span><span style="FONT-SIZE: 10.5pt; FONT-FAMILY: 宋体; mso-ascii-font-family: 'Times New Roman'; mso-hansi-font-family: 'Times New Roman'; mso-bidi-font-family: 'Times New Roman'; mso-ansi-language: EN-US; mso-fareast-language: ZH-CN; mso-bidi-language: AR-SA; mso-bidi-font-size: 12.0pt; mso-font-kerning: 1.0pt">包装:</span></shapetype>
BufferedInputStreambis=newBufferedInputStream(sock.getInputStream());
DataInputStreamin=newDataInputStream(bis);
再次运行,发现一个很奇怪的问题,接收时有数据丢失的情况,正常情况下应该是从1到10000:
cmppdeliver:1361234567801234116240905710000010001
cmppdeliver:1361234567801234216241005710000010001
cmppdeliver:136123456780123426116241005710000010001
cmppdeliver:136123456780123426216241005710000010001
cmppdeliver:136123456780123426316241005710000010001
cmppdeliver:136123456780123426416241005710000010001
......
为何用Buffer进行包装之后会有数据丢失而没有包装时接收正常呢?我们仔细研究一下接收的源代码发现,在每次对数据进行接收时,都会在一个Socket上重新建一个输入流,因为BufferedInputStream在创建时会自动建立一个缓冲区用于整块数据的读取,系统默认为8192,也就是说当你读第一个包的时候,系统本身其实已经读取的8192个字节的数据,而你的包大小可能是只有100个字节,在你循环过来再次读第二个数据包时,等于又重新创建了一个输入流,把前面那个丢掉了,而它原先已经预先读取的数据也随之丢失。而不用Buffer包装的输入流因为每次都是从实际的IO中读取数据所以不存在数据丢失的情况。
明白了这一点,那我们可以把创建输入流放到每次读取的循环之外,修改读取方法如下:

publicstaticCmppPackreceive(DataInputStreamin)throwsIOException...{
finalintMAX_LEN=10000;
CmppPackpack=null;
if(in==null)
thrownewIOException();

try...{
intlen=in.readInt();//读取消息头

if(len>=12&&len<MAX_LEN)...{
intcmd=in.readInt();
intseq=in.readInt();

intbodyLen=len-12;
byte[]msg=newbyte[bodyLen];
in.read(msg);//读取消息体

CmppHeadhead=newCmppHead(len,cmd,seq);
CmppBodybody=newCmppBody(msg);
pack=newCmppPack(head,body);
}

}catch(SocketTimeoutExceptione)...{
//logger.warn("timeout");

}catch(IOExceptione)...{
throwe;
}

returnpack;
}
服务器端的代码也作相应调整,把创建输入流的过程放在循环之外,保证每次读取数据包都是使用同一个输入流:
BufferedInputStreambis=newBufferedInputStream(sock.getInputStream());
DataInputStreamin=newDataInputStream(bis);

while(true)...{
CmppPackcp=CmppCommu.receive(in);
...
再次进行测试,结果如下:

从上图可以看出来,效率提高了很多,这里提高的原因有两点:一个使用了Buffer进行输入流的包装,二是每次读取数据包时创建新的输入流的过程放到了循环之外,减少的资源的开销。但纯粹的使用Buffer进行包装,效果究竟能提高多少呢?我们再次使用非Buffer的读取方式,但把创建输入流的过程放在循环之外,接收方法不变,服务端代码如下:
DataInputStreamin=newDataInputStream(sock.getInputStream());

while(true)...{
CmppPackcp=CmppCommu.receive(in);
...

从上图可以看出,非Buffer包装的输入流,时间增加了约3秒钟,效率下降了50%左右。
再发客户端的程序做一个改进,把创建输出流这一步也提到循环之外:
BufferedOutputStreamout=newBufferedOutputStream(client.getOutputStream());

for(inti=0;i<cpList.size();i++)...{
CmppCommu.send(out,cpList.get(i));
System.out.println(i);
}
提高虽然不明显,但也有提高,结果如下:

从上述的测试过程中可以明白两点:
1、使用Buffer进行输入输出流的包装可以减少程序对IO的实际操作次数,提高效率
2、尽量把不变的东西提到循环之外,象创建输入流这一步,极大地影响了程序的执行效率
分享到:
相关推荐
在Java编程语言中,输入输出流(IO流)是处理数据传输的核心机制,无论是读取文件、接收网络数据还是在程序之间传递信息,都离不开IO流。本篇将深入探讨IO流的操作,包括其概念、分类、使用方法以及在实际开发中的...
以上就是Android中使用TCP Socket客户端进行数据收发的基本流程。在实际项目中,你可能需要根据业务需求对代码进行优化,比如添加超时设置、数据编码解码等。同时,为了提高应用的健壮性,还要考虑网络状态变化、...
IO,即Input(输入)和Output(输出),在Java中表现为数据流的形式,用于读取或写入各种数据源,如文件、网络连接等。Java的IO流体系结构复杂而强大,包括字节流和字符流两大类,以及许多子类,如缓冲流、转换流等...
使用场景及目标:适用于开发中有需要处理数据存储、网络数据收发等问题的人群,在项目实战中解决文件读写和数据交互问题。 其他补充说明:该教程不仅包含了理论概念,还辅之大量示例帮助理解和掌握知识点,并提供了...
其中,RocketIO技术是Xilinx公司的高端FPGA产品中集成了高速串行收发器技术,通过先进的信号处理和优化技术,实现了高速、高效的数据传输。RocketIO技术可以支持多种高速串行标准,如PCI Express、RapidIO、ATA等,...
在IT行业中,串口通信和网络数据传输是两个至关重要的技术领域,特别是在设备间的数据交互和控制系统设计上。本文将详细探讨如何使用C#进行串口数据接收,并通过网络发送这些数据,以此实现如展厅入口控制媒体播放的...
在IT行业中,Node.js是一个基于Chrome V8引擎的JavaScript运行环境,它允许开发者使用JavaScript进行服务器端编程。Socket.IO是一个实时应用框架,它为实时、双向通信提供了强大的工具,特别适用于构建实时交互的Web...
这些资源可能涵盖了Aurora的协议规范、配置指南、硬件接口定义以及如何在实际设计中使用Aurora进行数据传输的实例。通过深入学习和理解这些材料,工程师能够更好地掌握如何在Xilinx GTX RocketIO上实现Aurora协议,...
在C#编程环境中,开发一个文件收发客户端是一项常见的任务,尤其在网络通信领域。这个项目主要涉及了C#中的网络编程、文件操作以及用户界面设计等核心知识点。下面将详细阐述这些关键点。 1. **网络编程基础**: ...
在“数据流图Net-mai笔记”中,我们很可能是探讨如何使用数据流图来分析和设计网络邮件系统。在这个场景下,我们可以深入理解数据流图的基本元素、作用以及在C语言编程环境下的应用。 1. 数据流图基本元素: - **...
Java数据输入输出流是Java IO库中的重要组成部分,主要用于处理不同数据类型的输入和输出操作,尤其是在文件和网络通信中。本文将深入探讨DataInputStream和DataOutputStream这两个类以及它们所关联的DataInput和...
7. 网络流:在进行网络通信时,`Socket` 和 `ServerSocket` 提供了基于TCP的字节流,`DatagramSocket` 和 `DatagramPacket` 提供了基于UDP的字节流。这些流类使得Java程序能够收发网络数据。 8. 多路复用流:`...
本示例关注的是如何利用Netty实现一个基于UDP(User Datagram Protocol)的数据接收服务,这在需要进行快速、无连接的数据传输场景中非常常见。以下是对这个主题的详细讲解: 首先,我们需要理解UDP的基础知识。UDP...
在IT行业中,网络编程是不可或缺的一部分,特别是在分布式系统和实时通信的应用中。C#作为.NET框架的主要编程语言,提供了强大的网络编程支持。本教程将详细讲解如何使用C#的Socket库来实现一个简单的图片收发功能,...
在聊天室中,IO流用于在网络连接中传输数据。Java的IO流分为字节流和字符流两大类,且有输入流和输出流之分。例如,`java.io.InputStream`和`java.io.OutputStream`用于处理字节流,`java.io.Reader`和`java.io....
2. **数据收发原理**:在TCP/IP协议栈中,数据被分割成数据包(或称报文段),通过网络层传输,然后在接收端重新组装。数据的可靠性由协议本身处理,如TCP确保数据的顺序和无丢失传输,而UDP则不提供这些保证。 3. ...
在进行实际的LIN诊断时,LindiagnosisTool这样的软件可以提供便利。它可以用来发送LIN命令,读取从节点的响应,检查通信的正确性,以及进行故障注入以测试系统的容错能力。 总结来说,使用电脑UART模拟LIN总线是一...
在高帧率多通道数字图像传输和远程高速反馈控制的应用中,需要实时地采集大量数据并进行处理,FPGA结合RocketIO技术为这类系统提供了可能。 3. **高性能计算**: 在高性能计算领域,数据传输速度是影响整个系统...
本篇文章将深入探讨C#中的`TcpListener`类以及如何结合序列化进行数据的收发。 首先,让我们了解TCP(传输控制协议)的基础知识。TCP是一种面向连接的、可靠的、基于字节流的传输层通信协议,它确保了数据的正确性...
本篇将详细探讨"JAVA程序与PLC通信——学习使用"这一主题,包括如何使用Java实现与西门子PLC的串口通信,以及如何收发数据。 首先,我们要理解Java语言的优势。Java作为一种跨平台的编程语言,其强大的网络支持和...