阅读 546

TCP:三个角度看TCP连接建立与结束

前言

本文的核心在于 看问题的角度和图例 ;阅读前提是了解TCP连接的大致过程,通过本文可以更加深入的了解连接建立的细节;本文同时是两个TCP常见面试题的答案: (1) 描述TCP连接建立和断开的过程; (2) TCP连接中accept系统调用发生在哪一步;

信息传递角度

从信息传递角度看,信息传递的标识是SYN,标识了开始建立连接并互换信息,交换的信息有:
  1. client的ip和port,也就是通知服务端链接人的地址;
  2. 双方互换了开始计数的sequence number,也就是ISN;
  3. 双方协商了MSS;
  4. 双方沟通了window size;

状态流转角度

从连接的建立和结束过程的状态流转来看,连接的正常状态如下图;信息交换之后,两端的联系状态会发生变化;打个比方,人和人之间了解了彼此的情况沟通交流之后,关系的状态也会发生变化。

系统调用角度

最后看一下什么操作导致了信息的传递和状态的变化,有些是用户进程通过system call触发的(绿色表示),有些是kernel按rfc对于tcp的规定实现的。

这里涉及的系统调用包括:socket,listen,bind,accept,connect,close;

accept拓展详解

这张图中accept画在了server establish的后面,这里具体展开解释一下accept方法。给accept过多关注有两个原因:这个操作容易产生误解,笔者第一次看tcp server的过程中以为accept是连接建立的一部分,毕竟大部分讲tcp server的例子里accept会block住直到返回一个已经建好的连接;第二个原因是accept在面试中常常被问到。

这里先看一下linux manual里accept的api定义:

   #include <sys/types.h>          
   #include <sys/socket.h>

   int accept(int sockfd, struct sockaddr *addr, socklen_t *addrlen);
复制代码
  1. accpet用于需要建立连接的socket。 也就是UDP这种server并不需要accept,TCP这种需要连接的传输协议才需要调用accept函数。

  2. accept的作用是1-从监听socket的队列中取得第一个2-等待处理的连接pending connection,并3-创建一个新的已经处于连接状态的socket 并返回这个socket的fd。这句话中包含了3个关键信息,其中3信息中有2个socket和一个连接:第一个socket是accept需要知道listening socket是哪个,要从这个监听socket的连接队列中拿到这个等待处理的连接;第二个是拿到连接之后,accept直接创建一个connected socket与之对应;从这里可以看到connection本身已经存在于queue中,accept的作用实际是从queue中拿出一个连接而已,这个就解释了accept实际是发生在三次握手之后。实际一个listening socket有两个队列,一个队列处理正在握手过程中的connection,另一个队列处连接建立完成的connection,accept取得的是握手已经完成并等待用户进程处理的连接;

  3. accept是否阻塞可以通过listening socket的选项控制:大部分例子里accept会阻塞caller进程直至返回一个connected socket,但是这个是可以控制的,这里就涉及“socket options”,当socket被设置为nonblocking时如果没有连接可以拿accept不会一直blocking,会直接返回error;

升华一下

连接的建立有(1)动作,动作使得(2)信息的交换,信息的交换使得(3)状态发生改变。这里”动作-信息-状态“也可以看作一种结构性分析的方法,这个方法可以来帮忙设计各种场景下的状态机:什么核心操作,核心信息变化,应该是一种状态。

希望这三个角度能加深您对TCP的认识哦:)