Socket通讯产生阻塞的解决方案

来源:互联网 发布:中国旅游数据统计 编辑:程序博客网 时间:2024/06/06 18:05

Socket通讯正常想实现的流程:

是客户端给服务端发送发送报文,当服务端接收到报文后,给客户端一个反馈信息。



目前代码实现情况是:

客户端和服务端在read时都被阻塞了,经过反复的查阅相关资料和测试,发现了问题的根本。



导致read阻塞的原因是:

当客户端给服务端发送完数据的时候服务端在读取数据,但是服务端没有办法判断什么时候会自动中断,所以服务端会在这个地方阻塞。

阻塞之后服务端就没有办法往客户端发送数据,这个时候客户端的接收数据也会等服务端的数据,会在这里阻塞。这个时候服务端和客户端都不会关闭,会一直持续阻塞。

客户端传递数据的时候,服务端不知道什么时候终止,用read!=-1是没有办法判断出来的,因为客户端流没有终止,流一直存在,所以服务端以为数据没有传输完毕。


有两个解决方案,方案如下:

1.在客户端传输结束之后,你可以把流进行关闭,使用socket.shutdownOutput()和socket.shutdownInput()这两个方法,将流关闭掉,对面就可以接收到结束的信号。

2.双方约定好,定义一个结束符,客户端每次给服务端发送报文时,在发送结束加上结束符;当服务端这面接收到报文读取时,读到结束符的话,就证明是结束了,就不在循环了。


方案1服务端代码:

package com.pactera.ok;import java.io.BufferedReader;  import java.io.IOException;  import java.io.InputStream;  import java.io.InputStreamReader;  import java.io.OutputStream;  import java.io.PrintWriter;  import java.net.ServerSocket;  import java.net.Socket;  /** * @Title:TestZLFServer * @Description:  * @company:XXXXXX * @author:XXXXXX-zhanglf * @date:2017-5-16 * @version:1.0.0 */public class TestZLFServer {      public static void main(String[] args) {          try {              ServerSocket ss=new ServerSocket(10086);              Socket s=ss.accept();              InputStream is=s.getInputStream();              BufferedReader br=new BufferedReader(new InputStreamReader(is));              OutputStream os=s.getOutputStream();              PrintWriter pw=new PrintWriter(os);              //读取用户输入信息              String info=null;              while(((info=br.readLine()) !=null)){                  System.out.println("我是服务器,用户信息为:"+info);                  s.shutdownInput();            }                          //给客户端一个响应              String result="客户端,我收到你发过的信息了,通知你一下";              pw.write(result);              pw.flush();                          pw.close();              os.close();              br.close();              is.close();              s.close();              ss.close();          } catch (IOException e) {              e.printStackTrace();          }          }  }  

方案1客户端代码:

package com.pactera.ok;import java.io.BufferedReader;  import java.io.IOException;  import java.io.InputStream;  import java.io.InputStreamReader;  import java.io.OutputStream;  import java.io.PrintWriter;  import java.net.InetAddress;import java.net.Socket;  import java.net.UnknownHostException;  /** * @Title:TestZLFClient * @Description:  * @company:XXXXXX * @author:XXXXXX-zhanglf * @date:2017-5-16 * @version:1.0.0 */public class TestZLFClient {      public static void main(String[] args) {          try {              Socket s =new Socket(InetAddress.getLocalHost(),10086);              OutputStream os=s.getOutputStream();              PrintWriter pw=new PrintWriter(os);              InputStream is=s.getInputStream();              BufferedReader br=new BufferedReader(new InputStreamReader(is));              //给服务端发送的短信内容            String info="ssssssssssss";              pw.write(info);              pw.flush();              s.shutdownOutput(); //不加这句代码,客户端输出不了给果:             //接收服务器的相应              String result=null;              while(!((result=br.readLine())==null)){                  System.out.println("接收服务器的信息:"+result);              }              //关闭资源              br.close();              is.close();              pw.close();              os.close();              s.close();          } catch (UnknownHostException e) {              e.printStackTrace();          } catch (IOException e) {              e.printStackTrace();          }      }  }  

方案2服务端代码:

package com.pactera.ok3;import java.io.InputStream;import java.io.OutputStream;import java.net.ServerSocket;import java.net.Socket;/** * @Title:Server3 * @Description:  * @company:XXXXX * @author:XXXXX-zhanglf * @date:2017-5-16 * @version:1.0.0 */public class Server3 {public static void main(String[] args) { try { // 创建一个服务端ServerSocket,监听指定端口的请求 ServerSocket ss = new ServerSocket(10086); System.out.println("=============Server 等待客户端接入==============="); // 监听客户端请求 Socket socket = ss.accept(); // 与客户端建立连接之后,读取客户端发过来的信息 InputStream is = socket.getInputStream(); byte[] buffer = new byte[1024]; int len = 0; // 定义一个字符串构建器,用于存储客户端发过来的数据 StringBuilder sb = new StringBuilder(); int index; while ( (len=is.read(buffer)) != -1 ) {String temp = "";String tmp = new String(buffer, 0, 2); /**01-单独给信贷系统增加的处理逻辑**/if("xd".equals(tmp)){temp = new String(buffer, 0, len); //System.out.println("temp ====== : "+temp);// 读到结束符,则跳出循环 if ( (index=temp.indexOf("eof")) != -1 ) { // 截取指定长度 sb.append(temp.substring(2, index)); break; } }else{/**02-核心原有处理逻辑**/temp = new String(buffer, 0, len); }// 如果没有读到结束符,则继续读取,并加入字符串构建器 sb.append(temp); } System.out.println("Server 来自客户端的信息 : " + sb.toString()); // 读完之后,往客户端发送响应数据 OutputStream out = socket.getOutputStream(); out.write("Hello Client!".getBytes()); out.write("eof".getBytes());// 写一个结束符 out.flush(); out.close(); is.close(); socket.close(); ss.close();}catch (Exception e) {e.printStackTrace(); }}}

方案2客户端代码:

package com.pactera.ok3;import java.io.InputStream;import java.io.OutputStream;import java.net.InetAddress;import java.net.Socket;/** * @Title:Client3 * @Description:  * @company:XXXXX * @author:XXXXX-zhanglf * @date:2017-5-16 * @version:1.0.0 */public class Client3 {public static void main(String[] args) { try{// 与服务端建立连接(服务端主机号,服务端监听的端口号) Socket socket = new Socket(InetAddress.getLocalHost(),10086); // 与服务端建立连接之后,就可以往服务端写数据 OutputStream out = socket.getOutputStream(); // 往服务端中写数据 out.write("xd|0|001101|150XXXXXXXX|您好,你卡号取款200元。|".getBytes()); out.write("eof".getBytes());// 写一个结束符,表示写入完毕 out.flush(); // 写完之后,获取服务端的响应数据 InputStream is = socket.getInputStream(); byte[] buffer = new byte[1024]; int len = 0; // 定义一个StringBuilder存储客户端发过来的数据 StringBuilder sb = new StringBuilder(); int index; while ( (len=is.read(buffer)) != -1 ) { String temp = new String(buffer, 0, len); // 读到结束符,则跳出循环 if ( (index=temp.indexOf("eof")) != -1) { sb.append(temp.substring(0, index)); break; } sb.append(temp); } System.out.println("Client 来自服务端的信息 : " + sb.toString()); out.close(); is.close(); socket.close();}catch (Exception e) {e.printStackTrace();}}}




原创粉丝点击