Upgrade to Pro — share decks privately, control downloads, hide ads and more …

Linux系统服务端口的那些事

Sponsored · SiteGround - Reliable hosting with speed, security, and support you can count on.
Avatar for yongboy yongboy
June 28, 2014

 Linux系统服务端口的那些事

了解Linux服务器端口的用途和局限,以及如何突破端口限制。

Avatar for yongboy

yongboy

June 28, 2014
Tweet

Other Decks in Technology

Transcript

  1. 协议端口用途  一台服务器好比一座院子  IP地址比作院子大门;一座院子对应至少一个大门  每一个具体的服务程序进程好比一个房子  端口号好比进入房间的门 

    一个房间至少一个门 服务器程序可以决定由哪一个大门才能进入房间  以太网帧根据IP地址决定投递主机位置,端口决定数据报送达应用程 序映射  服务器内核接收的数据将根据端口进行路由传递到对应程序中
  2. Linux系统端口范围  默认范围:1~65535  0-1023已知端口,已被分配,需要ROOT权限  可被自由使用端口范围:65535 - 1024 ≈

    64000  查看Linux系统默认可使用端口范围: sysctl -a | grep 'net.ipv4.ip_local_port_range' 32768 61000  修改其端口范围: sysctl -w net.ipv4.ip_local_port_range=1024 65535  保存修改: sysctl -p 持久化
  3. 虚拟IP来帮忙  添加物理网卡,费时费劲,不太方便  可分配一个或多个IP地址给系统的虚拟IP,很方便!  Linux添加虚拟IP: ifconfig eth0:0 192.168.190.151

    netmask 255.255.255.0 up 写入/etc/rc.local里可防止重启后丢失  试试Docker 已经释出Docker 1.0,可以尝试一下
  4. 代码指定IP和端口  C语言如何做 struct sockaddr_in clnt_addr; clnt_addr.sin_addr.s_addr = inet_addr(server_ip); clnt_addr.sin_port

    = htons(server_port);  Java如何做 java.net.InetSocketAddress 此类实现 IP 套接字地址(IP 地址 + 端口号)。它还可以是一个对 (主机名 + 端口号),在此情况下,将尝试解析主机名。 如果解析失败,则该地址将被视为未解析地址,但是其在某些情形下 仍然可以使用,比如通过代理连接。  服务器程序可以绑定所有可用IP地址  客户端请求者只能绑定一个具体IP(若非手动指定,系统默认选择可 用IP)
  5. 指定已有程序绑定IP/端口?  已有程序,如何修改其绑定的IP地址和端口 ? 修改配置文件  试试linux系统的bindp小程序吧!  https://github.com/yongboy/bindp 

    可在运行之前硬绑定的指定IP和端口  原理: LD_PRELOAD,允许定义在程序运行前优先加载的动态链接库  如何使用: BIND_ADDR="your ip" BIND_PORT="your port" LD_PRELOAD=/your_path/bindp.so the real command ...
  6. bindp + nginx + curl的示范1  nginx默认80端口, 设置nginx以8888端口进行启动 BIND_PORT="8888" LD_PRELOAD=/home/yongboy/bindp/bindp.so

    /usr/sbin/nginx -c /etc/nginx/nginx.conf  测试端准备 绑定特定IP和端口: BIND_ADDR="192.168.192.141" BIND_PORT="16888" LD_PRELOAD=/home/yongboy/bindp/bindp.so curl http://192.168.192.130  nginx日志输出:
  7. bindp + nginx + curl的示范2  测试端第一次请求 BIND_ADDR="192.168.192.141" BIND_PORT="16888" LD_PRELOAD=/home/yongboy/bindp/bindp.so

    curl http://192.168.192.130  测试端第二次请求(间隔很短,不超过10秒钟) BIND_ADDR="192.168.192.141" BIND_PORT="16888" LD_PRELOAD=/home/yongboy/bindp/bindp.so curl http://192.168.192.130  持续观察Nginx日志输出
  8. 占用端口何时释放?  测试端连接虽已关闭,但被占用端口系统不会立即释放  主动关闭方产生TIME_WAIT  TIME_WAIT需要等待分组彻底消失,2倍MSL(Maximum Segment Life), 1MSL

    = 30s(Linux系统)  sysctl -a | grep net.ipv4.tcp_fin_timeout net.ipv4.tcp_fin_timeout = 60  原因: 1)TIME_WAIT可确保系统有足够时间让对端收到Fin ACK,如果 对方没有收到Fin Ack,会触发重发Fin ACK,2个MSL时间周期 2)系统有足够的时间让已关闭的连接不会跟后面的连接混淆(避免 连接被重用时,可能路由器层面缓存IP数据包,导致混淆) 3)TIME_WAIT下一站是真正的关闭
  9. 服务器程序地址重用  服务器程序启动时需要显式标注自身需要地址重用  C语言版: int reuseaddr_on = 1; if

    (setsockopt(listen_fd, SOL_SOCKET, SO_REUSEADDR, &reuseaddr_on, sizeof(reuseaddr_on))) err(1, "setsockopt failed");  Java&Netty 版本  Java: ServerSocket socket = new ServerSocket(); socket.setReuseAddress(true);  Netty 3.x bootstrap.setOption("reuseAddress", true);  Netty 4.x/5.x ServerBootstrap server = new ServerBootstrap(); server.group(bossGroup, workerGroup) .option(ChannelOption.SO_REUSEADDR, true);  演示实际效果 ?
  10. 服务器程序地址重用2  不指定地址重用,在短时间内(60S内)再次重启: server: bind failed: Address already in use

     地址重用  可以快速重启  同一端口可以被多次使用,但需要绑定到不同IP上  不同IP绑定同一端口  绑定不存在的IP地址: bind failed: Cannot assign requested address  不指定具体IP,意味着继续使用默认IP,其它进程绑定端口 bind failed: Address already in use  已绑定的指定IP和端口,其它进程再次绑定: bind failed: Address already in use
  11. 服务器如何快速回收端口?  Linux系统默认值:  net.ipv4.tcp_tw_reuse = 0  net.ipv4.tcp_tw_recycle =

    0  默认都是关闭  tcp_tw_recycle,比较激进,若开启需同时设置 tcp_timestamps=1  不建议修改  修改可能会产生意想不到的问题  服务器端尽量不要主动关闭连接