保持来自自制 Java 服务器的持久连接
Posted
技术标签:
【中文标题】保持来自自制 Java 服务器的持久连接【英文标题】:Keeping persistent connections from a home-made Java server 【发布时间】:2011-11-09 14:48:06 【问题描述】:我已经构建了一个简单的 Java 程序,可以作为本地服务器。
目前它做了一些事情,例如预览目录,如果目录包含它,则转发到 index.html,发送 Last-Modified
标头并正确响应客户端的 If-Modifed-Since
请求。
我现在需要做的是让我的程序接受持久连接。目前它是线程化的,因此每个连接都有自己的线程。我想将我的整个线程代码放在一个循环中,该循环一直持续到Connection: close
或指定的超时。
有人知道从哪里开始吗?
编辑:这是一个大学项目,必须在不使用框架的情况下完成。
我有一个 main 方法,它无限循环,每次循环它都会创建一个 Socket 对象,然后创建一个 HTTPThread
对象(我自己创建的一个类) - 处理单个请求。
我希望使用Connection: keep-alive
请求标头允许多个请求在单个连接中工作。我希望在我的 HTTPThread
类中使用循环,我只是不确定如何传递多个请求。
提前致谢:)
【问题讨论】:
您能否再次解释一下您所说的“持久连接”是什么意思?如果会话暂时断开,您是否可能要保存会话状态以便恢复它? 我的问题是我不完全明白我需要做什么!目前我有一个循环调用一个名为 HTTPThread 的类。它传递一个 inputStream 和一个 outputStream。然后 HTTPThread 类相应地解析请求。如果连接状态是保持活动状态,我想以某种方式将我已经拥有的连接用于下一个请求.. 【参考方案1】:我假设您从 Socket API 开始自己实现 HTTP 协议代码。并且您正在实现 HTTP 规范的持久连接部分。
您可以按照您的建议将代码放入循环中,并使用 Socket.setSoTimeout 设置阻塞操作的超时,从而设置您的 HTTP 超时。你不需要做任何事情来重用你的连接流......除了不关闭它们。
我要指出,实现 Web 服务器的方法要简单得多。现有许多 Java Web 服务器框架和应用程序服务器,或者您可以重新利用 Apache HTTP 协议栈。
【讨论】:
我目前有一个循环,它为每个请求声明一个套接字。一个 HTTPThread 对象(我所有的代码都在其中),接受一个输入流和一个输出流,并在那里处理单个请求。如何从 HTTPThread 类内部执行多个请求 - 单个连接? soTimeout 与持久连接有什么关系? 如此处所述,en.wikipedia.org/wiki/HTTP_persistent_connection,除非标头中另有说明,否则 HTTP 1.1 始终使用持久连接。 Apache 2.2 在空闲 5 秒后关闭套接字。因此,您不必关闭套接字,还必须设置一些计时器以在空闲时间过长时将其关闭。一种方法是拥有一个专门的管理线程来处理这个(可能还有其他)任务。 不幸的是,这是一个大学项目 - 它必须使用基本的简单 java 来完成 - 不幸的是,没有人知道如何开始实施它!【参考方案2】:如果它应该像 Web 服务一样工作:从客户端打开 2 个套接字,一个用于请求,一个用于 回应。保持套接字和流打开。
你需要定义一个分隔符来通知对方一个 转移结束。二进制的特殊位串,特殊的 基于文本的协议(如 XML)的字符(通常是换行符)。
如果您真的尝试实现自己的 http-server,您应该使用已经实现 HTTP 1.1 连接保持连接标准的library。【讨论】:
它的作业我怀疑正确的解决方案是使用已经这样做的库。 我明白了,那你当然应该自己实现。 ;) Java Socket API 提供了一种设置 SO_KEEPALIVE 的方法:download.oracle.com/javase/6/docs/api/java/net/… 我认为在套接字上保持活动与 HTTP 1.1 持久连接不同。 http长连接是更高层次的抽象,但是如果你自己实现整个东西,你需要利用这些socket方法。 这是为什么呢? socket keep-alive 是通知死亡的对等点,并在没有流量时保持连接活动(通过发送带有 ACK 的零长度数据包)。 HTTP 持久连接会在短时间内保持套接字打开以提高性能,因为每个客户端都可能在短时间内发出多个请求。除了名字相似之外,我看不出它们有什么关系。【参考方案3】:一些帮助您入门的想法:
这篇***文章描述了 HTTP 1.1 持久连接:
http://en.wikipedia.org/wiki/HTTP_persistent_connection
您不想关闭套接字,但是在一些非活动时间段(apache 2.2 使用 5 秒)之后您想关闭它。
你有两种实现方式:
在你的线程中不要关闭套接字,也不要退出线程,而是在套接字上设置一个读取超时(无论你想支持什么)。当您调用 read 时,它将阻塞,如果超时到期,则关闭套接字,否则您读取下一个请求。这样做的缺点是,无论您的最大等待时间是多少,每个持久连接都同时拥有一个线程和一个套接字。这意味着您的解决方案无法扩展,因为您持有线程的时间过长(但对于学校项目而言可能没问题)!
您可以通过维护元组列表 socket,timestamp、后台线程监视器和关闭超时连接以及使用 NIO 检测现有的新读取来绕过 (1) 的限制打开插座。因此,在您完成读取初始请求后,您只需退出线程(将其返回到线程池)。显然这要复杂得多,但它有释放请求线程的好处。
【讨论】:
请原谅我的无知,但是您如何阅读下一个请求.. 我认为这就是我真正陷入困境的地方。另外,我在任何时候都没有调用方法来关闭套接字,我关闭了输入和输出流,这会做同样的事情吗? 您对哪种情况感兴趣?在第一种情况下,您对输入流进行读取,它会阻塞,直到客户端发送另一个请求,或者发生超时,或者客户端强行关闭连接。在第二种情况下,您对非阻塞 IO api 执行相同的操作,这意味着读取会立即返回,但是当流上有新数据可用时,您会从在不同线程中运行的某个选择循环中找到。跨度> 如果你关闭套接字,它也会关闭输入和输出流。以上是关于保持来自自制 Java 服务器的持久连接的主要内容,如果未能解决你的问题,请参考以下文章