tcp连结建立与断开(三握手四挥手)

1.监听队列

listen到底在干什么,创建两个监听队列,

其值在linux上的含义是,已经完成3次握手队列的大小

但在unix系统上指的是上下两个队列之和。

所以这个队列的值并不精准。共性就是给的值越大 队列就越大。

三次握手 建立连接的。

2.三次握手流程("打电话约见面")

整体流程

第 1 次握手:你打给朋友,说 "我要找你"
  • 客户(你)状态:从 "没打电话"(CLOSED)→"等朋友接"(SYN-SENT
  • 发的消息:SYN=1, seq=x
    • 类比:"喂,是我不?我想约你见面(SYN=1是'请求建立连接'的信号),我这边的序号是 x(seq=x是数据的起始编号)"
  • 服务器(朋友)状态:从 "等电话"(LISTEN)→"等你确认"(SYN-RCVD
第 2 次握手:朋友接电话,说 "我在,你说"
  • 服务器发的消息:SYN=1, ACK=1, seq=y, ack=x+1
    • 类比:"我在(ACK=1是'确认收到你的消息'),我也想跟你连(SYN=1是'同意建立连接'),我这边的序号是 y(seq=y),我收到你的序号 x 了(ack=x+1是'下一条消息请从 x+1 开始发')"
  • 客户状态:从 "等朋友接"→"可以聊天了"(ESTABLISHED
第 3 次握手:你回朋友,说 "好的,开始聊"
  • 客户发的消息:ACK=1, seq=x+1, ack=y+1
    • 类比:"收到你的回复了(ACK=1),我接下来发消息从 x+1 开始(seq=x+1),你发的 y 我也收到了(ack=y+1)"
  • 服务器状态:从 "等你确认"→"可以聊天了"(ESTABLISHED

核心结论

三次握手完成后,双方状态都变成ESTABLISHED,就能开始传数据了。

记口诀:"你喊我→我应你→你确认",三次沟通保证 "双方都知道'能连、想连'",避免连错 / 连丢。

3.服务器监听 + 三次握手 + accept () 建立连接

这张图是 **"服务器监听 + 三次握手 + accept () 建立连接" 的对应关系 **,结合 "奶茶店迎客" 的类比来理解:

先理清核心角色

  • 左边(服务器) :对应 "奶茶店",listen()是 "开门营业",accept()是 "接待顾客";
  • 右边(客户端) :对应 "顾客",connect()是 "上门找店";
  • 中间(三次握手):是 "顾客进门的流程"。

1. listen()的作用:"开门营业,准备接客"

  • listen()执行后,服务器进入 **"LISTEN(监听)状态"**,相当于奶茶店 "打开门、摆好排队的栏杆";
  • 图里的 "未完成握手" 队列:是 "刚上门、正在和店员打招呼(进行三次握手)的顾客";
  • 图里的 "已完成握手" 队列:是 "已经打完招呼、排队等接待的顾客"。

2. 三次握手和队列的关系

客户端发起connect()后,三次握手的流程会对应服务器的两个队列:

  • 第 1 次握手(客户端发 SYN):服务器收到后,把这个客户端放到 "未完成握手" 队列;
  • 第 2 次握手(服务器回 SYN+ACK):还在 "未完成握手" 队列里;
  • 第 3 次握手(客户端回 ACK):三次握手完成,服务器把这个客户端从 "未完成" 移到 "已完成握手" 队列。

3. accept()的作用:"从排队的顾客里接一个进来"

  • accept()阻塞函数 (没人排队就一直等),它会从 "已完成握手" 队列里取出一个客户端 ,并创建一个新的套接字(比如图里的c
  • 这个新套接字c,就是服务器和这个客户端单独通信的 "通道"(相当于奶茶店给这个顾客开一个 "小窗口" 点单);
  • 图里 "已完成握手" 队列里的红圈,就是accept()要取的 "已经准备好的顾客"。

核心总结

  • listen():让服务器进入 "可接客状态",并维护 "未完成 / 已完成握手" 两个队列;
  • 三次握手:是客户端 "从上门到排队" 的过程,完成后进入 "已完成握手" 队列;
  • accept():从 "已完成队列" 里接一个客户,建立单独的通信通道。

简单说:listen()是 "开门 + 摆排队栏",三次握手是 "顾客排队",accept()是 "接排队的顾客进店"。

客户段代码:

cpp 复制代码
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>

int main()
{
    int sockfd = socket(AF_INET,SOCK_STREAM,0);
    if ( sockfd == -1 )
    {
        exit(1);
    }

    struct sockaddr_in saddr;//指定服务器的ip port
    memset(&saddr,0,sizeof(saddr));
    saddr.sin_family = AF_INET;
    saddr.sin_port = htons(6000);
    saddr.sin_addr.s_addr = inet_addr("192.168.5.94");
    int res = connect(sockfd,(struct sockaddr*)&saddr,sizeof(saddr));//发起连接 三次握手
    if ( res == -1 )
    {
        printf("connect err\n");
        exit(1);
    }

    while( 1 )
    {
        printf("input\n");
        char buff[128] = {0};
        fgets(buff,128,stdin);

        if ( strncmp(buff,"end",3) == 0 )
        {
            break;
        }

        send(sockfd,buff,strlen(buff)-1,0);
        memset(buff,0,128);
        recv(sockfd,buff,127,0);
        printf("buff=%s\n",buff);
    }

    close(sockfd);
    exit(0);
}

4.网络编程中的套接字(Socket)通信流程

核心是服务端处理客户端连接的基本逻辑,下面分步骤讲清楚:

明确图里的关键概念

  • sockfd(监听套接字) :服务端启动后创建的 "监听用套接字",作用是绑定端口、监听客户端的连接请求,不负责和客户端直接通信。
  • c1/c2(连接套接字) :当客户端发起连接时,服务端通过 accept() 函数生成的 "连接用套接字",每个连接套接字对应一个客户端,后续和这个客户端的读写都用它。
  • client:发起连接的客户端程序。

5.TCP四次挥手

可以把 TCP 的 "四次挥手" 想象成两人打电话挂电话的过程,更通俗:

假设你(客户端)和朋友(服务器)正在打电话聊天,现在你想挂电话(主动关闭):

第 1 次 "挥手":你说 "我没啥要说的了"

你(客户端)先开口:"我这边没别的话了哈~"(对应发FIN报文),然后你拿着电话等朋友回应(进入FIN-WAIT-1状态)。

第 2 次 "挥手":朋友说 "收到,我再收尾一下"

朋友(服务器)听到后,先回你:"好的,我知道你没话说了,我把剩下的事说完哈"(对应发ACK确认报文),此时朋友开始整理自己没说完的内容(服务器进入CLOSE-WAIT状态);你听到朋友的回应,就安静等他收尾(你进入FIN-WAIT-2状态)。

第 3 次 "挥手":朋友说 "我也说完了,挂吧"

朋友把自己的话全说完后,跟你说:"我这边也没话说了,咱们挂吧"(对应发FIN+ACK报文),然后朋友拿着电话等你最后确认(服务器进入LAST-ACK状态)。

第 4 次 "挥手":你说 "收到,我等会儿再挂"

你听到朋友说 "挂吧",回他:"收到,那我等几秒再挂哈~"(对应发ACK确认报文),然后你会等一小会儿(2MSL,防止朋友没听到你的回应又喊你);朋友听到你的回应,直接挂了电话(服务器进入CLOSED状态);等你等够时间,也挂了电话(客户端进入CLOSED状态)。

简单说:四次挥手就是 "我说完了→知道了→我也说完了→收到了,等会儿挂",确保双方都没话说了再彻底挂掉,避免有人话没说完就被打断。

把左边看成主动挂电话的人(客户端) ,右边看成被动挂电话的人(服务器)

  1. 第 1 步(左→右):FIN seq=x左边(主动方)先喊:"我没话说了(close)",对应发 "结束请求"(FIN),x 是他最后一句话的 "序号"。

  2. 第 2 步(右→左):ACK x+1右边(被动方)回:"收到你的话了",用 "ACK x+1" 表示 "我听到 x 这句话了,等你下一句(但你已经没话了)"。

  3. 第 3 步(右→左):FIN seq=y右边(被动方)把自己的话说完后,也喊:"我也没话说了(close)",发 "结束请求"(FIN),y 是他最后一句话的 "序号"。

  4. 第 4 步(左→右):ACK y+1左边(主动方)回:"收到你的话了",用 "ACK y+1" 表示 "我听到 y 这句话了"。

简单讲:这张图就是 **"主动方说'我说完了'→被动方确认→被动方说'我也说完了'→主动方确认"**,完成 "互相确认没话讲,然后挂掉" 的过程。

相关推荐
WTCLLB2 小时前
cmd-set-ip
网络·windows
damon087082 小时前
nodejs 实现 企业微信 自定义应用 接收消息服务器配置和实现
服务器·前端·企业微信
步步为营DotNet2 小时前
深度解析.NET 中IAsyncEnumerable:异步迭代的高效实现与应用】
服务器·数据库·.net
奋斗者1号2 小时前
paho-mqtt-c + OpenSSL 3.x 连接华为云 IoTDA TLS 握手失败问题分析
c语言·网络·华为云
APIshop2 小时前
实战解析:1688详情api商品sku、主图数据
java·服务器·windows
学Linux的语莫2 小时前
本地部署ollama
linux·服务器·langchain
软件小滔2 小时前
卫生间WiFi又断了?
网络·macos·智能路由器·mac·应用推荐
深圳市恒讯科技2 小时前
常见服务器漏洞及防护方法
服务器·网络·安全
程序媛哪有这么可爱!2 小时前
【删除远程服务器vscode缓存】
服务器·人工智能·vscode·缓存·边缘计算