监听 socket、已连接 socket

监听 socket、已连接 socket

前言

最近补了补网络的基础知识,很多资料讲到 socket 的时候都会提及 监听 socket 和 已连接 socket 不是同一个 socket,但是没有详细解释为什么

socket 流程

先捋一捋流程 TCP:

UDP:

TCP 的监听 socket、已连接 socket

看到 TCP 建立连接的时候,服务端收到客户端发起的连接请求后,调用 Socket 的 accept() 方法接受连接,并返回一个新的 socket,其实这两个 socket 是承担不一样的职责的。 套接字其实可以用一个四元组来表示:{ 对端 IP,对端端口,本机 IP,本机端口 } 监听 socket 可以表示为:* + * + TCP + 本机IP + 本机端口 已连接 socket 可以表示为: 对端 IP + 对端端口 + TCP + 本机IP + 本机端口

监听 socket 可以接受任何对端的连接请求(对端 IP,对端端口 都用通配符表示),建立成功后返回一个已连接 socket,这个 socket 的四个基本信息全是特定的,也就是说这个新的 socket 是特定客户端和服务端一对一通信的 socket 也就是说 监听 socket 只等待连接、建立连接,而已连接 socket 负责在连接完成后与指定客户端完成一对一的数据传输,他俩专人专职。

UCP 的监听 socket

因为 UDP 不提供连接服务,不需要记录客户端信息,所以一个监听 socket 就够用了:* + * + UCP + 本机IP + 本机端口

原因

再来细究一下两个 socket,其实每次连接的时候,服务器会给等待连接的 socket 复制出一个副本 socket,然后客户端连接在这个副本 socket 上,后续也由这个副本 socket 来负责通信操作,而原来那个等待连接的 socket 还会继续以等待连接的状态存在,以便和下一个客户端连接。

知道了两者的区别,那为什么需要两个 socket 呢,直接一个 socket 负责监听连接、建立连接,然后再使用这个 socket 完成后续的数据传输不可以吗? 理论上是可以的,但是一旦一个客户端成功和服务器连接,那之前的 socket 就被占用了,其他客户端想要连接就连接不上了,这样服务器的效率是非常低下的。 所以两个 socket 的设计是为了职责分工,分层协作,提高服务端性能

在写上面这段话的时候,我突然想到,如果只使用一个 socket,每次这个 socket 被连接占用了以后,再生成一个新的 socket 用于后续的监听连接呢? 我自己又想了想,如果是这样,在连接建立后需要重新 bind() socket 的对端 IP和对端端口,一旦涉及到对现有的数据结构进行修改,就需要考虑修改的风险,比如多线程问题。如果在修改的同时,有另一个客户端发起连接,发现现在的 socket 还没有被占用,但实际上已经在修改了,只是还没修改成功,那这时就会发生错误。通过加锁可能可以解决,但是会有额外的资源消耗。

参考

知乎上有一个答案,讲的还蛮生动易懂的:https://www.zhihu.com/question/54182420/answer/138476746