Java套接字:两个换行比一个换行快

Java套接字:两个换行比一个换行快,java,networking,Java,Networking,我有一个简单的客户机-服务器应用程序。服务器使用Java,客户端使用Python3。服务器等待单个客户机,然后通过以下方式与它通信。服务器从客户端读取一行,然后将消息“yyyy”发回。因此,从客户端来看,对话可能是这样的: xxxx > yyyy xxxx > yyyy xxxx > yyyy ... 我遇到的问题是通信的速度。我测量了服务器读取客户机请求所需的时间,大约为40毫秒。然而,最令人惊讶的是,如果客户端在其每条消息中附加一个换行符“\n”,则持续时间将下降到~0毫

我有一个简单的客户机-服务器应用程序。服务器使用Java,客户端使用Python3。服务器等待单个客户机,然后通过以下方式与它通信。服务器从客户端读取一行,然后将消息“yyyy”发回。因此,从客户端来看,对话可能是这样的:

xxxx
> yyyy
xxxx
> yyyy
xxxx
> yyyy
...
我遇到的问题是通信的速度。我测量了服务器读取客户机请求所需的时间,大约为40毫秒。然而,最令人惊讶的是,如果客户端在其每条消息中附加一个换行符“\n”,则持续时间将下降到~0毫秒。这可能是什么原因造成的,我如何修复它,使我不必在每个客户的请求中包含人工换行符

为了完整性,我还提供了服务器端和客户端代码

服务器端:

import java.io.*;
import java.net.*;
import java.time.*;
import java.util.*;

class Server {
  public static void main (String[] args) {
    Clock clock = Clock.systemDefaultZone();
    try {
      ServerSocket server = new ServerSocket();
      server.bind(new InetSocketAddress("127.0.0.1", 4248));
      Socket client = server.accept();

      Scanner sc = new Scanner(client.getInputStream());
      PrintStream ps = new PrintStream(client.getOutputStream());

      while (true) {
        Instant start = clock.instant();
        String msg = sc.nextLine();
        Instant end = clock.instant();
        System.err.format("Took me %d ms to receive the message\n", Duration.between(start, end).getNano() / 1000000);
        ps.println("yyyy");
      }
    }
    catch (IOException exc) {}
  }
}
客户端:

import socket, sys

sock = socket.create_connection(("127.0.0.1", 4248))
fin = sock.makefile('r')
fout = sock.makefile('w')

while True:
  print("xxxx", file = fout, flush = True)
  msg = fin.readline().rstrip('\n');
  print(msg, file = sys.stderr)
我们通过将“xxxx”替换为“xxxx”来获得“fast”客户端\n。请注意,Python3会在每条消息后自动打印一个换行符,因此前者实际上是“xxxx\n”,后者是“xxxx\n\n”

我测量服务器读取客户机请求所需的时间

不仅如此,您还可以测量(至少部分地)客户机发送请求之前的时间

只是猜测 Python客户端是瓶颈,无法跟上Java服务器。服务器的
nextLine()
总是等待客户端打印内容。
当您将
print(“xxxx”)
更改为
print(“xxxx\n”)
时,一次打印两行,这将使客户端的行输出速率加倍。现在情况正好相反:客户端发送消息的速度比服务器处理消息的速度快,客户端的
readline()
必须等待服务器。
请注意,在后一种情况下,消息在
“xxxx”
之间交替出现。那可能不是你想要的。但是,您可以使用
打印(“xxxx\nxxx”)


您可以通过编写一个使用
println(“xxxx”)
的Java客户机来测试这一理论。假设Java客户端比python客户端快,我希望测量的时间小于40ms,但可能略大于0ms。

您确定每次更改都会得到0ms吗?我期望在40ms和0ms之间交替:40ms,0ms,40ms,0ms,40ms,0ms…是的,这就是为什么它如此令人惊讶。就好像套接字在快速交替输入和输出方面存在问题,但如果比率为1:2,则不会有太大问题……有趣的是,我在这里测试了它,但在windows机器上使用了python 2(这就是我安装的)和java 8。我在xxxx和xxxx之间没有区别\n-始终0-1msI可以在旧的linux笔记本电脑上用Java 8和Python 3复制OP的发现。当我在客户机中将
打印(“xxxx”,…)
放在
之前,而在客户机中为True
时,测量的时间以以下模式重复:40,0,0,40,0。。。循环之前有两个
打印
,模式变为40,0,0,0,40,0,0,0,…我刚刚测试了这一点(使用Java 8客户端和服务器)。使用一条换行符,速度正好慢两倍(80ms)。有了两条换行符,仍然是0毫秒的超高速。问题是,即使客户端比服务器慢,它也无法解释为什么处理“xxxx”然后“xxxx”比只处理“xxxx”要快。那么我一定猜错了。为了澄清一个可能的误解:
为什么处理“xxxx”然后“xxxx”比处理“xxxx”要快
。我没有谈论在服务器上处理某些内容所需的时间,而是讨论服务器等待输入的时间,即客户端发送某些内容所需的时间。使用
打印(“xxxx\n”)
每个循环迭代发送两行;使用
print(“xxxx”)
时,只发送一行,但两个呼叫应占用大约相同的时间。同样使用
xxxx\n
服务器的下一个输入
在服务器发送回复之前就已经存在了。