【问题标题】:Java OutputStream only flushes data on closeJava OutputStream 仅在关闭时刷新数据
【发布时间】:2015-04-20 14:29:16
【问题描述】:
Socket socket = new Socket("192.168.178.47", 82);

OutputStream out = socket.getOutputStream();
out.write("{ \"phone\": \"23456789\" }".getBytes());
out.flush();

//服务器

InputStream in = client.getInputStream();
ByteArrayOutputStream bOut = new ByteArrayOutputStream();

int i = 0;
while((i = in.read()) >= 0) {
    bOut.write(i);
}

String complete = new String(bOut.toByteArray(), "UTF-8");

我曾尝试通过 OutputStream 将数据发送到套接字,但数据未刷新。如果我在末尾添加一个out.close();,那么它可以完美运行,但是套接字已关闭,我无法接受响应。有人知道为什么吗?服务器没有给出任何类型的错误。我用过 Java 1.7!

【问题讨论】:

  • 服务器代码是什么样的?
  • 如何确认输出没有发送?
  • 嗯,你知道,OutputStream.flush()。此外,您编写 JSON 的方式也被破坏了:它使用 JRE 的默认编码。为什么不使用 JSON 库呢?

标签: java sockets outputstream


【解决方案1】:

服务器可能正在等待行尾。如果是这种情况,请在文本中添加“\n”

【讨论】:

  • 这正是我的程序正在做的事情。感谢您的提示!
【解决方案2】:

我不确定您问题中的标签“//Server”,但我假设以下代码是服务器代码:

InputStream in = client.getInputStream();
ByteArrayOutputStream bOut = new ByteArrayOutputStream();

int i = 0;
while((i = in.read()) >= 0) {
    bOut.write(i);
}

String complete = new String(bOut.toByteArray(), "UTF-8");

这将继续读取,每次都阻塞,直到它从read() 获得一个小于零的值。只有在流关闭时才会发生这种情况。

看起来您确实需要建立自己的协议。因此,与其寻找“

这是我的意思的快速演示(我昨天没有时间)。我有 3 个类,MessageMyClient(这也是 main 类)和 MyServer。请注意,没有任何关于发送或接收换行符的内容。没有设置 tcpNoDelay。但它工作正常。其他一些注意事项:

  • 此代码仅发送和接收单个请求和响应。
  • 不支持发送多个Message 实例。这需要检查 Message 的开头和结尾。

Message类:

public class Message {
    public static final String MSG_START = "<message>";
    public static final String MSG_END = "</message>";

    private final String content;

    public Message(String string){
        content = string;
    }

    @Override
    public String toString(){
        return MSG_START + content + MSG_END;
    }
}

MyServer

public class MyServer implements Runnable{
    public static final int PORT = 55555;

    @Override
    public void run(){
        try {
            ServerSocket serverSocket = new ServerSocket(PORT);
            Socket socket = serverSocket.accept();
            String message = getMessage(socket);
            System.out.println("Server got the message:  " + message);
            sendResponse(socket);
        }catch (IOException e){
            throw new IllegalStateException(e);
        }
    }

    private void sendResponse(Socket socket) throws IOException{
        Message message = new Message("Ack");
        System.out.println("Server now sending a response to the client: " + message);
        OutputStream out = socket.getOutputStream();
        out.write(message.toString().getBytes("UTF-8"));
    }

    private String getMessage(Socket socket) throws IOException{

        BufferedInputStream in = new BufferedInputStream(socket.getInputStream());
        StringBuilder sb = new StringBuilder(100);
        byte[] bytes = new byte[1024<<8];
        while(sb.lastIndexOf(Message.MSG_END) == -1){
            int bytesRead = in.read(bytes);
            sb.append(new String(bytes,0,bytesRead,"UTF-8"));
        }

        return sb.toString();
    }
}

MyClient

public class MyClient {

    public static void main(String[] args){
        MyClient client = new MyClient();

        Thread server = new Thread(new MyServer());
        server.start();

        client.performCall();
    }

    public void performCall(){
        try {
            Socket socket = new Socket("127.0.0.1",MyServer.PORT);
            sendMessage(socket, "Why hello there!");
            System.out.println("Client got a response from the server: " + getResponse(socket));
        } catch (IOException e) {
            throw new IllegalStateException(e);
        }
    }

    public String getResponse(Socket socket) throws IOException{
        String response;

        StringBuilder sb = new StringBuilder(100);
        InputStream in = socket.getInputStream();
        byte[] bytes = new byte[1024];
        while(sb.lastIndexOf(Message.MSG_END) == -1){
            int bytesRead = in.read(bytes);
            sb.append(new String(bytes,0,bytesRead,"UTF-8"));
        }
        response = sb.toString();

        return response;
    }

    public void sendMessage(Socket socket, String message) throws IOException{
        Message msg = new Message(message);
        System.out.println("Client now sending message to server: " + msg);
        OutputStream out = socket.getOutputStream();
        out.write(msg.toString().getBytes("UTF-8"));
    }
}

输出

客户端现在向服务器发送消息:为什么你好!
服务器收到消息:为什么你好!
服务器现在向客户端发送响应:Ack
客户端得到服务器的响应:Ack

进程以退出代码 0 结束

【讨论】:

  • 无法从客户端代码发送 -1。他正在读取单个字节。只要连接没有关闭,他就只能接收 0 到 255 之间的值。如果客户端调用 out.write(-1),服务器将接收 255。
  • @SpiderPig 老实说,我不太确定。我对过去这样做的记忆模糊,但我可能记错了。你说的有道理。我正在更新我的答案以反映它。
【解决方案3】:

尝试使用

socket.setTcpNoDelay(true);

出于性能原因会发生缓冲(阅读 Nagle 的算法)。

【讨论】:

  • 伟大的思想 :) 我试图在你之前发帖,但这个网站开始变得很慢(其他网站都很好)。
【解决方案4】:

查看您的代码似乎还可以。但是,您发送的 MTU 少于 Nagle 的算法可能会阻止它,直到有足够的数据用于完整的数据包或您关闭套接字。

所以 - 试试这个:

socket.setTCPNoDelay(true);

http://en.wikipedia.org/wiki/Nagle%27s_algorithm https://docs.oracle.com/javase/8/docs/api/java/net/Socket.html#setTcpNoDelay-boolean-

【讨论】:

  • 还可以尝试将您的字符串填充到 > 1500 字节。那将证明这一点。
【解决方案5】:

这是服务器问题,因为flush 总是强制写入。测试它尝试运行这段代码:

public static void main(String[] args) throws IOException, InterruptedException {
    Socket socket = new Socket("localhost", 8222);
    OutputStream out = socket.getOutputStream();
    for (int i = 0; i < 10; i++) {
        out.write((i + " : { \"phone\": \"23456789\" }").getBytes());
        out.flush();
        TimeUnit.SECONDS.sleep(1);
    }
}

之前,在 shell 上运行这个命令:

$ nc -l localhost 8222

在端口 8222 上侦听数据。您将看到每 1 秒的数据显示在 nc 输出上

【讨论】:

    【解决方案6】:

    问题不在于你没有正确刷新,而是读取代码在处理数据之前等待套接字断开:

    while((i = in.read()) &gt;= 0)

    只要可以从in(套接字的InputStream)读取内容,就会循环。在其他对等方断开连接之前,该条件不会失败。

    【讨论】:

      猜你喜欢
      • 2011-01-13
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2021-08-14
      • 2012-04-27
      • 2018-07-20
      相关资源
      最近更新 更多