TCP/IP动态端口号临时分配策略

  • A+
所属分类:系统知识 系统运维

在实际工作中,大并发的nginx服务器部署了个tomcat,不知道怎么的启动tomcat时,日志报端口已被占用,自己并没有把该端口设置给其他服务,就不知道为什么了,下面给大家说说具体原因.

 

TCP/IP协议中的端口,端口号的范围从0到65535,这些端口又分为两大类:知名端口和动态端口

(1)知名端口(Well-Known Ports)
知名端口即众所周知的端口号,范围从0到1023,这些端口号一般固定分配给一些服务。
比如21端口分配给FTP服务,25端口分配给SMTP(简单邮件传输协议)服务,
80端口分配给HTTP服务,135端口分配给RPC(远程过程调用)服务等等。

(2)动态端口(Dynamic Ports)
动态端口的范围从1024到65535,这些端口号一般不固定分配给某个服务,
也就是说许多服务都可以使用这些端口。只要运行的程序向系统提出访问网络的申请,
那么系统就可以从这些端口号中分配一个供该程序使用。
比如1024端口就是分配给第一个向系统发出申请的程序。
在关闭程序进程后,就会释放所占用的端口号。

知名端口,可以查看/etc/service文件,如下:

# service-name port/protocol [aliases ...] [# comment]

tcpmux 1/tcp # TCP port service multiplexer
tcpmux 1/udp # TCP port service multiplexer
rje 5/tcp # Remote Job Entry
rje 5/udp # Remote Job Entry
echo 7/tcp
echo 7/udp
discard 9/tcp sink null
discard 9/udp sink null
systat 11/tcp users
systat 11/udp users
daytime 13/tcp
daytime 13/udp
qotd 17/tcp quote
qotd 17/udp quote
msp 18/tcp # message send protocol
msp 18/udp # message send protocol
chargen 19/tcp ttytst source
chargen 19/udp ttytst source
ftp-data 20/tcp
ftp-data 20/udp
# 21 is registered to ftp, but also used by fsp
ftp 21/tcp
ftp 21/udp fsp fspd
ssh 22/tcp # The Secure Shell (SSH) Protocol
ssh 22/udp # The Secure Shell (SSH) Protocol
telnet 23/tcp
telnet 23/udp
# 24 - private mail system
lmtp 24/tcp # LMTP Mail Delivery
lmtp 24/udp # LMTP Mail Delivery
smtp 25/tcp mail
smtp 25/udp mail
time 37/tcp timserver
time 37/udp timserver

动态端口,范围是1024-65535,在这个范围内,我们可以通过设定系统内核参数自定义范围的,/etc/sysctl.conf中的net.ipv4.ip_local_port_range以及/proc/sys/net/ipv4/ip_local_port_range中可以查看,动态端口分配并不是有序的,而是按照特定的算法随机分配的。

内核中临时端口号的分配发生在以下两处:

– bind();
– connect()。

bind()通过inet_csk_get_port()获取端口号,利用了net_random()产生的随机数 :

int inet_csk_get_port(struct sock *sk, unsigned short snum)
 {
         struct inet_hashinfo *hashinfo = sk->sk_prot->h.hashinfo;
         struct inet_bind_hashbucket *head;
         struct inet_bind_bucket *tb;
         int ret, attempts = 5;
         struct net *net = sock_net(sk);
         int smallest_size = -1, smallest_rover;
         kuid_t uid = sock_i_uid(sk);

         local_bh_disable();
         if (!snum) {
                 int remaining, rover, low, high;

again:
                 inet_get_local_port_range(&low, &high);
                 remaining = (high - low) + 1;
                 smallest_rover = rover = net_random() % remaining + low;

                 smallest_size = -1;
                 do {
                         if (inet_is_reserved_local_port(rover))
                                 goto next_nolock;

connect()通过inet_hash_connect()分配端口号。核心的代码是:
port = low + (i + offset) % remaining;
其中 offset 是随机数。 


为以上代码生成随机数port_offset的函数是:


综上,临时端口号是这样产生的:

生成一个随机数,利用随机数在ip_local_port_range范围内取值,如果取到的值在ip_local_reserved_ports范围内 ,那就再依次取下一个值,直到不在ip_local_reserved_ports范围内为止。

 

 

  • 我的微信
  • 微信扫一扫
  • weinxin
  • 微信公众号
  • 微信公众号扫一扫
  • weinxin
avatar