0

C 语言 TCP 服务器/客户端 .. 我想为从 8080 请求我的服务器的特定客户端分配一个新套接字假设新套接字是 8081 以获得进一步的请求,并且想要释放以前的套接字(8080)以便其他客户端将从 8080 请求我的服务器。有没有办法用 C 语言来做。(操作系统 Ubuntu)谢谢

4

2 回答 2

0

您的问题陈述不正确。即使你想这样做,你也不能这样做。TCP 套接字的工作方式是,accept() 在您正在侦听的同一端口上为传入的客户端连接提供一个新套接字。这就是你所需要的,也是你所能得到的。如果不与他进行另一次 TCP 握手,您就不能在新端口上为客户端“分配新套接字”,当您已经与他建立连接时,这完全是浪费时间。这并不排除另一个连接在打开时被接受。您需要阅读 TCP Sockets 网络教程。

于 2013-09-08T18:33:55.407 回答
-1

Mat 和 EJP 已经说了上面的相关内容,但我认为这可能有助于其他人更详细地描述这种情况。

TCP/IP 连接由四元组标识:目标 IP 地址目标 TCP 端口号源 IP 地址源 TCP 端口号。内核将根据这四件事跟踪已建立的连接。单个服务器端口(和 IP 地址)可以同时连接到数千个客户端,实际上仅受可用资源的限制。

当你有一个监听 TCP 套接字时,它会绑定到某个 IP 地址(或通配符地址)和 TCP 端口。这样的套接字不接收数据,只接收新连接。当accept()被调用时,服务器记录连接的新四元组,并交出代表该连接的文件描述符(作为accept()返回值)。原来的套接字可以自由地接受新的连接。哎呀,如果你愿意,你甚至可以有多个线程接受新连接,尽管在 Linux 中建立新连接是如此之快,你不应该打扰;这太微不足道了。

如果在应用程序级别建立连接是资源密集型的——例如加密连接就是这样,同意加密方案和准备所需的数据结构通常比简单的 TCP 连接多几个数量级的 CPU 资源—— ,那么自然希望避免这种开销。让我们假设这是 OP 问题的重点:当最近的客户端需要另一个连接时,避免建立不必要的应用程序级连接。

首选的解决方案是连接多路复用。简而言之,应用层协议旨在允许通过单个 TCP 连接实现多个数据流。

OP 指出,有必要/最好保持现有应用程序协议的完整性,即优化应该完全在服务器端,对客户端透明。

这将推荐的解决方案转向了一个全新的方向。我们不应该谈论应用协议,而是如何有效地实现现有的协议。

在我们开始之前,让我们绕道而行。

从技术上讲,可以使用内核数据包过滤工具来修改传入数据包以使用基于源 IP 地址的不同端口,将来自特定 IP 地址的请求重定向到单独的端口,并使这些单独的端口无法访问。技术上可行,但实施起来相当复杂,而且好处也很可疑。

所以,让我们忽略 OP 假设的方向会带来预期的好处,并看看替代方案。或者,实际上,使用的常用方法。

在结构上,您的应用程序具有 - 一段接受新连接的代码 - 一段建立该连接所需的应用程序级资源的代码 - 一段与客户端进行通信的代码(根据客户端的要求)

这三个部分没有理由是连续的,甚至是同一代码流的一部分。使用数据结构对您有利。

与其将新的传入连接 ( accept()ed) 视为平等,不如将它们简单地根据其源 IP 地址放入单独的池中。(或者,如果你愿意的话,有一个将源 IP 地址聚集在一起的数据结构,否则会按照接收到的顺序保持它们。)

每当工作人员完成客户端的请求时,它都会检查同一客户端是否有新的传入连接。如果是,它可以通过检查新连接是否与旧连接的应用程序级参数匹配来避免大部分(如果不是全部)应用程序级连接的建立。(您会看到,即使源 IP 地址相同,也可能是完全不同的客户端,例如,如果客户端位于同一 VPN 或经过 NAT 的子网下。)

有很多问题需要处理,例如如何保持优先级,并避免在已知客户端试图占用服务时使新 IP 地址挨饿。

对于像 HTTP 这样的协议,一旦服务器接受连接,客户端就会发送请求信息,有一个更好的模式可以应用:使用请求池代替连接池。单个线程或线程池可以接收请求(在大多数协议中它们可能跨越多个数据包),而无需对其进行操作;仅检测请求本身何时完成。(细心的服务器会限制未决请求的数量和未完成请求的数量,以避免受到 DOS 攻击。)

当请求完成时,它们会被分组,以便为​​一个请求提供服务的同一个“工作人员”可以以最小的开销为另一个类似的请求提供服务。同样,需要仔细考虑以避免多产的客户端通过发送大量请求来占用服务器资源的情况,但是仔细考虑和测试将无法解决。

还有一个问题:

你需要这样做吗?

我敢打赌你不会。Apache 是最好的 HTTP 服务器之一,它不执行上述任何操作。性能优势被认为不值得额外的代码复杂性。您能否编写一个新的 HTTP 服务器(或您正在使用的任何协议的服务器),并使用与上述类似的方案,以确保您可以尽可能高效地使用您的硬件?当然。你甚至不需要成为一个巫师,只需做一些研究和仔细计划,避免陷入细节,时刻牢记大局。

我坚信代码的可维护性和安全性比效率更重要,尤其是在编写初始实现时。迄今为止,从第一次实施中获得的信息总是改变了我对实际“问题”的看法;类似于打开新的眼睛。为第一代创建一个健壮、易于开发和维护,但不一定非常高效的实现总是值得的。如果有人愿意支持下一代的开发,那么您不仅可以比较(验证和调试)第一代实现,还可以获得所有的实践知识。

这也是老手经常警告不要过早优化的原因。简而言之,您最终会优化资源浪费和个人痛苦,而不是您正在开发的实现。

如果可以的话,我会建议 OP 备份几个步骤,并实际描述他们打算实施什么,观察到的实施问题是什么,以及如何解决和避免问题的建议。当前的问题就像问如何更好地冷冻香蕉,因为当你用它锤钉子时它会不断碎裂。

于 2013-09-09T07:47:29.123 回答