对socket的思考

为什么有监听socket和连接socket,为什么产生两个socket

Posted by Liangjf on April 9, 2019

为什么有监听socket和连接socket,为什么产生两个socket

先看一半的socket建立连接的双方的过程:

客户端:

socket()—->创建出 active_socket_fd (client_socket_fd)

bind()—>把active_socket_fdip,port绑定起来

connect()—>client_socket_fd 主动请求服务端的 listen_socket_fd

read()/write()—->读/写 socket io

close()—->关闭socket_fd

服务端:

socket()—->创建出 active_socket_fd

bind()—>把active_socket_fd与ip,port绑定起来

listen()—->active_socket_fd–> listen_socket_fd 等待客户端的client_socket_fd来请求连接

accept()—->listen_socket_fd–>connec_socket_fd 把监听socket转变为连接socket,用于建立连接购的读写数据

read()/write()—->读/写 socket io

close()—->关闭socket_fd

linux内核, socket函数创建的套接字是主动套接字

一开始socket函数, 不管在客户端还是在服务端, 创建的都是主动socket, 但是在服务端经过listen(), 后把其转变为listen_socket_fd(被动监听socket), 经过accept()后转变为connect_socket_fd(已连接socket).

在转变为connect_socket_fd之前, 都是同一个socket, 只不过是socket的状态改变了, 但是服务端经过accept()后返回的socket是新的socket, 用于连接后的read()/write()

为什么服务端这么特殊, 需要两种状态的socket, 并且在这个过程中产生两个socket?

需要两种状态的socket?

对于前者, 这个比较好理解, 因为是现在的网络程序中是C/S结构的, 一般是客户端主动向服务端请求建立连接. 这个过程中, 主要涉及到两个状态, 一个是主动, 一个是被动的. 因此, 客户端的socket只用于主动向服务端的socket请求建立连接, 服务端的socket一直被动的等待客户端的请求连接就ok了. 所以这就解答了为什么需要两种状态的socket, 只有一方是主动, 另一方是被动, 才能否完成上面的过程. 如果双方都是主动, 或者被动, 就完成不了上面的过程了.

1.产生两个socket?

等等, 上面好像没有说到为什么服务端需要产生两个socket(监听socket和已连接socket)

这个我认为是, 监听socket,是服务器作为客户端连接请求的一个对端,只需创建一次能够让客户端请求到有这个端点就ok,所以监听socket(listen_socket_fd)存在于服务器的整个生命周期, 不需要每个连接都创建一个新的监听socket出来, 没必要呢。已连接socket(connect_socket_fd)是客户端与服务器之间已经建立起来了的连接的一个端点,服务器每次接受连接请求时都会创建一个新已连接socket,它的生命周期只是客户端请求服务端的时间范围内。

2.为什么不只使用一个listen_socket_fd完成从创建监听socket(listen_socket_fd), 到被请求连接, 处理请求, 关闭socket的整个过程呢? 而需要用一个listen_socket_fd作为监听客户端请求, 然后每个连接创建一个新的connect_socket_fd来完成服务端与客户端的”交流”?

  • 假设前者那种情况, 只用一个socket完成整个过程. 那么这个socket就会一直被占用, 而不能被另外的客户端请求, 造成了服务端的性能极其低下, 如果没有存储后面的客户端请求, 就会被错过而丢弃, 因为当前的socket正在与当前一个客户端的socket建立连接.
  • 所以从上面的情况可以得知, 在请求连接和连接后需要的socket应该不是同一个, 它们负责的工作是不一样的. 有了listen_socket_fd和connect_socket_fd后, 就可以专门用一listen_socket_fd负责响应客户端的请求, 每次新的connect_socket_fd专门负责当前这次连接的数据交互.

总结

为什么需要两种socket(监听socket和已连接socket)已经说得明白了, 总的来说是, 是为了职责分工, 分层协作, 提高服务端性能.