当服务器处于繁忙循环时,客户端如何连接到服务器?

时间:2017-03-30 22:42:29

标签: java sockets

服务器如下所示:

public class Server {
public static void main(String[] args) {
    Server server = new Server();
    server.start(5006);
}

private void start(int port) {
    try(ServerSocket serverSocket = new ServerSocket(port);
        Socket clientSocket = serverSocket.accept();
        BufferedReader bufferedReader = new BufferedReader(new InputStreamReader(clientSocket.getInputStream(), "UTF-8"));) {
        String line;
        while (true) {
            while((line = bufferedReader.readLine())!=null){
                System.out.println("line = " + line);
            }
        }

    } catch (IOException e) {
        throw new RuntimeException(e);
    }
}

客户端看起来像这样:

public class Client {
public static void main(String[] args) {
    Client client = new Client();
    client.start("localhost", 5006);
}

private void start(String localhost, int port) {
    Random random = new Random();
    try (Socket socket = new Socket(localhost, port);
         BufferedWriter bufferedWriter = new BufferedWriter(new OutputStreamWriter(socket.getOutputStream(), "UTF-8"))) {
        while (true) {
            int i = random.nextInt();
            bufferedWriter.write(String.valueOf(i));
            bufferedWriter.newLine();
            System.out.println("i = " + i);

            //sleep(bufferedWriter);
        }
    } catch (Exception e) {
        e.printStackTrace();
    }
}

private void sleep(BufferedWriter bufferedWriter) throws Exception{
        //bufferedWriter.flush(); //Has to enabled if the wait below is to work
        TimeUnit.SECONDS.sleep(3);
}

上下文

从代码中可以看出,服务器是单线程的。它接受来自客户端的连接,并从客户端套接字进入忙循环处理数据。该服务器是故意残障的。

运行客户端程序的一个实例按预期工作。客户端结束随机整数,并在服务器控制台上打印相同的内容。

问题:

1)当客户端的一个实例仍在运行时,启动另一个客户端程序实例。

  • 当服务器仍然处于繁忙循环时,该客户端实例如何能够连接到服务器(while(true))? 客户端甚至填满缓冲的写入器然后挂起;等待服务器使用流。

2)在客户端程序中,取消注释“sleep”方法并重新运行。

  • 客户端程序挂起。服务器没有收到任何东西。为什么?我只想每3秒写一次缓冲区。荒谬但让我们假设为了论证这是理智的事情。我们在将新行发送到服务器之后也进入睡眠状态,以确保服务器打印其输入。

  • 如果在sleep方法中取消注释flush,它将再次开始工作。为什么?

2 个答案:

答案 0 :(得分:0)

  

当服务器仍处于忙碌循环("/some/file/path/funny_video.mov")时,该客户端实例如何能够连接到服务器?客户端甚至填满缓冲的写入器然后挂起;等待服务器使用流。

因为监听积压队列。操作系统完成入站连接并将其置于积压队列中。在积压队列为空时阻塞while(true),然后从中删除第一个连接。在调用相应的accept()之前,客户端的连接操作已完成,并且由于客户端现在有连接,因此它现在可以向其写入一定数量的数据。

  

2)在客户端程序中,取消注释“sleep”方法并重新运行。客户端程序挂起。

它睡了三秒钟。它不会“挂起”。由于输出速度慢得多,accept()的缓冲区需要更长的时间(很多)来填充和输出才能刷新到服务器。

  

服务器没有收到任何内容。为什么呢?

因为你还没有刷新缓冲区。

  

我只想每隔3秒写一次缓冲区。荒谬但让我们假设为了论证这是理智的事情。我们将新行发送到服务器之后也进入睡眠状态,以确保服务器打印输入。

     

如果在sleep方法中取消注释flush,它将再次开始工作。为什么呢?

见上文。

答案 1 :(得分:-1)

1)两个客户:

一个。客户1步骤:

  • (正如EJP所说),Connection在OS级别建立并置于积压队列中。 然后它正在等待ServerSocket选择它并开始从clientSocket InputStream

  • 读取
  • 客户端1将数据写入其socket OutputStream - 服务器的读取器从clientSocket InputStream读取数据 服务器很忙,因为无限循环。

B中。客户2步骤:

  • (正如EJP所说),Connection在操作系统级别建立并置于积压队列中。
  • 通过此代码,ServerSocket永远不会选择它。服务器无限期地忙于无限期打开Socket to Client 1.

  • 从客户端2写入的所有数据都保留在客户端2的缓冲区中。

注意:即使客户端1进程被终止并且从服务器到服务器的连接中断,客户端2也永远不会超过当前代码的那一点,服务器将结束。对客户端2的处理请求没有第二次accept()调用

2)flush

  • 当客户端将字节写入其socket OutputStream个字节时,首先不通过网络到达服务器。

  • flush强制OutputStream此时发送缓冲区中的任何内容。

  • 当缓冲区已满时,不会将flush数据发送到服务器。

  • 如果代码流中某处没有flush,服务器永远不会收到任何内容。它在当前代码中无限期地等待数据。但是所有数据都保留在客户端的缓冲区中,等待flush或缓冲区已满。

3)

  

客户端程序挂起。

假设不正确。客户端程序不会挂起。它正在运行并填充缓冲区,但在缓冲区已满之前没有任何内容发送到服务器。

无论有没有flush,都有sleep无关紧要。

“没有睡眠” - 缓冲区填充速度非常快。 “睡眠”缓冲区每3秒填充一次。它只需要一个时间来填充缓冲区。

  

如果在sleep方法中取消注释flush,它将再次开始工作。为什么呢?

只有服务器才开始提前接收数据,因为客户端在每次写入后都没有等待填充缓冲区来发送数据和刷新缓冲区。