网络编程套接字(8)——TCP协议通讯过程

下图为基于TCP协议的客户端/服务器程序的一般流程:

网络编程套接字(8)——TCP协议通讯过程_第1张图片

  • 服务器初始化:

        调用socket,创建文件描述符;

        调用bind,将当前的文件描述符与ip/port绑定在一起。若此端口已被其他进程占用,则绑定失败;

        调用listen,声明当前的文件描述符作为一个服务器的文件描述符,为后面的accept做准备;

        调用accept,阻塞式等待客户端连接过来。

  • 建立连接的过程:

        调用socket,创建文件描述符;

        调用connect,向服务器发起连接请求;

        connect会发出SYN段并阻塞式等待服务器应答;(第一次握手)

        服务器收到客户端的SYN,会应答一个SYN-ACK段表示“同意建立连接”;(第二次握手)

        客户端收到SYN-ACK后会从connect()返回,同时应答一个ACK段。(第三次握手)

这个建立连接的过程,通常被称为三次握手

  • 数据传输的过程:

      建立连接后,TCP协议提供全双工的通信服务,使得在同一条连接中,同一时刻,通信双方可以同时写数据;

        服务器从accept()返回后立即调用read(),读socket与读管道相同,若无数据则阻塞式等待;

        客户端调用write()发送请求给服务器,服务器收到后从read()返回,对客户端的请求进行处理,在此期间客户端调用read()阻塞式等待服务器的应答;

        服务器调用write()将处理结果发回给客户端,再次调用read()阻塞式等待下一条请求;

        客户端收到后从read()返回,发送下一条请求,如此循环往复。

  • 断开连接的过程:

        若客户端无更多的请求,就调用close()关闭连接,客户端会向服务器发送FIN段;(第一次挥手)

        服务器收到FIN后,会回应一个ACK,同时read会返回0;(第二次挥手)

        read返回后,服务器就知道客户端关闭了连接,也调用close关闭连接,此时服务器会向客户端发送一个FIN;(第三次挥手)

        客户端收到FIN,再返回一个ACK给服务器;(第四次挥手)

这个断开连接的过程,通常被称为四次挥手


这里我们可以举一个例子来帮助理解三次握手和四次挥手的过程:

比如说,一对青年男女谈恋爱,在初期确立两个人的关系时,必然得有一方主动提出来。我们假设是男生追求女生:

        男生:“做我女朋友吧!”(第一次握手)

        女生:“什么时候?”(第二次握手)

        男生:“就现在!”(第三次握手)

我们可以看出,通过三次的对话,两个人的恋爱关系就确立了下来。

同理,两个人分手时,需要双方同意才可以。

        女生:“你一点上进心都没有,我们分手吧!”(第一次挥手)

        男生:“行吧。”(第二次挥手)

        男生:“凭什么是你提分手,我也要和你分手。”(第三次挥手)

        女生:“行!”(第四次挥手)

我们可以看出,当双方都认同了分手这个决定后,两个人就不再是恋爱关系,断开了联系。


通过这个例子,我们可以比较直观的理解三次握手和四次挥手的过程。其中有两点需要我们注意:

        (1)三次握手时需有一方主动;

        (2)四次挥手断开连接时,须得征得双方同意。


这里我们再来讨论一个问题:为什么是三次握手而不是两次握手或者四次握手呢?

        就上面这个谈恋爱确立关系的例子来说,男生向女生发起建立恋爱关系的请求,女生答应。表面上看起来两次握手即可建立连接。但我们可以想象一种情况:

        男生:“做我女朋友吧!”(第一次握手)

        女生:“让我考虑考虑,过段时间给你答复。”(第二次握手)

但假设女生在说这句话时,天上突然打了几道雷,雷声盖过了女生的声音,男生并没有听到女生的答复。此时男生误以为女生已经同意,可事实上女生还没有同意。所以两次握手不能完全保证双方已经建立起了连接。

至于为什么不是四次或者更多次数的握手,这个问题在谢仁希版的《计算机网络》中有提及:三次是保证双方互相明确对方能收能发的最低值。所以四次或者更多次的握手从理论上来讲是可行的,但是为了提高效率,三次握手显然为最优解。

  • TCP与UDP对比

            网络编程套接字(8)——TCP协议通讯过程_第2张图片





你可能感兴趣的:(Linux)