【问题标题】:How can data be received by a socket from a server before server flushes the data?在服务器刷新数据之前,套接字如何从服务器接收数据?
【发布时间】:2014-06-28 16:04:15
【问题描述】:

所以这是我的代码:

public class TestClass {
    public static void main(String[] args) throws IOException, InterruptedException {
        Thread server = new Thread(new MyServer());
        server.start();
        Thread.sleep(750);
        Thread client = new Thread(new MyClient());
        client.start();
    }
}

服务器:

public class MyServer implements Runnable{

    public static synchronized void go() throws IOException {

        System.out.println("MyServer: Go called...");
        ServerSocket serverSocket = new ServerSocket(5000);
        while(true){
            Socket socket = serverSocket.accept();
            System.out.println(time() + "MyServer: Connection accepted!");
            OutputStream outputStream = socket.getOutputStream();
            System.out.println(time() + "MyServer: socket.getOutputStream");
            PrintWriter printWriter = new PrintWriter(outputStream);
            System.out.println(time() + "MyServer: New PrintWriter object created!");
            printWriter.write("Hello from my socket!");
            System.out.println(time() + "MyServer: printwriter.write method called..");
            printWriter.flush();
            System.out.println(time() + "MyServer: Flushed!");
            printWriter.close();
            System.out.println(time() + "MyServer: printWriter closed...");
        }
    }

    public static String time(){
        return String.valueOf(MyCounterClass.getCounter()) + " ";
    }

    @Override
    public void run() {
        try {
            go();
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
}

客户:

public class MyClient implements Runnable {

    public static synchronized void go() throws IOException {
        Socket socket = new Socket("localhost",5000);
        System.out.println(time() + "My Client: Connection established...");
        InputStream inputStream = socket.getInputStream();
        System.out.println(time() + "MyClient: socket.getInputStream...");
        BufferedReader bufferedReader = new BufferedReader(new InputStreamReader(inputStream));
        System.out.println(time() + "MyClient: BufferedReader object created...");
        System.out.println(time() + "Bufferedreader readline being called and directly printer: " + bufferedReader.readLine());
        System.out.println(time() + "bufferedReader.readline has just been called...");
    }

    public static String time(){
        return String.valueOf(MyCounterClass.getCounter()) + " ";
    }

    @Override
    public void run() {
        try {
            go();
        } catch (IOException e) {
            e.printStackTrace();
        }
    }

}

还有 Counter 类:

public class MyCounterClass {
    private static volatile int counter = 0;
    synchronized public static int getCounter(){
        return counter++;
    }
}

输出将是:

0 My Client: Connection established...
1 MyServer: Connection accepted!
2 MyClient: socket.getInputStream...
3 MyClient: BufferedReader object created...
4 MyServer: socket.getOutputStream
6 MyServer: New PrintWriter object created!
7 MyServer: printwriter.write method called..
8 MyServer: Flushed!
9 MyServer: printWriter closed...
5 Bufferedreader readline being called and directly printer: Hello from my socket!
10 bufferedReader.readline has just been called...

订购时:

0 My Client: Connection established...
1 MyServer: Connection accepted!
2 MyClient: socket.getInputStream...
3 MyClient: BufferedReader object created...
4 MyServer: socket.getOutputStream
5 Bufferedreader readline being called and directly printer: Hello from my socket!
6 MyServer: New PrintWriter object created!
7 MyServer: printwriter.write method called..
8 MyServer: Flushed!
9 MyServer: printWriter closed...
10 bufferedReader.readline has just been called...

所以我觉得奇怪的是第 5 行在 6,7,8 之前...这怎么可能?

【问题讨论】:

标签: java multithreading sockets synchronization


【解决方案1】:

这里发生了很多事情

System.out.println(time() + "Bufferedreader readline being called and directly printer: " + bufferedReader.readLine());

首先调用time() 以获取值。假设它返回 5。该值存储在堆栈中。然后readLine() 被调用并阻塞,直到它收到一些东西。一旦完成,它将连接堆栈中的5String"Bufferedreader read..." 和从readLine 返回的String

所以即使flush()(并写入流)稍后出现,time() 的值已经被检索到。

您需要围绕整个 String 连接操作进行同步。

【讨论】:

  • 当我将其更改为 ...readLine() + time 时,一切都很酷,所以非常感谢。
【解决方案2】:

flush 将以编程方式清空并发送剩余的缓冲区内容,但这并不意味着在通过套接字传输期间缓冲区完全填满时不会执行其他自动刷新。

也就是说,必须使用flush 来确保在完成传输后发送缓冲区中的最后剩余数据。但是,同时可能发生了多次填充-发送-刷新的迭代。

在此图中,您在 go 方法中执行的显式 flush 负责发送红色字节。

在调用 flush 之前,您的缓冲区可能永远不会被填满,在这种情况下,在调用完成之前不会向客户端发送字节:

编辑虽然这个答案中的公开是正确的,但它并不是对您遇到的问题的完整解释,Sotirios 的答案增加了对您代码的其他问题的更多洞察。无论如何不要忘记,go 末尾的刷新并不意味着此时发送了完整的块,m * sizeof(buffer) 可能在此之前已经发送了。

【讨论】:

  • 我不明白这与问题有什么关系。 6、7、8 之前的 5 是如何发生的?你的回答如何解释这一点?
  • @SotiriosDelimanolis “在服务器刷新数据之前,套接字如何从服务器接收数据”虽然我的回答并没有解决它解决了为什么 5 可能在 8 之前发生的所有情况。
  • 要发生 8,必须发生 6 和 7。在服务器创建发送数据的对象之前,客户端无法接收到数据。这里的问题是日志记录具有误导性。
  • @SotiriosDelimanolis 这次你来了。不过我会保留答案,因为确实没有调用 flush 并不意味着某些数据尚未发送。
猜你喜欢
  • 1970-01-01
  • 2020-09-17
  • 2019-06-02
  • 2017-07-17
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多