TCP 基础知识

格式

  • 主要有源端口 目标端口 序列号 确认应答号 窗口大小
TCP 头格式

TCP 和 UDP 可以使用同一个端口吗

传输层有两个传输协议分别是 TCP 和 UDP,在内核中是两个完全独立的软件模块。他的内部有不同的协议栈

img

重启 TCP 服务进程时,为什么会有“Address in use”的报错信息

重启 TCP 服务进程时,为什么会有“Address in use”的报错信息?

当我们重启 TCP 服务进程的时候,意味着通过服务器端发起了关闭连接操作,于是就会经过四次挥手,而对于主动关闭方,会在 TIME_WAIT 这个状态里停留一段时间,这个时间大约为 2MSL。

解决 我们可以在调用 bind 前,对 socket 设置 SO_REUSEADDR 属性,可以解决这个问题。

客户端的端口可以重复使用吗

  • tcp四元组是 ip+port 对 所以可以复用 端口

服务端没有 listen,客户端发起连接建立,会发生什么?

找不到对应的 监听的 tcp socket 会直接发送rst 报文

不使用 listen ,可以建立 TCP 连接吗?

是可以的,客户端是可以自己连自己的形成连接(TCP自连接),也可以两个客户端同时向对方发出请求建立连接(TCP同时打开),这两个情况都有个共同点,就是没有服务端参与,也就是没有listen,就能建立连接。

在 TCP 自连接的情况中,客户端在 connect 方法时,最后会将自己的连接信息放入到这个全局 hash 表中,然后将信息发出,消息在经过回环地址重新回到 TCP 传输层的时候,就会根据 IP + 端口信息,再一次从这个全局 hash 中取出信息。于是握手包一来一回,最后成功建立连接。 对于两个客户端同时建立连接的情况来说也是这样的

没有accept能建立tcp连接吗

半连接队列和全连接队列

能 ,accept 是从全连接队列里面拿出来一条消息来处理的

  • 半连接队列(SYN队列),服务端收到第一次握手后,会将sock加入到这个队列中,队列内的sock都处于SYN_RECV 状态。 其本质是一个哈希表 由于半连接队列需要精确定位到所在的连接socket
  • 全连接队列(ACCEPT队列),在服务端收到第三次握手后,会将半连接队列的sock 取出,放到全连接队列中。队列里的 sock 都处于 ESTABLISHED状态。这里的连接就是等待 accpect 拿取的连接

全连接队列满了

全连接队列满了会怎么样?

如果队列满了,服务端还收到客户端的第三次握手ACK,默认当然会丢弃这个ACK。

但除了丢弃之外,还有一些附带行为,这会受 tcp_abort_on_overflow 参数的影响。

tcp_abort_on_overflow设置为 0,全连接队列满了之后,会丢弃这个第三次握手ACK包,并且开启定时器,重传第二次握手的SYN+ACK,如果重传超过一定限制次数,还会把对应的半连接队列里的连接给删掉。

当设置成为1 的时候会直接发送rst给客户端

半连接队列满了怎么办

一般是丢弃,tcp_syncookies 这个控制了

  • 对于半连接队列满了的时候一般是受到了syn flood 攻击 也就是攻击者模拟syn请求而且不发送第三次的握手信息

当tcp_syncookies 设置成1 的时候 生成一个cookie 在第三次握手的ack时候返回,验证的时候进行校验,放到全连接队列中去 在这里可以获取tcp的seq消息来取得信息

  • 但是对于这种校验 一般是比较占用cpu的 由于需要计算结果 所以可能会导致ack攻击

客户端没有半连接队列和全连接队列,但有一个全局hash,可以通过它实现自连接或TCP同时打开。

FIN 报文一定得调用关闭连接的函数,才会发送吗?

如果进程退出了,不管是不是正常退出,还是异常退出(如进程崩溃),内核都会发送 FIN 报文,与对方完成四次挥手。