首页 文章

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

提问于
浏览
4

Hi, all

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

  • 创建一个SocketServer来侦听某个端口 .

  • 接受连接并创建相应的套接字对象

  • 从创建的套接字读取InputStream(在此操作中被阻止)


客户端:

  • 创建套接字对象以与服务器 Build 连接 .

  • 通过向OutputStream写入字节来发送命令以关闭服务器端的浏览器 .

  • 使用套接字的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<InetAddress> 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中注释掉反馈读取操作时,服务器和客户端都能正常工作 .


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

2 回答

  • 12

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

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

    如果要在单个套接字连接上发送多个命令,则需要提供一种分隔每个命令的方法(simple example here) .

  • 2

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

相关问题