一般编程:在服务器套接字中,accept()方法究竟发生了什么.在低级别,服务器套接字与客户端套接字的不同之处是什么?
在低级别,套接字只是套接字,无论它们是在服务器还是客户端应用程序中使用.两者的区别在于系统调用各种应用程序所做的.
服务器套接字将调用bind()
与端口关联.他们希望与端口关联,以便其他程序知道到达哪个端口.客户端套接字可以调用,bind()
但几乎从不这样做,因为没有太多意义.如果套接字没有调用bind()
操作系统,只需为它选择一个短暂的端口,这对客户端来说很好,因为它们正在进行调用; 没有人需要打电话给他们.
服务器套接字调用listen()
.这在其他答案中得到了很好的解释.
服务器套接字调用accept()
,我认为这是你的问题的关键,因为它起初有点神秘.要掌握的重要一点是,在调用accept()
内核时会传回一个新的套接字.它现在与原始侦听套接字分开,是您的服务器用于与其对等方通信的内容.
理解tcp连接依赖于(1)本地地址(2)本地端口(3)外部地址(4)的4元组时,理解侦听套接字如何继续监听的关键在于理解tcp连接外国港口.这些定义了唯一的连接.在accept()
传回新套接字之前,内核使用这些值来创建各种结构,以便与tcp/ip堆栈协作,具有此元组的所有流量将转到连接的套接字.即使您的服务器可能与本地地址192.168.1.100端口80有一千个连接,但地址和端口的客户端组合将始终不同,因此元组始终是唯一的.
首先,服务器套接字通常绑定到众所周知的名称(在这种情况下是端口),并且它们与自己建立起来listen()
.这就是真正的差异发生的地方,因为客户端套接字建立自己connect()
.调用listen()
套接字会导致内核的tcp/ip实现开始接受发送到套接字绑定名称(端口)的连接.无论你是否打电话,都会发生这种情况accept()
.
accept()
只需为您的服务器提供一种访问连接到您的侦听套接字的客户端套接字并与之交互的方法.
如果您真的感兴趣,那么我建议您阅读TCP/IP Illustrated,第2卷.如果你想要一个较少的"内心"答案,那么:
服务器套接字绑定到众所周知的端点,其中端点是(协议,地址,端口)元组.端点由socket()
系统调用中指定的协议和系统调用中指定的寻址信息组成bind()
.
当服务器调用listen()
系统调用时,网络堆栈会创建一个队列,其中放置挂起的连接.给出队列大小的提示作为backlog
参数listen()
.
然后,服务器调用accept()
从队列中提取新连接.
客户端套接字通过在调用中指定服务器端点connect()
然后使用send()
或发送数据来向服务器套接字发送消息write()
.
当客户端调用时connect()
,会将连接推送到服务器端的队列,直到服务器接受连接.
但是,此描述仅对TCP/IP套接字有效.由于UDP套接字不是(必然)连接,因此UDP情况更简单且完全不同.