Java 中的套接字最佳实践

Posted

技术标签:

【中文标题】Java 中的套接字最佳实践【英文标题】:Socket best practices in Java 【发布时间】:2015-08-11 23:00:49 【问题描述】:

用 Java 编写任何类型的 Web 服务器(无论是 Web 服务器、RESTful Web 应用程序还是微服务),您都可以使用 Sockets 在客户端和服务器之间进行双通道通信。 使用常见的SocketServerSocket 类是微不足道的,但由于套接字是阻塞的,您最终会为每个请求创建一个线程。使用这个线程系统,您的服务器将完美地工作,但不会很好地扩展。 另一种方法是通过SocketChannelServerSocketChannelSelector 使用Streams,显然不像普通的Sockets 那样简单。

我的问题是:这两个系统中的哪一个用于生产就绪代码?我说的是 Tomcat、Jetty、Sparkjava 之类的大中型项目? 我想他们都使用 Stream 方法,对吧?

【问题讨论】:

websockets 怎么样? @duffy356 你是什么意思?没有 NIO 就无法实现 Websockets,但是如果你认为有某种特殊的“WebSocket”而不是“ServerSocket”类,那你就错了。 感谢您提供此信息。 【参考方案1】:

要使 Web 服务器真正具有可扩展性,您必须使用 non-blocking I/O 来实现它 - 这意味着您应该以这样一种方式实现它,即线程永远不会在等待 I/O 操作完成时被阻塞。

线程是相对昂贵的对象。例如,对于每个线程,需要为其调用堆栈分配内存。默认情况下,这是大约 1 MB 或几 MB。这意味着,如果您创建 1000 个线程,那么仅所有这些线程的调用堆栈就已经花费了您大约 1 GB 的内存。

在一个简单的服务器应用程序中,您可能会为每个接受的连接(每个客户端)创建一个线程。如果您有许多并发用户,这将无法很好地扩展。

我不知道 Tomcat 和 Jetty 等服务器的实现细节,但它们很可能是使用非阻塞 I/O 实现的。

关于 Tomcat 中非阻塞 I/O 的一些信息:Understanding the Tomcat NIO Connector

Java 中最著名的非阻塞 I/O 库之一是 Netty。

【讨论】:

即使使用阻塞 IO,生产服务器也会使用阻塞在套接字上的单个线程。当该线程醒来接受连接时,它会将其传递给池中的线程,然后返回阻塞状态。这是 Tomcat BIO 连接器。 @BoristheSpider-您的意思是 Tomcat 在其基于 BIO 的生产系统中使用阻塞 I/O?那么,为什么要使用两种不同的方法 -> 用于生产服务器的 Tomcat BIO 和 Tomcat NIO!我有点困惑..请简要解释一下。 @BoristheSpider 在 Leader-Follower 模型(非阻塞)中,Leader-thread 等待所有连接,读取接收到的请求并立即处理它。另一个空闲的 Follower-Thread 成为新的 Leader,而旧的 Leader 仍在处理中。避免切换到另一个线程。 最有效的方法可能是非阻塞以及真正的异步回调。处理连接/回调的线程数量与内核数量完全相同。如果必须执行任何阻塞文件 IO 或远程调用,则这些将由接收响应的异步回调来完成。即使使用像akka这样的框架,线程也很少,但编程也很混乱。 Tomcat NIO 连接器文章的链接已失效。我想编辑答案,但“建议的编辑队列已满”。现在可以在此处找到 Tomcat 文章:dzone.com/articles/understanding-tomcat-nio

以上是关于Java 中的套接字最佳实践的主要内容,如果未能解决你的问题,请参考以下文章

Sails.js 套接字 - 最佳实践 4/2014

服务之间异步通信的最佳实践

Java中的构造函数重载 - 最佳实践

制作容器镜像的最佳实践

构造函数重载 - Java 中的最佳实践 [关闭]

Android上持久移动连接的最佳实践?