读取/写入 Java 服务器套接字的最佳实践

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/10311872/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-10-31 00:30:28  来源:igfitidea点击:

Best practice for reading / writing to a java server socket

javasocketsnetworking

提问by Schifty

How do you design a read and write loop which operates on a single socket (which supports parallel read and write operations)? Do I have to use multiple threads? Is my (java) solution any good? What about that sleep command? How do you use that within such a loop?

您如何设计在单个套接字上运行的读写循环(支持并行读写操作)?我必须使用多个线程吗?我的(java)解决方案有什么好处吗?那个 sleep 命令呢?你如何在这样的循环中使用它?

I'm trying to use 2 Threads:

我正在尝试使用 2 个线程:

Read

public void run() {
    InputStream           clientInput;
    ByteArrayOutputStream byteBuffer;
    BufferedInputStream   bufferedInputStream;
    byte[]                data;
    String                dataString;
    int                   lastByte;

    try {
        clientInput         = clientSocket.getInputStream();
        byteBuffer          = new ByteArrayOutputStream();
        bufferedInputStream = new BufferedInputStream(clientInput);

        while(isRunning) {  

            while ((lastByte = bufferedInputStream.read()) > 0) {
                byteBuffer.write(lastByte);
            }
                data       = byteBuffer.toByteArray();  
                dataString = new String(data);
                byteBuffer.reset();     
        }   

    } catch (IOException e) {
        e.printStackTrace();
    }
}

Write

public void run() {
    OutputStream clientOutput;
    byte[]       data;
    String       dataString;

    try {
        clientOutput = clientSocket.getOutputStream();

        while(isOpen) { 

            if(!commandQueue.isEmpty()) {
                dataString = commandQueue.poll();
                data       = dataString.getBytes();
                clientOutput.write(data);
            }                   
            Thread.sleep(1000);
        }       
        clientOutput.close();           
    } 
    catch (IOException e) {
        e.printStackTrace();
    } 
    catch (InterruptedException e) {
        e.printStackTrace();
    }
}

Read fails to deliver a proper result, since there is no -1 sent. How do I solve this issue?

Read 无法提供正确的结果,因为没有发送 -1。我该如何解决这个问题?

Is this sleep / write loop a good solution?

这个睡眠/写入循环是一个很好的解决方案吗?

采纳答案by user207421

There are basically three ways to do network I/O:

基本上有三种方式进行网络 I/O:

  1. Blocking. In this mode reads and writes will block until they can be fulfilled, so if you want to do both simultaneously you need separate threads for each.

  2. Non-blocking. In this mode reads and writes will return zero (Java) or in some languages (C) a status indication (return == -1, errno=EAGAIN/EWOULDBLOCK) when they cannot be fulfilled, so you don't need separate threads, but you do need a third API that tells you when the operations canbe fulfilled. This is the purpose of the select()API.

  3. Asynchronous I/O, in which you schedule the transfer and are given back some kind of a handle via which you can interrogate the status of the transfer, or, in more advanced APIs, a callback.

  1. 阻塞。在这种模式下,读和写会阻塞,直到它们被完成,所以如果你想同时做这两个,你需要为每个单独的线程。

  2. 非阻塞。在这种模式下,读取和写入将在无法完成时返回零(Java)或在某些语言(C)中返回状态指示(返回 == -1,errno=EAGAIN/EWOULDBLOCK),因此您不需要单独的线程,但是您确实需要第三个 API 来告诉您何时可以完成操作。这就是select()API的目的。

  3. 异步 I/O,您可以在其中安排传输并返回某种句柄,您可以通过该句柄查询传输状态,或者在更高级的 API 中为回调。

You should certainlynever use the while (in.available() > 0)/sleep()style you are using here. InputStream.available()has few correct uses and this isn't one of them, and the sleep is literally a waste of time. The data can arrive within the sleep time, and a normal read()would wake up immediately.

当然不应该使用你在这里使用的while (in.available() > 0)/sleep()样式。InputStream.available()几乎没有正确的用途,这不是其中之一,而且睡眠实际上是在浪费时间。数据可以在睡眠时间内到达,正常人read()会立即醒来。

回答by E-Kami

You should rather use a boolean variable instead of while(true) to properly close your thread when you will want to. Also yes, you should create multiple thread, one per client connected, as the thread will block itself until a new data is received (with DataInputStream().read() for example). And no, this is not really a design question, each library/Framework or languages have its own way to listen from a socket, for example to listen from a socket in Qt you should use what is called "signals and slots", not an infinite loop.

您应该在需要时使用布尔变量而不是 while(true) 来正确关闭线程。同样是的,您应该创建多个线程,每个连接的客户端一个,因为线程会阻塞自己,直到收到新数据(例如 DataInputStream().read())。不,这不是一个真正的设计问题,每个库/框架或语言都有自己的从套接字监听的方式,例如从 Qt 中的套接字监听你应该使用所谓的“信号和插槽”,而不是无限循环。