100万并发连接服务器笔记之处理端口数量受限问题

第二个遇到的问题:端口数量受限

一般来说,单独对外提供请求的服务不用考虑端口数量问题,监听某一个端口即可。但是向提供代理服务器,就不得不考虑端口数量受限问题了。当前的1M并发连接测试,也需要在客户端突破6万可用端口的限制。

单机端口上限为65536

端口为16进制,那么2的16次方值为65536,在linux系统里面,1024以下端口都是超级管理员用户(如root)才可以使用,普通用户只能使用大于1024的端口值。 
系统提供了默认的端口范围:

cat /proc/sys/net/ipv4/ip_local_port_range 
32768 61000

大概也就是共61000-32768=28232个端口可以使用,单个IP对外只能发送28232个TCP请求。 
以管理员身份,把端口的范围区间增到最大:

echo "1024 65535"> /proc/sys/net/ipv4/ip_local_port_range

现在有64511个端口可用. 
以上做法只是临时,系统下次重启,会还原。 更为稳妥的做法是修改/etc/sysctl.conf文件,增加一行内容

net.ipv4.ip_local_port_range= 1024 65535

保存,然后使之生效:

sysctl -p

现在可以使用的端口达到64510个(假设系统所有运行的服务器是没有占用大于1024的端口的,较为纯净的centos系统可以做到),要想达到50万请求,还得再想办法。

增加IP地址

一般假设本机网卡名称为 eth0,那么手动再添加几个虚拟的IP:

ifconfig eth0:1 192.168.190.151 
ifconfig eth0:2 192.168.190.152 ......

或者偷懒一些:

for i in `seq 1 9`; do ifconfig eth0:$i 192.168.190.15$i up ; done

这些虚拟的IP地址,一旦重启,或者 service network restart 就会丢失。

为了模拟较为真实环境,在测试端,手动再次添加9个vmware虚拟机网卡,每一个网卡固定一个IP地址,这样省去每次重启都要重新设置的麻烦。

192.168.190.134 
192.168.190.143
192.168.190.144
192.168.190.145
192.168.190.146
192.168.190.147
192.168.190.148
192.168.190.149
192.168.190.150
192.168.190.151

在server服务器端,手动添加桥接网卡和NAT方式网卡

192.168.190.230
192.168.190.240
10.95.20.250

要求测试端和服务器端彼此双方都是可以ping通。

网络四元组/网络五元组

四元组是指的是

{源IP地址,源端口,目的IP地址,目的端口}

五元组指的是(多了协议)

{源IP地址,目的IP地址,协议号,源端口,目的端口}

在《UNIX网络编程卷1:套接字联网API(第3版)》一书中,是这样解释:

一个TCP连接的套接字对(socket pari)是一个定义该连接的两个端点的四元组,即本地IP地址、本地TCP端口号、外地IP地址、外地TCP端口号。套接字对唯一标识一个网络上的每个TCP连接。

......

标识每个端点的两个值(IP地址和端口号)通常称为一个套接字。

以下以四元组为准。在测试端四元组可以这样认为:

{本机IP地址,本机端口,目的IP地址,目的端口}

请求的IP地址和目的端口基本上是固定的,不会变化,那么只能从本机IP地址和本机端口上考虑,端口的范围一旦指定了,那么增加IP地址,可以增加对外发出的请求数量。假设系统可以使用的端口范围已经如上所设,那么可以使用的大致端口为64000个,系统添加了10个IP地址,那么可以对外发出的数量为 64000 * 10 = 640000,数量很可观。

只有{源IP地址,源端口}确定对外TCP请求数量

经测试,四元组里面,只有{源IP地址,源端口}才能够确定对外发出请求的数量,跟{目的IP地址,目的端口}无关。

测试环境

在server端,并且启动./server两次,分别绑定8000端口和9000端口

./server -p 8000
./server -p 9000

本机IP、端口绑定测试程序

这里写一个简单的测试绑定本机IP地址和指定端口的客户端测试程序。

可以看到libevent-*/include/event2/http.h内置了对绑定本地IP地址的支持:

/** sets the ip address from which http connections are made */
void evhttp_connection_set_local_address(struct evhttp_connection *evcon,
const char *address);

不用担心端口,系统自动自动随机挑选,除非需要特别指定:

/** sets the local port from which http connections are made */
void evhttp_connection_set_local_port(struct evhttp_connection *evcon,
ev_uint16_t port);

编译

gcc -o client3 client3.c -levent

client3运行参数为

  • -h 远程主机IP地址
  • -p 远程主机端口
  • -c 本机指定的IP地址(必须可用)
  • -o 本机指定的端口(必须可用)

测试用例,本机指定同样的IP地址和端口,但远程主机和IP不一样. 
在一个测试端打开一个终端窗口1,切换到 client3对应位置

./client3 -h 192.168.190.230 -p 8000 -c 192.168.190.148 -o 4000

输出为

remote host is 192.168.190.230
remote port is 8000
local ip is 192.168.190.148
local port is 4000
>Chunks: 1 Bytes: 505

再打开一个测试端终端窗口2,执行:

./client3 -h 192.168.190.240 -p 9000 -c 192.168.190.148 -o 4000

窗口2程序,无法执行,自动退出。 
接着在窗口2终端继续输入:

./client3 -h 192.168.190.230 -p 8000 -c 192.168.190.148 -o 4001

注意,和窗口1相比,仅仅改变了端口号为4001。但执行结果,和端口1输出一模一样,在等待接收数据,没有自动退出。

剩下的,无论怎么组合,怎么折腾,只要一对{本机IP,本机端口}被占用,也就意味着对应一个具体的文件句柄,那么其它程序将不能够再次使用。

Java怎么绑定本地IP地址?

java绑定就很简单,但有些限制,不够灵活,单纯从源码中看不出来,api doc可以告诉我们一些事情。 打开JDKAPI1_6zhCN.CHM,查看InetSocketAddress类的构造函数说明:

public InetSocketAddress(InetAddress addr, int port) 
根据 IP 地址和端口号创建套接字地址。 有效端口值介于 0 和 65535 之间。端口号 zero 允许系统在 bind 操作中挑选暂时的端口。

null 地址将分配通配符 地址。

参数: 
addr - IP 地址 
port - 端口号 
抛出: 
IllegalArgumentException - 如果 port 参数超出有效端口值的指定范围。


public InetSocketAddress(String hostname, int port) 
根据主机名和端口号创建套接字地址。 
尝试将主机名解析为 InetAddress。如果尝试失败,则将地址标记为未解析。

如果存在安全管理器,则将主机名用作参数调用其 checkConnect 方法,以检查解析它的权限。这可能会导致 SecurityException 异常。

有效端口值介于 0 和 65535 之间。端口号 zero 允许系统在 bind 操作中挑选暂时的端口。

参数: hostname - 主机名 
port - 端口号 
抛出: 
IllegalArgumentException - 如果 port 参数超出有效端口值的范围,或者主机名参数为 null。 
SecurityException - 如果存在安全管理器,但拒绝解析主机名的权限。 
另请参见: 
isUnresolved()

InetSocketAddress的两个构造函数都支持,看情况使用。注意int port传递值为0,即可做到系统随机挑选端口。追踪一下源代码,发现最终调用

private native void socketBind(InetAddress address, int port) throws IOException;

如何查看socketBind的原始C代码,我就不清楚了,您若知晓,希望指教一下。 构造一个InetSocketAddress对象:

SocketAddress localSocketAddr = new InetSocketAddress("192.168.190.143", 0);

然后传递给需要位置即可。诸如使用netty连接到某个服务器上,在connect时指定远方地址,以及本机地址

ChannelFuture connect(SocketAddress remoteAddress, SocketAddress localAddress) Attempts a new connection with the specified remoteAddress and the specified localAddress.

Netty 客户端连接API见: <ahref="http: docs.jboss.="" org="" netty="" 3.="" 2="" api="" jboss="" bootstrap="" clientbootstrap.html"="">http://docs.jboss.org/netty/3.2/api/org/jboss/netty/bootstrap/ClientBootstrap.html

Linux支持绑定本机IP、端口原理

说是原理,有些牵强,因为linux C提供了如何绑定函数,框架或者高级语言再怎么封装,在linux平台下面,需要这么调用:

struct sockaddr_in clnt_addr;
....
clnt_addr.sin_family = AF_INET;
clnt_addr.sin_addr.s_addr = INADDR_ANY; //绑定本机IP地址
clnt_addr.sin_port = htons(33333); //绑定本机端口
if (bind(sockfd, (struct sockaddr *) &clnt_addr,
sizeof(clnt_addr)) < 0) error("ERROR on binding");
if (connect(sockfd,(struct sockaddr *) &serv_addr,sizeof(serv_addr)) < 0) error("ERROR connecting");
.......

构造一个clnt_addr结构体,本地IP或者端口赋值,在connect之前,先bind,就这么简单。

更完整例子,可以参考 http://stackoverflow.com/questions/4852256/need-a-complete-snippet-example-of-binding-tcp-client-socket

有关端口的更详细解释,请参考《UNIX网络编程卷1:套接字联网API(第3版)》2.9节 端口号部分。

有关端口的问题,到此为止,下一篇,回到测试。

转自:http://www.blogjava.net/yongboy/archive/2013/04/09/397594.html

Linux - TCP编程相关配置2的更多相关文章

  1. Linux - TCP编程相关配置1

    100万并发连接服务器笔记之1M并发连接目标达成 第四个遇到的问题:tcp_mem 在服务端,连接达到一定数量,诸如50W时,有些隐藏很深的问题,就不断的抛出来. 通过查看dmesg命令查看,发现大量 ...

  2. Linux环境编程相关的文章

    Linux环境编程相关的文章 好几年没有接触Linux环境下编程了,好多东西都有点生疏了.趁着现在有空打算把相关的一些技能重拾一下,顺手写一些相关的文章加深印象. 因为不是写书,也受到许多外部因素限制 ...

  3. Linux TCP队列相关参数的总结 转

        在Linux上做网络应用的性能优化时,一般都会对TCP相关的内核参数进行调节,特别是和缓冲.队列有关的参数.网上搜到的文章会告诉你需要修改哪些参数,但我们经常是知其然而不知其所以然,每次照抄过 ...

  4. Linux TCP队列相关参数的总结

    作者:阿里技术保障锋寒 原文:https://yq.aliyun.com/articles/4252 摘要: 本文尝试总结TCP队列缓冲相关的内核参数,从协议栈的角度梳理它们,希望可以更容易的理解和记 ...

  5. 使用VMware安装linux虚拟机以及相关配置

    前言 使用VMware安装虚拟机这个一般都知道,操作简单.而本文主要讲使用虚拟机的后续相关配置.并记录使用过程中遇到的问题以及一些技巧.本篇文章以后回持续更新的... 安装包准备 VM:12 Linu ...

  6. linux串口编程参数配置详解(转)

    1.linux串口编程需要的头文件 #include <stdio.h>         //标准输入输出定义#include <stdlib.h>        //标准函数 ...

  7. linux串口编程参数配置详解

    1.linux串口编程需要的头文件 #include <stdio.h>         //标准输入输出定义 #include <stdlib.h>        //标准函 ...

  8. linux中 systemd相关配置

    systemd相关配置 推荐使用systemd管理进程,相比使用supervisord systemd提供系统级别的支援. 一.系统管理 Systemd 并不是一个命令,而是一组命令,涉及到系统管理的 ...

  9. Linux网卡的相关配置总结

    当有多个网卡的时候,我们需要进行相关的配置. 一.如何改变网卡的名字? 修改/etc/udev/rules.d/70-persistent-net.rules 进去之后的效果是 根据mac地址,把没用 ...

随机推荐

  1. [LeetCode] 34. Find First and Last Position of Element in Sorted Array == [LintCode] 61. Search for a Range_Easy tag: Binary Search

    Description Given a sorted array of n integers, find the starting and ending position of a given tar ...

  2. visual studio 2017 (vs2017安装)

    vs2017要找到控制台模板,要安装模块: 安装完之后: 新建控制台项目: 不使用预编译头: 推荐安装官方扩展: https://marketplace.visualstudio.com/items? ...

  3. MSSqlServer 主从同步复制原理(发布/订阅)

    基本模型 1.发布类型: 快照发布:用于为事务复制和合并复制提供初始数据集:在适合数据完全刷新时也可以使用快照复制.利用这三种复制,SQL Server 提供功能强大且灵活的系统,以便使企业范围内的数 ...

  4. AutoMapper.Mapper.CreateMap报“System.NullReferenceException: 未将对象引用设置到对象的实例。”异常复现

    >>Agenda: >>Ⅰ.国庆假期问题出现 >>Ⅱ.双休日异常再次出现 >>Ⅲ.排障 >>Ⅳ.异常复盘 >>Ⅴ.修复后监测 & ...

  5. Hello world!(内含自己编写的C语言二叉树同学录)

      修改:刷了一段时间的题,水平渐涨,发现同学录真的要做成市面可行的应用的话,应该按学号建立二叉平衡树,红黑树是一个可行的选择. 在同学的推荐下,来到博客园来找志同道合的人交流代码.3个月后参加蓝桥杯 ...

  6. caffe中的caffemodel参数提取方法

    需要的文件为:deploy.prototxt caffemodel net = caffe.Net(deploy.txt,caffe_model,caffe.TEST)具体代码: import caf ...

  7. Unity shader学习之高光反射光照模型

    高光反射光照模型的公式如下: Cspecular = Clight * mspecular * max(0, dot(v, r))gloss 要计算高光反射需要知道4个参数:入射光线颜色Cspecul ...

  8. SpringBoot的json序列化及时间序列化处理

    使用场景:前台的多种时间格式存入后台,后台返回同时的时间格式到前台. 1 在config目录下配置jscksonConfig.java package com.test.domi.config; im ...

  9. X.509证书及CeritificationPath及PKCS

    X.509,数字证书标准.X.509用在包含SSL/TLS在内的很多网络协议中,证书内部包含一个public key和一个identity(hostname,organization等). X.509 ...

  10. 【impala学习之二】impala 使用

    环境 虚拟机:VMware 10 Linux版本:CentOS-6.5-x86_64 客户端:Xshell4 FTP:Xftp4 jdk8 CM5.4 一.Impala shell 1.进入impal ...