场景
客户端 服务端 建立连接
客户端发送数据给服务端处理
服务端从输入流取到数据,处理中.....
此时客户断开连接
服务端将处理后的数据发送给客户,预想的情况,连接已断开,输出流已经不存在,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通讯程序知识点 #### 一、Java Socket编程简介 在Java中,Socket编程是一种常用的网络通信方式,它允许程序之间通过TCP/IP协议进行数据交换。Java中的`java.net.Socket`类和`java.net.ServerSocket...
Socket通讯测试工具是一种实用的软件应用,主要用于帮助程序员在开发过程中检查和验证网络通信功能,尤其是基于TCP/IP的socket通信。这个工具具有双重角色,既能够作为服务器端,也能作为客户端,使得用户能够轻松地...
在主线程中通过控制台读取键盘输入时,会产生阻塞。故另外开启一个线程,用于接受客户端的socket消息。服务器在收到一个socket连接之后,...测试可以在不同控制台运行server和client,服务器接收消息时,会显示消息来源
本文将详细讨论“卫通星GPS定位器GT06”如何通过Socket通讯协议与Java Spring Boot应用程序进行对接,以及涉及的技术点。 首先,我们要了解卫通星GPS定位器GT06。这是一款支持多种通讯方式的设备,包括GSM/GPRS网络...
标题中的“GPS定位器GT06协议socket通讯JAVA源代码”揭示了本次讨论的主要内容,即使用Java编程语言实现GPS定位器(型号为GT06)的Socket通信协议。GPS定位器是用于获取地理位置信息的设备,而GT06协议是这种特定...
总的来说,卫通星GPS定位器GT06与Java Spring Boot的Socket通讯涉及到了网络编程、数据解析、框架集成等多个技术点。通过合理的架构设计和编码实践,我们可以构建出稳定、高效的GPS监控系统,满足物联网应用的需求。
本文将深入探讨如何使用Java Socket实现多客户端与服务器的通讯,并涉及多线程技术。 首先,让我们了解Socket的基本结构。在Java中,`java.net.Socket`类代表客户端到服务器的连接,而`java.net.ServerSocket`类...
本话题主要探讨了两种常用编程语言——Java和C#之间如何利用Socket进行通信。Socket是网络编程的基本接口,允许应用程序通过网络发送和接收数据。以下是关于"Java和C#之间基于Socket的通信"的详细知识点: 1. **...
★ 支持多Socket并行测试, 采用树状Socket可视化界面,所有Socket句柄一目了然 ★ 在一个程序内可进行多句柄/多类型的Socket的创建/删除/以及数据收发等操作 ★ 支持16进制的发送和16进制接收显示,支持汉字以及文本...
总结,Android实现Socket通讯涉及创建和管理Socket对象,以及正确处理网络数据的读写。通过上述步骤,开发者可以构建基本的客户端-服务器通信模型,进一步扩展功能,如数据序列化、心跳机制、断线重连等,以满足各种...
JAIN SIP(Java API for IP Multimedia Subsystems)是一个开放源代码的SIP(Session Initiation Protocol)API,它为构建VoIP、即时通讯和其他多媒体应用程序提供了框架。SIP是一种应用层控制协议,常用于启动、...
总的来说,Socket通讯是一个涉及网络层、传输层的编程概念,通过Java的Socket类,我们可以构建出基本的TCP服务器和客户端,实现双向的数据交换。这在许多应用场景中都是必不可少的,如文件传输、在线聊天等。理解并...
Java和Android之间的Socket...总之,Java和Android的Socket通信是一种基础但强大的技术,可以实现设备间的实时通讯,例如即时聊天应用、远程控制等场景。理解并熟练掌握Socket编程,对于提升移动应用开发能力至关重要。
本项目着重讲解了如何使用Java与C语言通过Socket进行通信,实现一个基于Web的党费上交系统。在这个系统中,Java负责前端展示和部分业务逻辑,而C则作为后端服务,处理数据存储与查询,两者之间通过Socket进行数据...
【标题】"聊天室基础项目资料_socket聊天室_聊天室_java项目_socket_" 涉及的是基于Java的Socket编程技术,用于实现一个TCP/IP通信的即时聊天室。在这个项目中,开发者将学习如何利用Java的Socket类来创建客户端和...
这篇毕设将介绍一个基于Java的简单即时通讯工具的设计和开发过程。 ## 设计 在设计阶段,我们将考虑实现以下功能: 1. 用户登录和注册 2. 好友列表和聊天窗口 3. 单聊和群聊功能 4. 消息发送和接收 5. 图片和文件...
本项目“基于socket的实时通讯,简单java后台”专注于使用Java编程语言构建一个没有依赖任何特定框架的后台系统。下面将详细讨论这个项目涉及到的知识点。 首先,Socket是网络通信的基本组成部分,它是TCP/IP协议族...
Java中的Socket编程是一种网络通信机制,它允许两个网络应用程序之间进行双向通信。在这个"基于Java的socket的聊天系统"中,我们主要会涉及到以下几个关键知识点: 1. **Socket概念**:Socket是网络通信的一种接口...
Java 编写基于 CMPP3.0 的 Socket 服务端和客户端是移动通讯领域中常见的技术实践,主要用于实现与移动运营商的短信网关进行数据交互。CMPP(China Mobile Short Message Peer-to-Peer)是中国移动制定的一种短消息...
例子都可以跑通均已测试通过 com.socket 包中是一个简单的客户端发给服务器的例子 com.socket.complex 使用多线程来模拟通信 com.socket.block 根据客户端传递的参数来返回不同的信息