Java服务器套接字通信非常慢

Java服务器套接字通信非常慢,java,python,sockets,Java,Python,Sockets,Linux上的本地。一条20k的信息大约需要10秒。我猜我的Java不好,Python很好 py客户端: def scan(self, msg): try: print 'begin scan' HOST = 'localhost' PORT = 33000 s = socket.socket(socket.AF_INET, socket.SOCK_STREAM) s.connect((HOST, PORT)

Linux上的本地。一条20k的信息大约需要10秒。我猜我的Java不好,Python很好

py客户端:

def scan(self, msg):
    try:
        print 'begin scan'
        HOST = 'localhost'
        PORT = 33000
        s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
        s.connect((HOST, PORT));
        s.sendall(msg)
        data = s.recv(1024)
        s.close()
        print 'Received', repr(data)
    except Exception, e:
        print "error: " + str(e)
Java服务器:

    ServerSocket service = new ServerSocket(33000); 

    while(true) {

    debug("Begin waiting for connection");

    //this spins
    Socket connection = service.accept();

    debug("Connection received from " + connection.getInetAddress().getHostName());

    OutputStreamWriter out = new OutputStreamWriter(connection.getOutputStream());
    BufferedInputStream in = new BufferedInputStream(connection.getInputStream());


    ScanResultsHeader results = new ScanResultsHeader();

        Scanner scanner = new Scanner();
        results = scanner.scan("scannerfake@gmail.com", "123", in);

public ScanResultsHeader扫描字符串userEmail, 字符串无效, BufferedInputStream mimeEmail 抛出IOException、FileNotFoundException、MimeException、ScannerException{

    //how fast would it be to just slurp up stream?
    debug("slurp!");
    String slurp = IOUtils.toString(mimeEmail);
    debug("slurped " + slurp.length() + " characters");
    slurp = slurp.toLowerCase();
    debug("lc'ed it");
    //...
我猜我把输入流处理错了。一个问题是BufferedInputStream mimeEmail签名是库API扫描所使用的必需的,所以我最终需要使用该格式。但是我注意到,简单地将字符串拼凑起来需要花费相当长的时间,所以我已经做了一些不正确的事情。

修改我的答案。。。

如果你的阅读效率很高,而且看起来你是,那只会花很多时间,因为

每次发送消息时,您都在创建一个新的连接,这可能非常昂贵。 你发送数据的速度没有你想象的那么快。 这一信息不太可能,但也有可能 关于如何做到这一点,有很多例子,您可以使用的一个好库是IOUtils,它使它更简单

在Java中,您应该能够通过单个套接字发送大约200K/s的消息

如果你有一个使用Big-Endian发送X字节的协议,你可以这样做

DataInputStream dis = new DataInputStream( ...
int len = dis.readInt();
byte[] bytes = new byte[len];
dis.readFully(bytes);
String text = new String(bytes, "UTF-8");

最初的问题是,客户端没有发送输入的结尾,因此slurp操作一直在等待更多的东西通过连接


解决方案是实现一个应用层协议,预先发送消息的大小,然后在这么多字节后停止侦听更多消息。我更喜欢一个标准库,比如FiniteInputStream扩展BufferedInputStream并将大小作为参数,但我自己编写。

代码示例使用IOUtils已经存在;事实上,对IOUtils方法的调用似乎花费了最长的时间。我确认如果我在端口上安装C服务器而不是Java服务器,它的速度会非常快,包括slurp步骤,当然在C中,slurp步骤只意味着写入字符[]缓冲区。问题肯定是Java,可能在我的代码中,或者理论上是这样,但在IOUtils调用中不太可能。hmmm很有趣。我知道Java肯定可以在10秒内处理10k。我在10秒内处理了几百k条消息。可能你想在你认为需要花费很长时间的步骤上做时间日志记录吗?在一台高速PC上,我没有单个线程中每秒350K条小消息。这是一个持久连接。使用异步消息,我每秒收到的消息超过一百万条。典型的往返延迟约为10微秒。为了更快,我通过内存映射文件使用共享内存。这支持每秒500-2000万条消息根据大小和复杂度,往返延迟为100-300纳秒,例如128字节比16字节慢。我的观点是:Java并不慢,但我看不出你做错了什么。我认为我的问题是,在slurp尝试完成时,连接仍然打开。服务器正在等待输入结束,直到客户机厌倦了等待并关闭了连接。因此,这是一个很好的情况,在这种情况下,完全错误的操作会慢慢显现出来。要重新编程客户机/服务器以使用I'm sending X bytes协议。如果有人知道BufferedInputStream的Java子类可以做到这一点,我将不胜感激,因为现在我正在编写自己的假装输入在X字节后结束的ubclass。也许在客户端和服务器上进行一些性能记录可以帮助您确定这两个服务器中的哪一个真的减慢了速度。根据我对下面答案的评论,我换了一台C服务器,并确认它的速度非常快。客户端很好,连接很好,它无法有效地插入I使用我提供的流进行OUtils。将大小作为什么的参数?BufferedInputStream在构造函数中有一个大小参数,DataInputStream.readFully接受隐式或显式大小参数。