我对插座感到困惑。据我所知,socket是ip地址和端口号的组合。它只是编程抽象,允许写入或从流中读取(在TCP的情况下)。现在我不能完全确定服务器在服务客户端时是否有一个或多个套接字?让我们在80号港口说http
。
来自不同客户端的所有数据是否都被发送到一个套接字(服务器:80),并且某些UBER服务器进程根据传入地址区分它们,或者是基于TCP层创建的客户端地址和端口号组合的更多套接字?有人可以通过逐步算法(对于同时服务的多个客户端)彻底描述这一点,而不仅仅是服务器绑定套接字到端口,服务器侦听套接字,服务器服务数据。
答案 0 :(得分:8)
您将TCP连接与套接字混淆。套接字不是网络级概念。是操作系统的概念。 TCP连接作为(source-ip,source-port,dest-ip,dest-port)的唯一组合存在于网络上。套接字是打开端口或打开连接的句柄(此语句略有简化)。当我开始时,我也认为这是令人困惑的和OS设计错误(但它是什么,我们坚持它)。设计错误是每个不同套接字的允许操作非常不同。这些用例应该是两个具有不同名称和不同API的独立概念。
正如您所看到的,套接字和连接之间没有1:1的关系。
有人可以通过逐步算法彻底描述这一点
服务器打开一个套接字,让操作系统知道它想要监听或连接。然后,每个接受的连接都将生成一个新的独立套接字。每个新连接都在同一个服务器-ip和服务器端口上。只是客户端IP和/或客户端端口是不同的。服务器在每个连接套接字上进行读写。开放式端口套接字仅用于接受新连接。
服务器在概念上是这样的:
var openPortSocket = Open(80); //HTTP port
while(true) {
var connectionSocket = openPortSocket.Accept();
ServeConnectionOnNewThread(connectionSocket);
}
这是一个逻辑模型。实际的API调用是不同的。例如,大多数服务器使用异步IO。这与你的问题无关。
客户端必须为每个连接使用不同的客户端端口。这正是您的浏览器所做的。
答案 1 :(得分:0)
通常,在服务器端,在创建套接字并绑定到特定端口/地址组合之后,将调用名为Listen
(或类似)的函数。这使得这个绑定套接字成为一个监听套接字 - 它只是等待连接尝试启动。
在此之后,将在侦听套接字上调用一个名为Accept
的函数。此调用将从侦听套接字接收挂起的连接请求,创建 new 套接字并返回该插槽。
在连接期间,客户端和服务器之间的所有进一步通信都将通过这个新套接字(在服务器端)。
如果服务器需要同时处理多个客户端连接,则可以使用不同的技术来实现可伸缩性。一个简单的技术(不扩展到数千个连接的客户端)是产生一个新的线程/进程(取决于你的O / S上的便宜)来传递这个连接,然后是原始线程/ process返回调用Accept
。
其他技术可能涉及将套接字放置在某种形式的池中,或者能够使套接字生成由固定数量的线程处理的事件,以及每个套接字需要注意时。
答案 2 :(得分:0)
我可以主要谈论Linux,但我相信大多数操作系统/内核的运行方式类似。简短的回答是内核完成了大部分工作。
内核与某种网络接口通信,基本上只是将信号从线路转换到内核,反之亦然。套接字和地址只是给定连接的描述符。内核跟踪哪些内部进程与哪个套接字/地址对相关,并相应地引导数据。通常,这是作为FIFO实现的 - 先进先出。传入和传出数据都是如此。
如果服务器连接到多个客户端,通常应用程序有责任向每个连接的客户端发送单独的数据包,这意味着应用程序必须跟踪活动客户端的数量。某些内核和/或NIC可以为您执行此操作。如果这是本地网络,并且您希望将数据包发送到连接到网络的每个客户端,则可以发送广播数据包,只需发送一次,但每次连接都会收到。
如果您需要更多信息,此链接非常彻底: