Java socket 读取后立即写入

Posted

技术标签:

【中文标题】Java socket 读取后立即写入【英文标题】:Java socket write immediately after read 【发布时间】:2018-03-22 10:58:11 【问题描述】:

基本上,我想要实现的是完成客户端套接字和服务器套接字之间的乒乓通信。

场景应该是这样的:

    客户端建立与服务器的连接。 客户端发送“Hello”到服务器(通过OutputStream),然后开始从服务器读取(通过InputStream) 服务器读取“Hello”消息并打印到控制台,然后将“Hello”发送到客户端(通过 OutputSteam)。 客户端打印来自服务器的响应消息并退出。

服务器套接字

try (ServerSocket serverSocket = new ServerSocket(8080)) 
            while (true) 
                // Blocking here
                Socket socket = serverSocket.accept();
                InputStream inStream = socket.getInputStream();
                OutputStream outStream = socket.getOutputStream();

                String reqMessage = new String(inStream.readAllBytes(), StandardCharsets.UTF_8);
                System.out.println(reqMessage);

                String resMessage = "Hello";
                outStream.write(resMessage.getBytes(StandardCharsets.UTF_8));
                outStream.flush();
                System.out.println(String.format("Message '%s' has been sent to client", resMessage));

                outStream.close();
                socket.close();
            
        

客户端套接字:

Socket socket = new Socket("localhost", 8080);

        OutputStream outStream = socket.getOutputStream();
        outStream.write("Hello Server".getBytes(StandardCharsets.UTF_8));
        outStream.flush();

        InputStream inStream = socket.getInputStream();
        System.out.println("Received from server");
        System.out.println(new String(inStream.readAllBytes(), StandardCharsets.UTF_8));

        outStream.close();
        socket.close();

我的问题:

一旦建立连接,双方都被阻塞,没有人打印正确的消息,就像他们在等待对方一样。一旦我关闭客户端,服务器就会打印所有正确的信息。但是,如果我从客户端删除了“从服务器读取”部分,即 InputStream 部分,那么双方都可以正常工作。我只是感到困惑,为什么它会这样?如果我想让它工作,我应该修改什么?

谢谢。

【问题讨论】:

你研究过NIO非阻塞socket***.com/questions/11745686/java-nio-client/… 您的问题是什么,您是否尝试在服务器中第二次调用inStream.readAllBytes() 以确保返回一个空数组(= 流标记结束)。如果在客户端关闭套接字之前从未调用过第二次调用,则在网络套接字流中无法识别 EOF 对这个函数有用。您可以定义消息格式numOfBytes(64bit),databytes 并在您的服务器和客户端中相应地读取。不要等待真正的文件结束/流结束状态。 @Whome 是的,但我只是在热身并练习一些基本概念,我认为 Kayaman 给出了正确答案,所有问题都来自readAllBytes(),它一直等到流关闭,这将永远不会发生。 【参考方案1】:

您的问题在于readAllBytes()。这并不意味着它会读取所有可用的字节,它会读取所有字节,直到流关闭

String reqMessage = new String(inStream.readAllBytes(), StandardCharsets.UTF_8);

将阻塞直到您关闭客户端,因为服务器仍在等待“所有”字节。同时客户端正在等待服务器发送一些东西,当然它不能这样做,因为它仍在等待来自客户端的更多数据。

无论如何,您都不应该使用字节,因为您正在编写文本消息。使用BufferedReaderInputStreamReader,例如PrintWriterOutputStreamWriter 来编写文本。不要忘记readLine() 需要来自发件人的换行符,并在InputStreamReaderOutputStreamWriter 中指定字符编码。

【讨论】:

以上是关于Java socket 读取后立即写入的主要内容,如果未能解决你的问题,请参考以下文章

Java Socket

从操作系统内核看Java非阻塞IO事件检测

actionscript socket readBytes() <- java app write() write() write()

Java学习笔记——Socket实现文件传输

iOS--(转)socket编程之Asyncsocket详解

socket缓冲区以及阻塞模式