java socket InputStream在客户端和服务器上挂起/阻塞

大家好

我最近正在开发一个旨在远程关闭浏览器的小程序。 基本程序如下:
服务器端:

  1. 创建一个SocketServer来监听某个端口。
  2. 接受连接并创建相应的套接字对象
  3. 从创建的套接字读取InputStream(在此操作中被阻止)

客户端:

  1. 创建套接字对象以与服务器建立连接。
  2. 发送命令以通过向OutputStream写入字节来关闭服务器端的浏览器。
  3. 通过在套接字的InputStream上使用read()来读取服务器的反馈(在此操作中被阻止)

代码如下:

Server.java

package socket; import java.io.IOException; import java.net.InetAddress; import java.net.NetworkInterface; import java.net.ServerSocket; import java.net.Socket; import java.util.Enumeration; import java.util.concurrent.ExecutorService; import java.util.concurrent.Executors; public class Server { private static ExecutorService es = Executors.newFixedThreadPool(5); public static void main(String[] args) throws IOException { InetAddress targetAddress = null; NetworkInterface ni = NetworkInterface.getByName("eth2"); System.out.println(ni); Enumeration inetAddresses = ni.getInetAddresses(); while(inetAddresses.hasMoreElements()) { InetAddress inetAddress = inetAddresses.nextElement(); if(inetAddress.toString().startsWith("/10")) { targetAddress = inetAddress; break; } } ServerSocket sSocket = new ServerSocket(11111, 0, targetAddress); while(true) { System.out.println("Server is running..."); Socket client = sSocket.accept(); System.out.println("Client at: " + client.getRemoteSocketAddress()); es.execute(new ClientRequest(client)); } } } 

ClientRequest.java

 package socket; import java.io.IOException; import java.io.InputStream; import java.io.OutputStream; import java.net.Socket; public class ClientRequest implements Runnable { private Socket client; public ClientRequest(Socket client) { this.client = client; } @Override public void run() { try { System.out.println("Handled by: " + Thread.currentThread().getName()); // get input/output streams for client socket InputStream cis = client.getInputStream(); OutputStream cos = client.getOutputStream(); // buffer size : 1024 ? byte[] buffer = new byte[1024]; int recvSize; int totalRecvSize = 0; while(-1 != (recvSize = cis.read(buffer, totalRecvSize, 1024 - totalRecvSize))) { totalRecvSize += recvSize; } String command = new String(buffer, "utf-8"); System.out.println("Command from client: " + command); String commandNative = CommandMap.getNativeCommand(command.trim()); if(null != commandNative) { Process np = Runtime.getRuntime().exec(commandNative); InputStream is = np.getInputStream(); byte[] bufferProcess = new byte[1024]; int bytesRead; int totalBytesRead = 0; while(-1 != (bytesRead = is.read(bufferProcess, totalBytesRead, 1024 - totalBytesRead))) { totalBytesRead += bytesRead; } // give feed back of process output cos.write(bufferProcess); // close process input stream is.close(); } } catch (IOException e) { e.printStackTrace(); } finally { if(null != client) { try { client.close(); } catch (IOException e) { e.printStackTrace(); } } } } 

最后, Client.java

 package socket; import java.io.IOException; import java.io.InputStream; import java.io.OutputStream; import java.net.Socket; import java.net.UnknownHostException; import java.nio.charset.Charset; public class Client { private static final int BUF_SIZE = 1024; // feedback message size will not exceed 1024 bytes private static final byte[] BUFFER = new byte[BUF_SIZE]; public static void main(String[] args) throws UnknownHostException, IOException, InterruptedException { Socket socket = new Socket("10.117.37.176", 11111); System.out.println("Connected to Server..."); OutputStream os = socket.getOutputStream(); InputStream is = socket.getInputStream(); String command = "kill ie"; byte[] commandBytes = command.getBytes(Charset.forName("utf-8")); System.out.println("Send: " + command); os.write(commandBytes); System.out.println("After send: " + command); int totalRecv = 0; int recvSize; while(-1 != (recvSize = is.read(BUFFER, totalRecv, BUF_SIZE - totalRecv))) { totalRecv += recvSize; } String feedback = new String(BUFFER, "utf-8"); System.out.println("Feedback: " + feedback); socket.close(); } } 

重申问题:

  • 服务器端无法通过调用套接字的InputStream对象上的read(buffer,offset,len)来读取命令。 它阻止。
  • 客户端无法通过调用其套接字的InputStream对象上的read(buffer,offset,len)来读取反馈。 它阻止。
  • 但是当我在Client.java中注释掉反馈读取操作时,服务器和客户端都能正常工作。

我想知道这些代码中隐藏的原因是什么?
希望有人可以帮助我,非常感谢!

您的套接字读取代码正在读取,直到EOF。 在关闭sockets之前,您不会收到EOF。 因此,您的代码永远不会继续。

如果您只想在套接字连接上发送单个命令,则在写入命令后关闭OutputStream(使用Socket.shutdownOutput() )。

如果要在单个套接字连接上发送多个命令,则需要提供一种分隔每个命令的方法( 此处为简单示例 )。

您正在阅读两端的EOS,这是一个糟糕的选择,因为您无法“发送”EOS而不会失去在同一连接上发送更多数据的能力。 您需要重新设计应用程序协议,以便一次可以读取命令,而无需关闭连接以完成它。 例如,发送行,或长度字前缀,或自描述协议(如XML或Java对象序列化),或者您可以通过DataInputStream读取的任何内容,而不依赖于EOFException。