4

こんにちは、みんな

私は最近、ブラウザをリモートで閉じることを目的とした小さなプログラムに取り組んでいます。基本的な手順は次のとおりです。
サーバー側:

  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<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 のフィードバック読み取り操作をコメント アウトすると、サーバーとクライアントの両方が正しく機能します。

これらのコードに隠された原因は何だろう?
誰かが私を助けてくれることを願っています、どうもありがとう!

4

2 に答える 2

13

ソケット読み取りコードは EOF まで読み取っています。ソケットを閉じるまで、EOF を受け取りません。したがって、コードは続行されません。

ソケット接続で 1 つのコマンドのみを送信する場合は、コマンドを書き込んだ後に OutputStream を閉じます ( を使用Socket.shutdownOutput())。

単一のソケット接続で複数のコマンドを送信する場合は、各コマンドを区切る方法を考え出す必要があります (簡単な例はこちら)。

于 2012-08-30T03:32:57.507 に答える
2

同じ接続でさらにデータを送信する機能を失うことなくEOSを「送信」できないため、両端でEOSまで読み取りますが、これは悪い選択です。アプリケーション プロトコルを再設計して、コマンドを完了するために接続を閉じなくても一度にコマンドを読み取れるようにする必要があります。たとえば、行、長さの語の接頭辞、XML や Java Object Serialization などの自己記述型プロトコル、または EOFException に依存せずに DataInputStream を介して読み取ることができるものすべてを送信します。

于 2012-08-30T09:58:28.587 に答える