Java 中的套接字最佳实践
Posted
技术标签:
【中文标题】Java 中的套接字最佳实践【英文标题】:Socket best practices in Java 【发布时间】:2015-08-11 23:00:49 【问题描述】:用 Java 编写任何类型的 Web 服务器(无论是 Web 服务器、RESTful Web 应用程序还是微服务),您都可以使用 Sockets 在客户端和服务器之间进行双通道通信。
使用常见的Socket
和ServerSocket
类是微不足道的,但由于套接字是阻塞的,您最终会为每个请求创建一个线程。使用这个线程系统,您的服务器将完美地工作,但不会很好地扩展。
另一种方法是通过SocketChannel
、ServerSocketChannel
和Selector
使用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 中的套接字最佳实践的主要内容,如果未能解决你的问题,请参考以下文章