TCP/UDP 相关的端口问题详解

问题 1:TCP和UDP可以检测相同的端口吗?

可以的。
在数据链路层中,通过 MAC 地址来寻找局域网中的主机。在网络层中,通过 IP 地址来寻找网络中互连的主机或路由器。在传输层中,需要通过端口进行寻址,来识别同一计算机中同时通信的不同应用程序。
所以,传输层的「端口号」的作用,是为了区分同一个主机上不同应用程序的数据包。
传输层有两个传输协议分别是 TCP 和 UDP,在内核中是两个完全独立的软件模块。

当主机收到数据包后,可以在 IP 包头的「协议号」字段知道该数据包是 TCP/UDP,所以可以根据这个信息确定送给哪个模块(TCP/UDP)处理,送给 TCP/UDP 模块的报文根据「端口号」确定送给哪个应用程序处理。

因此, TCP/UDP 各自的端口号也相互独立,如 TCP 有一个 80 号端口,UDP 也可以有一个 80 号端口,二者并不冲突。

问题二:多个 TCP 服务进程可以绑定同一个端口吗?

eg:如果绑定的p和端口号是:127.0.0.1 8888 和192.168.1.100:8888,那么就不会发生错误。
但是如果绑定相同的ip和端口号就会报错,错误内容为:
在这里插入图片描述
所以说只要绑定时ip不相同但是端口号相同是可以的,有一种情况例外,就是当绑定的ip地址为0.0.0.0时,再绑定相同的端口号就会报错,应为0.0.0.0比较特殊,代表任意地址
意味着绑定了 0.0.0.0 地址,相当于把主机上的所有 IP 地址都绑定了。

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

TCP 服务进程需要绑定一个 IP 地址和一个端口,然后就监听在这个地址和端口上,等待客户端连接的到来。
当我们重启 TCP 服务进程的时候,意味着通过服务器端发起了关闭连接操作,于是就会经过四次挥手,而对于主动关闭方,会在 TIME_WAIT 这个状态里停留一段时间,这个时间大约为 2MSL。
在这里插入图片描述
当 TCP 服务进程重启时,服务端会出现 TIME_WAIT 状态的连接,TIME_WAIT 状态的连接使用的 IP+PORT 仍然被认为是一个有效的 IP+PORT 组合,相同机器上不能够在该 IP+PORT 组合上进行绑定,那么执行 bind() 函数的时候,就会返回了 Address already in use 的错误。

而等 TIME_WAIT 状态的连接结束后,重启 TCP 服务进程就能成功。

2重启 TCP 服务进程时,如何避免“Address in use”的报错信息?

在这里插入图片描述
设置SO_REUSEADDR 操作,如果 TCP 服务进程对 socket 设置 SO_REUSEADDR 属性了,那么在重启时,即使存在一个和绑定 IP+PORT 一样的 TIME_WAIT 状态的连接,依然可以正常绑定成功,因此可以正常重启成功。

问题三:客户端的端口可以重复使用吗?在这里插入图片描述

,客户端的端口选择的发生在 connect 函数,内核在选择端口的时候,会从 net.ipv4.ip_local_port_range 这个内核参数指定的范围来选取一个端口作为客户端端口。
参数默认值时32768到61000
在这里插入图片描述
通过netstat -napt 查看建立起来的连接。
那么例如在一个客户端中内核已经自动分配8888 去连接一个服务端,那么还可以继续使用该端口发起连接吗?

正确的理解:
TCP 连接是由四元组(源IP地址,源端口,目的IP地址,目的端口)唯一确认的,那么只要四元组中其中一个元素发生了变化,那么就表示不同的 TCP 连接的。所以如果客户端已使用端口 64992 与服务端 A 建立了连接,那么客户端要与服务端 B 建立连接,还是可以使用端口 64992 的,因为内核是通过四元祖信息来定位一个 TCP 连接的,并不会因为客户端的端口号相同,而导致连接冲突的问题。
对于客户端的bind绑定问题,如果绑定的IP地址和端口号一样还是会出现“Address already in use”,一般不建议客户端使用bind

问题四:客户端 TCP 连接 TIME_WAIT 状态过多,会导致端口资源耗尽而无法建立新的连接吗?

解决办法:打开 net.ipv4.tcp_tw_reuse 这个内核参数。

因为开启了这个内核参数后,客户端调用 connect 函数时,如果选择到的端口,已经被相同四元组的连接占用的时候,就会判断该连接是否处于 TIME_WAIT 状态,如果该连接处于 TIME_WAIT 状态并且 TIME_WAIT 状态持续的时间超过了 1 秒,那么就会重用这个连接,然后就可以正常使用该端口了。
启了 net.ipv4.tcp_tw_reuse 内核参数,是客户端(连接发起方) 在调用 connect() 函数时才起作用,所以在服务端开启这个参数是没有效果的。

  • 5
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值