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

Java socket 通讯流的测试

    博客分类:
  • java
 
阅读更多

场景

客户端  服务端  建立连接

客户端发送数据给服务端处理

服务端从输入流取到数据,处理中.....

此时客户断开连接

服务端将处理后的数据发送给客户,预想的情况,连接已断开,输出流已经不存在,write的时候应该报错

package tcp;

import java.io.BufferedReader;
import java.io.DataOutputStream;
import java.io.InputStreamReader;
import java.io.OutputStream;
import java.net.Socket;

public class TcpClient {
	public static void main(String[] args) {
		try {
			Socket s = new Socket("127.0.0.1", 8080);
//			s.setTcpNoDelay(true);
			// InputStream is = s.getInputStream();
			OutputStream os = s.getOutputStream();
			DataOutputStream os_d = new DataOutputStream(os);
			for (;;) {// 保持长连接不断发送
				InputStreamReader input = new InputStreamReader(System.in);
				BufferedReader read = new BufferedReader(input);
				String content = read.readLine();
				if ("exit".equals(content)) {
					s.close();
					return;
				}
				System.out.println("开始发送报文," + content);
				os_d.writeBytes(content + System.getProperty("line.separator"));
			}

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

 

package tcp;

import java.io.BufferedReader;
import java.io.BufferedWriter;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.OutputStream;
import java.io.OutputStreamWriter;
import java.net.ServerSocket;
import java.net.Socket;

public class TcpServer {

	// 先启动服务器端程序
	public static void main(String[] args) throws IOException {
		ServerSocket serverSocket = new ServerSocket(8080);
		System.out.println("tcp 服务端开启....");
		while (1 == 1) {
			Socket socket = serverSocket.accept();// 阻塞等待消息
			socket.setOOBInline(false);
			System.out.println("已经获取连接" + socket);
			// socket.setSoTimeout(10*1000);//readLine这里等待10s,如果用户还没有输入就抛出异常java.net.SocketTimeoutException
//			socket
			InputStream inputStream = socket.getInputStream();
			OutputStream outputStream = socket.getOutputStream();
			BufferedWriter bufferedWriter = new BufferedWriter(new OutputStreamWriter(outputStream));
			BufferedReader bufferedReader = new BufferedReader(new InputStreamReader(inputStream));
			System.out.println("接收客户端信息...");
			while (true) {// 长连接不断处理
				System.out.println("等待用户输入");
				String readLine = bufferedReader.readLine();
				if (readLine == null) {
					return;
				}
				System.out.println("接收报文:" + readLine);
				try {
					System.out.println("后台处理中.....");
					Thread.sleep(10*1000);
				} catch (InterruptedException e) {
					e.printStackTrace();
				}
				StringBuffer sb=new StringBuffer();
//				for(int i=0;i<10000;i++)
//					sb.append("aaaaaaaaaaaaaa");
				bufferedWriter.write(readLine+","+sb.toString());
				bufferedWriter.flush();
				System.out.println("响应客户端OK");
				try {
					Thread.sleep(10*1000);
				} catch (InterruptedException e) {
					// TODO Auto-generated catch block
					e.printStackTrace();
				}
			}
		}
	}
}

 

客户端控制台

aaa

开始发送报文,aaa

exit

 

服务端控制台

tcp 服务端开启....

已经获取连接Socket[addr=/127.0.0.1,port=3643,localport=8080]

接收客户端信息...

等待用户输入

接收报文:aaa

后台处理中.....

响应客户端OK

等待用户输入

Exception in thread "main" java.net.SocketException: Software caused connection abort: recv failed

at java.net.SocketInputStream.socketRead0(Native Method)

at java.net.SocketInputStream.read(SocketInputStream.java:129)

at sun.nio.cs.StreamDecoder.readBytes(StreamDecoder.java:264)

at sun.nio.cs.StreamDecoder.implRead(StreamDecoder.java:306)

at sun.nio.cs.StreamDecoder.read(StreamDecoder.java:158)

at java.io.InputStreamReader.read(InputStreamReader.java:167)

at java.io.BufferedReader.fill(BufferedReader.java:136)

at java.io.BufferedReader.readLine(BufferedReader.java:299)

at java.io.BufferedReader.readLine(BufferedReader.java:362)

at tcp.TcpServer.main(TcpServer.java:32)

 

这里说明服务端在write的时候竟然没问题,在下次read的时候才报连接断开,无法读取类似的异常。。

 

为什么呢?

write那里了呢?我还特意bufferedWriter.flush();也都没问题。

 

如果响应的是大量数据呢?,模拟代码如下:

for(int i=0;i<10000;i++)

 sb.append("aaaaaaaaaaaaaa");

bufferedWriter.write(readLine+","+sb.toString());

 

bufferedWriter.flush();

这时候预想的情况来了。

tcp 服务端开启....

已经获取连接Socket[addr=/127.0.0.1,port=3706,localport=8080]

接收客户端信息...

等待用户输入

接收报文:aa

后台处理中.....

Exception in thread "main" java.net.SocketException: Software caused connection abort: socket write error

at java.net.SocketOutputStream.socketWrite0(Native Method)

at java.net.SocketOutputStream.socketWrite(SocketOutputStream.java:92)

at java.net.SocketOutputStream.write(SocketOutputStream.java:136)

at sun.nio.cs.StreamEncoder.writeBytes(StreamEncoder.java:202)

at sun.nio.cs.StreamEncoder.implWrite(StreamEncoder.java:263)

at sun.nio.cs.StreamEncoder.write(StreamEncoder.java:106)

at java.io.OutputStreamWriter.write(OutputStreamWriter.java:190)

at java.io.BufferedWriter.flushBuffer(BufferedWriter.java:111)

at java.io.BufferedWriter.write(BufferedWriter.java:212)

at java.io.Writer.write(Writer.java:140)

at tcp.TcpServer.main(TcpServer.java:46)

 

 

这是为什么呢?估计是缓存的问题,可能跟具体的socket通讯机制有关。

Socket setSoLinger 

Enable/disable SO_LINGER with the specified linger time in seconds. The maximum timeout value is platform specific. The setting only affects socket close.

默认情况下,close 连接,实际上系统还会逗留一端时间才会真正关闭,代码close,仅仅是假象。

具体逗留多久有系统平台决定。看来前面的write是真的OK。

 

修改代码,把服务端的处理时间延长。再试试。

System.out.println("后台处理中.....");

Thread.sleep(60*1000);

这里处理1分钟情况跟之前一样,我猜想2边的通讯方式如下:

服务端在出来完write的时候,通过三次握手,告诉对方有人已经请求我close了不要在给我发送数据了,

这次接收是为了保证数据的完整性,怕我关闭后,立刻有别的socket冒充我,导致把处理后的数据发送给“骗子”

知道对方出问题了(已经关闭了)等下次在read的时候直接抛异常出来。

这个只是猜想,还需要进一步验证。

 

 

再次测试

在客户端修改代码

Socket s = new Socket("127.0.0.1", 8080);

s.setSoLinger(true, 0);

close后,不做任何逗留,让系统直接关闭。

 

 

tcp 服务端开启....

已经获取连接Socket[addr=/127.0.0.1,port=3842,localport=8080]

接收客户端信息...

等待用户输入

接收报文:ff

后台处理中.....

Exception in thread "main" java.net.SocketException: Connection reset by peer: socket write error

at java.net.SocketOutputStream.socketWrite0(Native Method)

at java.net.SocketOutputStream.socketWrite(SocketOutputStream.java:92)

at java.net.SocketOutputStream.write(SocketOutputStream.java:136)

at sun.nio.cs.StreamEncoder.writeBytes(StreamEncoder.java:202)

at sun.nio.cs.StreamEncoder.implFlushBuffer(StreamEncoder.java:272)

at sun.nio.cs.StreamEncoder.implFlush(StreamEncoder.java:276)

at sun.nio.cs.StreamEncoder.flush(StreamEncoder.java:122)

at java.io.OutputStreamWriter.flush(OutputStreamWriter.java:212)

at java.io.BufferedWriter.flush(BufferedWriter.java:236)

at tcp.TcpServer.main(TcpServer.java:42)

 

此时就是预想的情况。

 

 

 

这里可能还有个问题,就是为什么在我发送大量的数据给客户端时也会报write的异常呢?

代码:

for(int i=0;i<10000;i++)

 sb.append("aaaaaaaaaaaaaa");

bufferedWriter.write(readLine+","+sb.toString());

 

bufferedWriter.flush();

原因应该是这样的。对于TCP底层来说,每次通讯是发送包的,如果包裹太大,就会打出多个小包

分批来发送,当第一次发送的时候已经发送成功了,但对方已经把自己已经close的状态发送给

服务端了,此时服务端再次发包过去直接失败。

TCP_NODELAY

SO_TIMEOUT

SO_LINGER

SO_RCVBUF

SO_SNDBUF

看来有时间需要把TCP的通讯机制好好系统的学习下了。

 

 

分享到:
评论

相关推荐

    java socket通讯例程 多线程读写 可以同时收发不同终端的消息

    在主线程中通过控制台读取键盘输入时,会产生阻塞。故另外开启一个线程,用于接受客户端的socket消息。服务器在收到一个socket连接之后,...测试可以在不同控制台运行server和client,服务器接收消息时,会显示消息来源

    基于java+mysql+socket的即时通讯软件设计与实现(源码+文档)_mysql_socket_即时通讯软件.zip

    资源名字:基于java+mysql+socket的即时通讯软件设计与实现(源码+文档)_mysql_socket_即时通讯软件.zip 资源内容:项目全套源码+完整文档 源码说明: 全部项目源码都是经过测试校正后百分百成功运行。 适合场景:...

    socket通讯 .net做为服务器端和java 做为客户端

    由于需求原因,socket通讯采用 ,net 作为服务器端不断监听java做为客户端发送来的信息。.net 服务器端采用线程方式接收多个客户端连接。已经测试通过。

    卫通星GPS定位器GT06协议socket通讯JAVA Spring Boot对接

    卫通星GPS定位器GT06协议socket通讯JAVA Spring Boot对接

    基于Java的即时通讯工具的设计与开发的毕业设计,使用Java SE和Java Socket API开发基本功能

    这篇毕设将介绍一个基于Java的简单即时通讯工具的设计和开发过程。 ## 设计 在设计阶段,我们将考虑实现以下功能: 1. 用户登录和注册 2. 好友列表和聊天窗口 3. 单聊和群聊功能 4. 消息发送和接收 5. 图片和文件...

    三个 java socket服务器客户端通信例子

    例子都可以跑通均已测试通过 com.socket 包中是一个简单的客户端发给服务器的例子 com.socket.complex 使用多线程来模拟通信 com.socket.block 根据客户端传递的参数来返回不同的信息

    socket心跳测试(java)

    java语言 建立网络通讯长连接示例(心跳测试)

    基于Java+SOCKET的即时通讯工具设计与实现(源码+文档).zip

    资源名字:基于Java+SOCKET的即时通讯工具设计与实现(源码+文档)_java_SOCKET_即时通讯工具.zip 资源内容:项目全套源码+完整文档 源码说明: 全部项目源码都是经过测试校正后百分百成功运行。 适合场景:相关项目...

    Java聊天室的设计与实现socket 设计软件源码+WORD毕业论文文档.zip

    Java聊天室的设计与实现socket 设计软件源码+WORD毕业论文文档 Java聊天室系统主要用于实现在线聊天,基本功能包括:服务端和客户端。本系统结构如下: (1)服务端: 1、能够开启和关闭服务器 2、等待着客户端从...

    Socket通讯系统(多线程Thread)

    这个是用Java+socket 编写的通讯系统,继承了Thread,重写run(),实现了多用户交流,以及server与client之间交互!代码已经测试过,完全没有问题,我是在netbeens实现的,将server和client 复制在路径下就可以!请...

    JAVA 网络编程服务器端例程

    JAVA 网络编程服务器端例程,一个测试socket通信的比较好的例程

    Android例子源码简单Socket通信例子带服务端

    服务端是用的一个无限循环来等待客户端请求和消息,本项目有java服务端,想要测试的朋友需要配置好两边的ip和端口。另外本站之前也发过几个关于Socket通讯的项目源码,可以搜一下“Socket”就可以找到,本项目默认...

    socket通讯

    1.服务端Java(MyServer)/客户端Android(SocketTest); 2.数据流DataInputStream、DataOutputStream; 3.注意测试时手机端和服务器端应处于同一网段。

    java源码包---java 源码 大量 实例

     Java数据压缩与传输实例,可以学习一下实例化套按字、得到文件输入流、压缩输入流、文件输出流、实例化缓冲区、写入数据到文件、关闭输入流、关闭套接字关闭输出流、输出错误信息等Java编程小技巧。 Java数组倒置...

    java源码包2

     Java数据压缩与传输实例,可以学习一下实例化套按字、得到文件输入流、压缩输入流、文件输出流、实例化缓冲区、写入数据到文件、关闭输入流、关闭套接字关闭输出流、输出错误信息等Java编程小技巧。 Java数组倒置...

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

     Java数据压缩与传输实例,可以学习一下实例化套按字、得到文件输入流、压缩输入流、文件输出流、实例化缓冲区、写入数据到文件、关闭输入流、关闭套接字关闭输出流、输出错误信息等Java编程小技巧。 Java数组倒置...

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

     Java数据压缩与传输实例,可以学习一下实例化套按字、得到文件输入流、压缩输入流、文件输出流、实例化缓冲区、写入数据到文件、关闭输入流、关闭套接字关闭输出流、输出错误信息等Java编程小技巧。 Java数组倒置...

    java源码包4

     Java数据压缩与传输实例,可以学习一下实例化套按字、得到文件输入流、压缩输入流、文件输出流、实例化缓冲区、写入数据到文件、关闭输入流、关闭套接字关闭输出流、输出错误信息等Java编程小技巧。 Java数组倒置...

    java源码包3

     Java数据压缩与传输实例,可以学习一下实例化套按字、得到文件输入流、压缩输入流、文件输出流、实例化缓冲区、写入数据到文件、关闭输入流、关闭套接字关闭输出流、输出错误信息等Java编程小技巧。 Java数组倒置...

    Android Socket UDP通讯:手机对手机or手机对PC,点对点,or广播通讯,包含发送端,接收端-测试通过运用项目中

    Android Socket UDP通讯,发送端和接收端 手机对手机或者手机对PC端, 两种通讯方式:点对点,或者广播通讯

Global site tag (gtag.js) - Google Analytics