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

Linux系统服务端口的那些事

yongboy
June 28, 2014

 Linux系统服务端口的那些事

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

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  不建议修改  修改可能会产生意想不到的问题  服务器端尽量不要主动关闭连接