Java 套接字流的可靠性如何';s flush()是什么?

Java 套接字流的可靠性如何';s flush()是什么?,java,android,networking,tcp,Java,Android,Networking,Tcp,考虑一下这段(简化的)代码: public class Test { // assigned elsewhere InetSocketAddress socketAddress; String socketHost; int socketPort; Socket socket; int COMMAND = 10; int CONNECTION_TIMEOUT = 10 * 1000; int SOCKET_TIMEOUT = 30

考虑一下这段(简化的)代码:

public class Test {
    // assigned elsewhere
    InetSocketAddress socketAddress;
    String socketHost;
    int socketPort;
    Socket socket;

    int COMMAND = 10;
    int CONNECTION_TIMEOUT = 10 * 1000;
    int SOCKET_TIMEOUT = 30 * 1000;
    DataOutputStream dos;
    DataInputStream  dis;

    protected void connect() throws IOException, InterruptedException {
        socket.connect(socketAddress != null ? socketAddress : new InetSocketAddress(socketHost, socketPort), CONNECTION_TIMEOUT);

        socket.setSoTimeout(SOCKET_TIMEOUT);
        socket.setTcpNoDelay(true);
    }

    void initializeDataStreams() throws IOException {
        dos = new DataOutputStream(new BufferedOutputStream(socket.getOutputStream(), socket.getSendBufferSize()));
        dis = new DataInputStream( new BufferedInputStream( socket.getInputStream(),  socket.getReceiveBufferSize()));
    }

    void run() {
        try {
            connect();
            initializeDataStreams();

            sendCommand(COMMAND, true);

            sendIdAndUsername(true);

            sendSyncPreference(true);

            sendBlockedIds(true);

            sendHeaders();

            // reading from 'dis' here
            // ...

        } catch (InterruptedException | IOException e){
            /* ... */
        }
    }

    void sendCommand(int command, boolean buffered) throws IOException {
        dos.write(command);
        if (!buffered) {
            dos.flush();
        }
    }

    void sendIdAndUsername(boolean buffered) throws IOException {
        sendId(true);  // always buffered
        String username = "user name";
        dos.writeBoolean(username != null);
        if (username != null) {
            dos.writeUTF(username);
        }
        if (!buffered) {
            dos.flush();
        }
    }

    void sendId(boolean buffered) throws IOException {
        dos.writeUTF("user id");
        if (!buffered) {
            dos.flush();
        }
    }

    void sendSyncPreference(boolean buffered) throws IOException {
        boolean fullSync = true;
        dos.writeBoolean(fullSync);
        if (!buffered) {
            dos.flush();
        }
    }

    void sendBlockedIds(boolean buffered) throws IOException {
        Set<String> blockedCrocoIds = new HashSet<>();

        ObjectOutputStream oos = new ObjectOutputStream(dos);
        oos.writeObject(blockedCrocoIds);
        if (!buffered) {
            oos.flush();
        }
    }

    private void sendHeaders() throws IOException {
        dos.writeUTF("some string");
        dos.writeInt(123);
        // some other writes...

        // this should flush everything, right?
        dos.flush();
    }
}
然后:

public class ListeningThread extends Thread {
    private ServerSocket serverSocket;

    public ListeningThread() {
        try {
            // unbound server socket
            serverSocket = new ServerSocket();
            serverSocket.setReuseAddress(true);
            serverSocket.bind(new InetSocketAddress(NetworkUtil.APP_SERVER_PORT));
        } catch (IOException e) {
            log(e);
        }
    }

    @Override
    public void run() {
        log("run");

        while (serverSocket.isBound() && !isInterrupted()) {
            try {
                Socket socket = serverSocket.accept();
                new CommandThread(socket).start();
            } catch (IOException e) {
                log(e);
            }
        }

        try {
            serverSocket.close();
        } catch (IOException e) {
            log(e);
        }
    }
}
最后:

public class CommandThread extends Thread {
    private final Socket socket;

    public CommandThread(Socket socket) {
        log("CommandThread");

        this.socket = socket;
    }

    @Override
    public void run() {
        log("run");

        try {
            socket.setSoTimeout(NetworkUtil.SOCKET_TIMEOUT);
            socket.setTcpNoDelay(true);

            InputStream is = socket.getInputStream();
            int cmd = is.read(); // <========= so actually this is failing
            switch (cmd) {
                // handling of the command
                case COMMAND:
                    new DownloadMessagesThread(socket).start();
                break;
            }
        } catch (IOException | SQLException e) {
            log(e);
        }
    }
}
public类CommandThread扩展线程{
专用终端插座;
公共命令线程(套接字){
日志(“命令线程”);
this.socket=socket;
}
@凌驾
公开募捐{
日志(“运行”);
试一试{
socket.setSortimeout(NetworkUtil.socket\u超时);
socket.setTcpNoDelay(true);
InputStream=socket.getInputStream();

int cmd=is.read();//您应该验证在
sendblockedds
中创建的
ObjectOutputStream
不是罪魁祸首。 在混合数据流和ObjectStreams时,我已经遇到了一些协议“死锁”,因为ObjectStreams的编写器/读取器对的创建意味着一种握手,在混合这些流时可能会失败


编辑:当再次阅读您的问题时,我意识到我没有回答它。因此,是的,它是可靠的。EJP答案为+1。

要回答您标题中的问题,它是100%可靠的,因为它不做任何事情。只有
flush()
缓冲流的方法实际上可以做任何事情,并且只包括
ObjectOutputStream
BufferedOutputStream
,以及
PrintStream
,这取决于您如何构造它。不是
DataOutputStream
,也不是套接字本身的输出流

因此,在本例中,唯一可以执行任何操作的flush方法是缓冲输出流,您当然可以依赖它,因为它只是代码,已经工作了20年

如果这影响了
accept()
的速度,那么您的accept循环肯定有一些奇怪的地方,您没有告诉我们:通常,在accept循环中而不是在启动的线程中执行I/O

您当然不应该在连接的中间创建<代码> ObjutOutsStudio。在开始时创建它,并将其用于所有的内容,另一方面使用<代码> ObjutsPosivsStuts


注意:将缓冲区大小分别设置为套接字缓冲区大小实际上是毫无意义的。默认值是足够的。

我建议使用JSON之类的表示,而不是发送二进制对象。我知道你的意思,我也有同样的痛苦。然而,ObjectOutputStream的构造函数只是通过str发送几个字节eam,仅此而已。因此,即使有一些可怕的错误,它至少会到达accept()在服务器端,不是吗?如果这几个字节没有刷新,那么服务器端ObjectInputStream的构造函数将不会在超时时间内退出。我们可能需要服务器代码来进一步帮助您。@Xvolks:100%同意,这可能会导致问题的出现。但是正如前面提到的,服务器端甚至没有达到ac之外的点cept(),因此,无论发生什么,它都没有机会这样做,就像传输在22秒后才在客户端发生一样(我有来自服务端的完整日志,所以我可以看到它当时到达了侦听器…).为了安全起见,我添加了服务器代码。缓冲区大小设置不是我想出来的,我在Esmond Pitt的Java基本网络中看到了它,所以我认为他知道自己在做什么。知道什么会导致发送过程中出现如此严重的延迟吗?如果我在FNIJ中写下,我会收回它。什么页面?延迟只能由网络c造成条件或效果,而不是你的代码。大多数发送应该只需要一两秒钟,除非接收者非常备份和落后。第42页,第331页,也在书中提供的可用示例源代码中。哇。我在想什么?在大约2001-2年写了这篇文章:从那时起,我必须通过
Obj“完善”我的想法。”只有当您调用
writeObject()
时,才会分配数KBs的“数KBs”才是真的,它不是“数KBs”,而是哈希映射中的一个插槽。如果您调用
writeUTF()
writeInt()
等,则根本没有内存使用。发布非真实代码的代码是徒劳的。
public class CommandThread extends Thread {
    private final Socket socket;

    public CommandThread(Socket socket) {
        log("CommandThread");

        this.socket = socket;
    }

    @Override
    public void run() {
        log("run");

        try {
            socket.setSoTimeout(NetworkUtil.SOCKET_TIMEOUT);
            socket.setTcpNoDelay(true);

            InputStream is = socket.getInputStream();
            int cmd = is.read(); // <========= so actually this is failing
            switch (cmd) {
                // handling of the command
                case COMMAND:
                    new DownloadMessagesThread(socket).start();
                break;
            }
        } catch (IOException | SQLException e) {
            log(e);
        }
    }
}