socket跟TCP/IP 的关系,单台服务器上的并发TCP链接数能够有多少

常识一:文件句柄限制

在Linux下编写网络服务器程序的朋友确定都知道每个tcp链接都要占一个文件描述符,一旦这个文件描述符使用完了,新的链接到来返回给咱们的错误是“Socket/File: Can't open so many files”程序员

这时你须要明白操做系统对能够打开的最大文件数的限制。面试

  • 进程限制编程

    • 执行ulimit -n 输出1024,说明对于一个进程而言最多只能打开1024个文件,因此你要采用此默认配置最多也就能够并发上千个TCP链接。服务器

    • 临时修改:ulimit -n1000000,可是这种临时修改只对当前登陆用户目前的使用环境有效,系统重启或用户退出后就会失效。网络

    • 永久修改:编辑/etc/security/limits.conf 文件, 修改后内容为多线程

      * soft nofile 1000000并发

      * hard nofile 1000000socket

     

  • 全局限制tcp

    • 执行 cat/proc/sys/fs/file-nr 输出9344 0592026,分别为:1.已经分配的文件句柄数,2.已经分配但没有使用的文件句柄数,3.最大文件句柄数。但在kernel2.6版本中第二项的值总为0,这并非一个错误,它实际上意味着已经分配的文件描述符无一浪费的都已经被使用了 。函数

    • 咱们能够把这个数值改大些,用 root 权限修改 /etc/sysctl.conf 文件:

      fs.file-max = 1000000

      net.ipv4.ip_conntrack_max = 1000000

      net.ipv4.netfilter.ip_conntrack_max = 1000000

常识二:端口号范围限制?

操做系统上端口号1024如下是系统保留的,从1024-65535是用户使用的。因为每一个TCP链接都要占一个端口号,因此咱们最多能够有60000多个并发链接。我想有这种错误思路朋友不在少数吧?(我过去就一直这么认为)

咱们来分析一下吧

  • 如何标识一个TCP链接:系统用一个4四元组来惟一标识一个TCP链接:{local ip, local port,remoteip,remoteport}。好吧,咱们拿出《UNIX网络编程:卷一》第四章中对accept的讲解来看看概念性的东西,第二个参数cliaddr表明了客户端的ip地址和端口号。而咱们做为服务端实际只使用了bind时这一个端口,说明端口号65535并非并发量的限制。

  • server最大tcp链接数:server一般固定在某个本地端口上监听,等待client的链接请求。不考虑地址重用(unix的SO_REUSEADDR选项)的状况下,即便server端有多个ip,本地监听端口也是独占的,所以server端tcp链接4元组中只有remoteip(也就是client ip)和remoteport(客户端port)是可变的,所以最大tcp链接为客户端ip数×客户端port数,对IPV4,不考虑ip地址分类等因素,最大tcp链接数约为2的32次方(ip数)×2的16次方(port数),也就是server端单机最大tcp链接数约为2的48次方。


要写网络程序就必须用Socket,这是程序员都知道的。并且,面试的时候,咱们也会问对方会不会Socket编程?通常来讲,不少人都会说,Socket编程基本就是listen,accept以及send,write等几个基本的操做。是的,就跟常见的文件操做同样,只要写过就必定知道。
对于网络编程,咱们也言必称TCP/IP,彷佛其它网络协议已经不存在了。对于TCP/IP,咱们还知道TCP和UDP,前者能够保证数据的正确和可靠性,后者则容许数据丢失。最后,咱们还知道,在创建链接前,必须知道对方的IP地址和端口号。除此,普通的程序员就不会知道太多了,不少时候这些知识已经够用了。最多,写服务程序的时候,会使用多线程来处理并发访问。
咱们还知道以下几个事实:
1。一个指定的端口号不能被多个程序共用。好比,若是IIS占用了80端口,那么Apache就不能也用80端口了。
2。不少防火墙只容许特定目标端口的数据包经过。
3。服务程序在listen某个端口并accept某个链接请求后,会生成一个新的socket来对该请求进行处理。
因而,一个困惑了我好久的问题就产生了。若是一个socket建立后并与80端口绑定后,是否就意味着该socket占用了80端口呢?若是是这样的,那么当其accept一个请求后,生成的新的socket到底使用的是什么端口呢(我一直觉得系统会默认给其分配一个空闲的端口号)?若是是一个空闲的端口,那必定不是80端口了,因而之后的TCP数据包的目标端口就不是80了--防火墙必定会组织其经过的!实际上,咱们能够看到,防火墙并无阻止这样的链接,并且这是最多见的链接请求和处理方式。个人不解就是,为何防火墙没有阻止这样的链接?它是如何断定那条链接是由于connet80端口而生成的?是否是TCP数据包里有什么特别的标志?或者防火墙记住了什么东西?
后来,我又仔细研读了TCP/IP的协议栈的原理,对不少概念有了更深入的认识。好比,在TCP和UDP同属于传输层,共同架设在IP层(网络层)之上。而IP层主要负责的是在节点之间(End 

to End)的数据包传送,这里的节点是一台网络设备,好比计算机。由于IP层只负责把数据送到节点,而不能区分上面的不一样应用,因此TCP和UDP协议在其基础上加入了端口的信息,端口因而标识的是一个节点上的一个应用。除了增长端口信息,UPD协议基本就没有对IP层的数据进行任何的处理了。而TCP协议还加入了更加复杂的传输控制,好比滑动的数据发送窗口(Slice Window),以及接收确认和重发机制,以达到数据的可靠传送。无论应用层看到的是怎样一个稳定的TCP数据流,下面传送的都是一个个的IP数据包,须要由TCP协议来进行数据重组。因此,我有理由怀疑,防火墙并无足够的信息判断TCP数据包的更多信息,除了IP地址和端口号。并且,咱们也看到,所谓的端口,是为了区分不一样的应用的,以在不一样的IP包来到的时候可以正确转发。TCP/IP只是一个协议栈,就像操做系统的运行机制同样,必需要具体实现,同时还要提供对外的操做接口。就像操做系统会提供标准的编程接口,好比Win32编程接口同样,TCP/IP也必须对外提供编程接口,这就是Socket编程接口--原来是这么回事啊!在Socket编程接口里,设计者提出了一个很重要的概念,那就是socket。这个socket跟文件句柄很类似,实际上在BSD系统里就是跟文件句柄同样存放在同样的进程句柄表里。这个socket实际上是一个序号,表示其在句柄表中的位置。这一点,咱们已经见过不少了,好比文件句柄,窗口句柄等等。这些句柄,实际上是表明了系统中的某些特定的对象,用于在各类函数中做为参数传入,以对特定的对象进行操做--这实际上是C语言的问题,在C++语言里,这个句柄其实就是this指针,实际就是对象指针啦。如今咱们知道,socket跟TCP/IP并无必然的联系。Socket编程接口在设计的时候,就但愿也能适应其余的网络协议。因此,socket的出现只是能够更方便的使用TCP/IP协议栈而已,其对TCP/IP进行了抽象,造成了几个最基本的函数接口。好比create,listen,accept,connect,read和write等等。如今咱们明白,若是一个程序建立了一个socket,并让其监听80端口,实际上是向TCP/IP协议栈声明了其对80端口的占有。之后,全部目标是80端口的TCP数据包都会转发给该程序(这里的程序,由于使用的是Socket编程接口,因此首先由Socket层来处理)。所谓accept函数,其实抽象的是TCP的链接创建过程。accept函数返回的新socket其实指代的是本次建立的链接,而一个链接是包括两部分信息的,一个是源IP和源端口,另外一个是宿IP和宿端口。因此,accept能够产生多个不一样的socket,而这些socket里包含的宿IP和宿端口是不变的,变化的只是源IP和源端口。这样的话,这些socket宿端口就能够都是80,而Socket层仍是能根据源/宿对来准确地分辨出IP包和socket的归属关系,从而完成对TCP/IP协议的操做封装!而同时,放火墙的对IP包的处理规则也是清晰明了,不存在前面设想的种种复杂的情形。明白socket只是对TCP/IP协议栈操做的抽象,而不是简单的映射关系,这很重要!

相关文章
相关标签/搜索