Skip to content

Latest commit

 

History

History
executable file
·
33 lines (23 loc) · 3.2 KB

连接的维护.md

File metadata and controls

executable file
·
33 lines (23 loc) · 3.2 KB

连接维护(针对非阻塞IO)

建立连接

  • 建立连接的过程
    连接的建立比较简单,server端通过socket(),bind(),listen(),并使用epoll ET模式监听listenfd的读请求,当TCP连接完成3次握手后,会触发listenfd的读事件,应用程序调用accept(),会检查已完成的连接队列,如果队列里有连接,就返回这个连接,出错或连接为空时返回-1。此时,已经可以进行正常的读写操作了。 当然,因为是ET模式,accept()要一直循环到就绪连接为空。
  • 分析
    之所以说建立连接的过程比较简单,是因为数据的通信已经由操作系统帮我们完成了,这里的通信是指3次握手的过程,这个过程不需要应用程序参与,当应用程序感知到连接时,此时该连接已经完成了3次握手的过程,accept就好了。另一个原因是一般情况下,连接的建立都是client发起的,server端被动建立连接就好了,也不会出现同时建立的情况。
  • 限制
    假设server只监听一个端口,一个连接就是一个四元组(原ip,原port,对端ip, 对端port),那么理论上可以建立2^48个连接,可是,fd可没有这么多(操作系统限制、用户进程限制)。当连接满了,如果空等而不连接,那么就绪队列也满了后,会导致新连接无法建立。这里的做法我参考了muduo,准备一个空的文件描述符,accept()后直接close(),这样对端不会收到RST,至少可以知道服务器正在运行。

关闭连接

相对于连接的建立,关闭连接则复杂的多,远不是一个close()那么简单,关闭连接要优雅。

什么时候关闭连接?

通常server和client都可以主动发Fin来关闭连接

  • 对于client(非Keep-Alive),发送完请求后就可以shutdown()写端,然后收到server发来的应答,最后close掉连接。也可以不shutdown()写,等读完直接close。对于Keep-Alive的情况,就要看client的心情了,收到消息后可以断,也可以不断,server应该保证不主动断开。

  • 对于server端,毫无疑问应该谨慎处理以上所有情况。具体说来:

  • 出现各种关于连接的错误时,可以直接close()掉
  • 短连接超时的请求,可以close(),也可以不关
  • 长连接对方长时间没有请求(如果没有保活机制),可以close(),也可以不关
  • client发出Fin,server会收到0字节,通常不能判断client是close了还是shutdown,这时server应当把消息发完,然后才可以close(),如果对方调用的是close,会收到RST,server能感知到,就可以立即close了
  • 短连接正常结束,server可以close,也可以不close,大多数的实现是不close的(对HTTP1.1而言)
EPOLLIN触发但是read()返回0的情况

这种情况通常有两个原因:

  • 对端已经关闭了连接,这时再写该fd会出错,此时应该关闭连接
  • 对端只是shutdown()了写端,告诉server我已经写完了,但是还可以接收信息。server应该在写完所有的信息后再关闭连接。更优雅的做法是透明的传递这个行为,即server顺着关闭读端,然后发完数据后关闭。