• tcp三次握手的一些疑问


    提到tcp的三次握手,网上可以搜到很多资料,大体都是类似的,比如下面这张图示,client和server端的状态转换,报文标志位看上去挺清晰的。

    image.png

    但是从源码角度看会有几个不一样的地方,比如
    a. 服务器端收到客户端的syn报文,回复syn+ack后,就会进入syn_recv状态吗?
    b. 服务器端的状态会从listen转换到 syn_recv,再到established吗?

    下面是看过源码后根据自己理解画的一张图

    image.png

    server收到client发送的syn报文后,为了防止syn攻击,会首先创建request_sock结构,保存到hash表中(半连接队列),而不是直接分配sock结构。可参考kernel代码中 request_sock和sock结构体的定义,sock比request_sock需要更多内存。然后发送syn+ack报文给client。

    如果client是正常连接的话,会发送ack报文给server,server收到后会进行判断,如果是正常ack报文,就会接受此连接,将request_sock从hash表删除,真正分配sock结构,并设置sock->sk_state为TCP_SYN_RECV,将sock结构赋给request_sock->sock后,将request_sock再次添加到另一个链表(全连接队列),后面又紧接着把sock->sk_state为TCP_ESTABLISHED,最后唤醒accept进程到全连接队列取出sock,由accept进程使用newsock和client进行数据传输。

    上面这种防止syn攻击的方式成为syn cache,还有另一个syn cookie,可参考函数tcp_v4_conn_request,这种方法不会保存任何信息就可以达到防攻击目的。

    接下来回答上面的两个问题,对于问题a,server从收到syn到再次收到ack的这段时间内,因为还没有分配sock结构,所以从代码看,是在收到ack后,分配sock才设置TCP_SYN_RECV。但是还是可以认为是TCP_SYN_RECV,可以通过查看cat /proc/net/tcp确认。
    对于问题b,server sock一直是处于listen状态的,收到新连接后,会分配新的sock,改变新sock的状态。

    堵塞函数
    socket编程中有如下几个堵塞函数,简单介绍一下
    a. connect
    调用connect后,kernel会自动发送syn报文发起tcp三次握手。这个调用默认是堵塞的,等待三次握手完成后,才会返回成功与否。
    b. accept
    accept等待从全连接队列接收新连接,如果全连接队列为空,就会一直堵塞等待,直到新连接到来。
    c. read/write
    读写数据默认也都是堵塞的。

    如果不想堵塞的话,可以使用select/poll/epoll等io多路复用技术来实现。

    也可参考:https://www.jianshu.com/p/1f59ba05f851 

  • 相关阅读:
    el-tree结合el-switch实现状态切换
    java毕业生设计移动在线点菜系统服务端服务端计算机源码+系统+mysql+调试部署+lw
    PPP协议(PPP协议链路建立过程、PAP、CHAP、华为虚拟网络设备配置)
    matlab运行CLBP程序为什么没有图?
    入门力扣自学笔记75 C++ (题目编号522)
    抖音 滑块验证方案 s_v_web_id 参数分析
    Git下载,安装,提交
    MySQL-DDL数据定义语言-约束
    Go 常用命令介绍
    C++————类与对象<一>
  • 原文地址:https://blog.csdn.net/fengcai_ke/article/details/126564028