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

一、TCP 和 UDP 可以同时绑定相同的端口吗?

            

 

   在数据链路层中,通过MAC地址来寻找局域网中的主机。在网络层中,通过IP地址来寻找网络中互联的主机或路由器。在传输层中,需要通过端口来寻址,来识别同一机器中同时通信的不同应用程序。

  所以,传输层的端口号的作用,是为了区分同一主机上不同应用程序的数据包。

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

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

  因此,TCP/UDP各自的端口号也相互独立。

二、多个TCP服务器进程可以绑定同一个端口号吗

  如果两个TCP服务进程同时绑定的IP地址和端口号都相同,那么执行bind()时候就会出错,提示“Address already in use”。

  注意,必须IP地址和端口号都相同。

  如果进程绑定了0.0.0.0地址,这代表了任意地址,则此时只要有另一进程绑定了一致的端口号,则都会报错。

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

  在实践中,我们可能会经常碰到一个问题,当 TCP 服务进程重启之后,总是碰到“Address in use”的报错信息,TCP 服务进程不能很快地重启,而是要过一会才能重启成功。

  这是为什么呢?

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

 

   在TIME_WAIT状态下的IP+PORT组合仍然被认为是一个有效的组合,此时相同机器就不能够在该IP+PORT组合上进行绑定。

  对于此种情况,我们可以在调用bind前,对socket设置SO_REUSEADDR属性。

int on = 1;
setsockopt(listenfd, SOL_SOCKET, SO_REUSEADDR, &on, sizeof(on));

  SO_REUSEADDR 作用是:如果当前启动进程绑定的 IP+PORT 与处于TIME_WAIT 状态的连接占用的 IP+PORT 存在冲突,但是新启动的进程使用了 SO_REUSEADDR 选项,那么该进程就可以绑定成功。

  对于前面提到的问题:如果TCP服务进程A绑定了0.0.0.0:8080,而此时TCP服务进程去绑定192.168.1.100:8080会出错。

  这个问题也可以使用SO_REUSEADDR拒绝,因为它的另外一个作用是:绑定的IP地址+端口时,只要IP地址不是正好(exactly)相同,那么允许绑定。

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

  客户端在执行 connect 函数的时候,会在内核里随机选择一个端口,然后向服务端发起 SYN 报文,然后与服务端进行三次握手。

 

   所以客户端的端口选择发生在connect函数,内核在选择端口的时候,会从net.ipv4.ip_local_port_range这个内核参数指定的范围来选取一个端口作为客户端端口。

  TCP连接是由四元组(源IP地址,源端口,目的IP地址,目的端口)唯一确认的,那么只要四元组中其中一个元素发生了变化,那么就表示不同的TCP连接的。所以如果客户端已使用端口a与服务端A建立了连接,那么客户端要与服务端B建立连接,还是可以使用端口a的,因为内核是通过一个四元组来定位一个TCP连接的,并不会因为客户端的端口号相同,而导致连接冲突的问题。

  但是,如果多个客户端bind同一个IP地址+PORT组合,还是会出错的。一般而言,客户端也不建议使用bind函数,因为客户端的端口通常没什么意义。

五、客户端连接TIME_WAIT状态过多,会导致端口资源耗尽而无法建立新的连接吗

  针对这个问题要看,客户端是否都是与同一个服务器(IP地址+PORT一样)建立连接。

  如果客户端都是与同一服务器(IP地址+PORT一样)建立连接,那么TIME_WAIT状态过多,当端口资源被耗尽,就无法与这个服务器再建立连接了。

  但是,只要客户端连接的服务器不同,端口资源是可以重复使用的(四元组)。

六、解决客户端TCP连接TIME_WAIT过多,导致无法与同一个服务器建立连接的问题

  针对这个问题,解决方法是打开net.ipv4.tcp_tw_reuse这个内核参数。

  因为这个开启这个内核参数后,客户端调用connect函数时,如果选择到的端口,已经被相同四元组的连接占用时,会判断该连接是否处于TIME_WAIT状态且TIME_WAIT状态持续时间超过1秒,如果是,就会重用这个连接,然后就可以正常使用该端口了。

 -----------------------------------------------------------------

------------------------------------------------------------------

知识来源:小林coding

posted @   幻cat  阅读(2322)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· 没有源码,如何修改代码逻辑?
· PowerShell开发游戏 · 打蜜蜂
· 在鹅厂做java开发是什么体验
· 百万级群聊的设计实践
· WPF到Web的无缝过渡:英雄联盟客户端的OpenSilver迁移实战
点击右上角即可分享
微信分享提示