- 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 是随机数。
int __inet_hash_connect(struct inet_timewait_death_row *death_row, struct sock *sk, u32 port_offset, int (*check_established)(struct inet_timewait_death_row *, struct sock *, __u16, struct inet_timewait_sock **), int (*hash)(struct sock *sk, struct inet_timewait_sock *twp)) { struct inet_hashinfo *hinfo = death_row->hashinfo; const unsigned short snum = inet_sk(sk)->inet_num; struct inet_bind_hashbucket *head; struct inet_bind_bucket *tb; int ret; struct net *net = sock_net(sk); int twrefcnt = 1; if (!snum) { int i, remaining, low, high, port; static u32 hint; u32 offset = hint + port_offset; struct inet_timewait_sock *tw = NULL; inet_get_local_port_range(&low, &high); remaining = (high - low) + 1; local_bh_disable(); for (i = 1; i <= remaining; i++) { port = low + (i + offset) % remaining; if (inet_is_reserved_local_port(port)) continue;
为以上代码生成随机数port_offset的函数是:
static inline u32 inet_sk_port_offset(const struct sock *sk){const struct inet_sock *inet = inet_sk(sk);return secure_ipv4_port_ephemeral(inet->inet_rcv_saddr,inet->inet_daddr,inet->inet_dport);}
综上,临时端口号是这样产生的:
生成一个随机数,利用随机数在ip_local_port_range范围内取值,如果取到的值在ip_local_reserved_ports范围内 ,那就再依次取下一个值,直到不在ip_local_reserved_ports范围内为止。
- 安卓客户端下载
- 微信扫一扫
- 微信公众号
- 微信公众号扫一扫