6

我对插座感到困惑。据我所知,套接字是 ip 地址和端口号的组合。它只是编程抽象,允许写入或读取流(在 TCP 的情况下)。现在我不确定的是,服务器在为客户端提供服务时是否有一个或多个套接字?假设http在 80 端口。

来自各个客户端的所有数据是否都发送到一个套接字(服务器:80),并且某些 UBER 服务器进程根据传入地址区分它们,还是根据 TCP 层创建的客户端地址和端口号的组合来区分它们?有人可以用分步算法(同时为多个客户端服务)彻底描述这一点,而不仅仅是服务器将套接字绑定到端口,服务器侦听套接字,服务器提供数据。

4

3 回答 3

8

您将 TCP 连接与套接字混淆了。套接字不是网络级别的概念。是一个操作系统概念。TCP 连接作为 (source-ip, source-port, dest-ip, dest-port) 的唯一组合存在于网络上。套接字是打开端口打开连接的句柄(此语句略微简化)。当我开始时,我还认为这很令人困惑,并且是一个操作系统设计错误(但它就是这样,我们被困住了)。设计错误是每个不同套接字的允许操作非常不同。这些用例应该是两个独立的概念,具有不同的名称和不同的 API。

如您所见,套接字和连接之间没有 1:1 的关系。

有人可以用逐步算法彻底描述这个吗

服务器打开一个套接字让操作系统知道它想要监听或连接。然后,每个接受的连接都会产生一个新的、独立的套接字。但是,每个新连接都在相同的服务器 IP 和服务器端口上。只是客户端 IP 和/或客户端端口不同。服务器读取和写入每个连接的套接字。开放端口套接字仅用于接受新连接。

服务器在概念上是这样的:

var openPortSocket = Open(80); //HTTP port
while(true) {
 var connectionSocket = openPortSocket.Accept();
 ServeConnectionOnNewThread(connectionSocket);
}

这是一个逻辑模型。实际的 API 调用是不同的。例如,大多数服务器使用异步 IO。不过,这与您的问题无关。

客户端必须为每个连接使用不同的客户端端口。这正是您的浏览器所做的。

于 2013-09-03T13:49:34.090 回答
0

通常,在服务器端,在创建套接字并绑定到特定的端口/地址组合后,将调用一个被调用Listen(或类似)的函数。这使得这个绑定的套接字成为一个监听套接字——它只是在等待连接尝试开始。

在此之后,将调用一个类似于Accept侦听套接字的函数。此调用将从侦听套接字获取挂起的连接请求,创建一个套接字并返回它。

在连接期间,客户端和服务器之间的所有进一步通信都将通过这个新的套接字(在服务器端)。

如果服务器需要同时处理多个客户端连接,则可以使用不同的技术来实现可伸缩性。一种简单的技术(不能扩展到数千个连接的客户端)是产生一个新的线程/进程(取决于你的操作系统上的便宜)来处理这个连接,然后原始线程/进程返回到调用Accept.

其他技术可能涉及将套接字放置在某种形式的池中,或者能够让套接字生成由固定数量的线程处理的事件,当每个套接字需要注意时。

于 2013-09-03T13:30:05.670 回答
0

尽管我相信大多数操作系统/内核的运行方式相似,但我主要可以与 Linux 交谈。简短的回答是内核完成了大部分工作。

内核与某种网络接口进行通信,基本上只是将信号从线路传输到内核,反之亦然。套接字和地址仅仅是给定连接的描述符。内核跟踪哪些内部进程与哪些套接字/地址对相关,并将相应地引导数据。通常,这是作为 FIFO 实现的——先进先出。这适用于传入和传出数据。

如果服务器连接到多个客户端,通常应用程序负责向每个连接的客户端发送单独的数据包,这意味着应用程序必须跟踪活动客户端的数量。一些内核和/或 NIC 可以为您完成其中的一些工作。如果这是一个本地网络,并且您想向连接到网络的每个客户端发送数据包,则可以发送广播数据包,该数据包只需发送一次,但每个连接都会收到。

如果您想了解更多信息,此链接非常详尽:

端口和套接字有什么区别?

于 2013-09-03T13:50:57.833 回答