【问题标题】:Socket mirror sends but does not receive套接字镜像发送但不接收
【发布时间】:2012-01-26 23:37:48
【问题描述】:

我有一个 Java 程序,它可以镜像从客户端服务器到远程服务器的连接。镜像发送数据找到,但收不到。我终其一生都无法弄清楚为什么。这是我的代码:

Socket client = new Socket("127.0.0.1", 42001);
System.out.println("Connected to client!");
Socket server = new Socket(serverAddress, serverPort);
System.out.println("Connected to server!");

BufferedReader clientin = new BufferedReader(new InputStreamReader(client.getInputStream()));
BufferedWriter scratchout = new BufferedWriter(new OutputStreamWriter(client.getOutputStream()));

BufferedReader serverin = new BufferedReader(new InputStreamReader(server.getInputStream()));
BufferedWriter serverout = new BufferedWriter(new OutputStreamWriter(server.getOutputStream()));

int i;
boolean serverNeedsFlush = false;
boolean clientNeedsFlush = false;
while (true)
{
    while (clientin.ready())
    {
        i = clientin.read();
        serverout.write(i);
        serverNeedsFlush = true;
    }
    if(serverNeedsFlush)
    {
        serverout.flush();
        serverNeedsFlush = false;
    }
    while (serverin.ready())
    {
        i = serverin.read();
        System.out.print((char)i);
        scratchout.write(i);
        clientNeedsFlush = true;
    }
    if(clientNeedsFlush)
    {
        scratchout.flush();
        clientNeedsFlush = false;
    }
}

【问题讨论】:

  • 如果您使用两个线程,则根本不需要忙于等待或读取行。只需复制你得到的数据。

标签: java sockets io


【解决方案1】:

如果您尝试将数据从一个套接字转发到另一个套接字,那么直接使用套接字流而不是装饰它们可能是一个更好的主意。

正如其他海报所建议的,您应该使用线程来执行此操作。它会让生活更轻松。然后,您可以使用线程执行基本的输入到输出流复制,如下所示。

public static void streamCopy(InputStream in, OutputStream out)
       throws IOException{

        byte[] data = new byte[1024];
        int length;
        do{
            length = in.read(data);
            if(length > 0){
                out.write(data, 0, length);
                out.flush();
            }
        }while(length != -1);

}

当上述方法返回时,您将读取整个in 流并将其写入out 流。您的线程或可运行对象的运行方法可能如下所示。

public void run() {

    Socket inSock = null;
    Socket outSock = null;
    try{
        inSock = new Socket(inHost, inPort);
        outSock = new Socket(inHost, inPort);
        /* Set up some socket options here (timeouts, buffers etc)*/

        /* Insert pre copy actions */

        /* This method won't return until inSock's inputStream hits end of stream. 
         * and all the data has been written to outSock's outputStream and flushed. */
        streamCopy(inSock.getInputStream(), outSock.getOutputStream());

        /* In order to really do this correctly you should create an 
         * application protocol that verifies the upstream receiver 
         * is actually getting the data before you close the socket. */

        /* Insert post copy actions */

    }catch(Exception e){
        /* Corrective action or logging here */
    }finally{
        /* Don't forget to close the sockets. */
        if(inSock != null){
            try{
                inSock.close();
            }catch(Exception e){
                /* Don't care */
            }
        }
        if(outSock != null){
            try{
                outSock.close();
            }catch(Exception e){
                /* Don't care */
            }
        }
    }
}

【讨论】:

  • 如果你调用了flush,但是没有什么可以flush,它什么也做不了。无需设置标志。
  • 你可以写length = clientin.read(data);,这也差不多。
  • @Peter 我不确定length = clientin.read(data); 是否会尝试读取可用缓冲区并阻塞,因此我明确传递了长度,因此它只会读取可用缓冲区并返回。冲洗部分很好,我错过了,因为它是 OPs 代码的复制粘贴。
  • 这一直有效,直到我断开连接然后再次连接。我将不得不更深入地研究这一点。
  • @MathWizz 以上并非旨在成为功能完整的实现。
【解决方案2】:

您无法在一个线程中正确执行此操作。您需要两个线程,每个方向一个。每个线程只是读写,直到遇到 EOS。并且不要使用 available(): 只是阻止读取。设置读取超时以避免异常情况。

【讨论】:

    猜你喜欢
    • 2013-06-18
    • 1970-01-01
    • 1970-01-01
    • 2017-09-11
    • 1970-01-01
    • 2010-11-14
    • 1970-01-01
    • 1970-01-01
    • 2013-03-21
    相关资源
    最近更新 更多