基于TCP协议的socket程序函数调用过程

socket需要指定协议是IPv4还是IPv6,分别设置AF_INET和AF_INET6。设置指定TCP协议还是UDP协议。如果是TCP,则参数要设置成SOCK_STREAM,UDP的则要设置成SOCK_DGRAM。

对于TCP:

服务端监听一个端口,调用bind()函数绑定服务端的IP地址和端口号。之后进入监听状态等待客户端的连接以及已连接的客户端发送数据。

在内核中,为每个socket维护两个队列:

  • 一个是已经建立连接的队列,这些连接已经完成了三次握手,处于established状态;
  • 另一个队列是没有完全建立连接的队列,这些连接三次握手还没完成,处于syn_rcvd状态。

客户端通过connect函数发起连接,connect函数中要配置好客户端的IP地址以及端口号,然后发起三次握手。当有新的请求时,服务端调用accept函数来处理请求。内核会为客户端分配一个临时端口,一旦握手完成,服务端的accept会返回另一个socket——即监听的socket和连接的socket的俩socket。

连接建立成功之后,双方通过read函数和write函数进行读写数据,就像往文件中读写一样。

socket在linux中以文件形式存在,其对应一个文件描述符,每个进程都有数据结构task_struct里面指向一个文件描述符数组,文件描述符是一个整数,是这个数组的下标。数组中的内容是一个指针,指针指向内核中所打开的文件列表

既然是文件,就会有一个inode,socket对应的inode存放在内存中,而不像其他文件存放在硬盘上。这个inode中,指向了socket在内核中的socket结构。在这个结构里,有两个队列,

  • 一个是发送队列
  • 一个是接受队列

这两个队列中保存的是一个缓存sk_buff。这个缓存里面能够看到完整的包的结构。

整个数据结构图:

对于UDP:

UDP不是面向连接,因此没有三次握手,也不需要调用listen和connect函数。UDP不用维护连接状态,因此不需要没对连接都建立一组socket,而是只需要一个socket,就可以和多个客户端进行通信。也是因为没有连接状态,因此每次通信时,都是调用sendtorecvfrom函数,都可以传入IP地址和端口号。

服务器如何连接更多的项目?

最大连接数的计算

系统会用一个四元组来标识一个TCP连接。

{本机 IP, 本机端口, 对端 IP, 对端端口}

                                                  最大 TCP 连接数 = 客户端 IP 数×客户端端口数

对于IPv4,客户端的IP数最多为2的32次幂,客户端的端口上=数最多为2的16次方,也就是服务端单击最大TCP连接数,约为2的

48次幂。

服务器最大并发TCP连接数不能达到理论上限,因为:

  • 文件描述符的限制。socket都是文件,索引首先通过ulimit配置文件描述符的个数
  • 另一个限制是内存,每个TCP链接都要占用一定的内存,操作系统是有限的

想要实现高并发,可以通过以下四种方式:

1、多进程

每来一个新的连球,就将基于已连接socket的交互交给这个新的子进程来自做。

linux下,通过fork创建子进程。内核会复制文件描述符的列表复制内存空间,还会复制一条记录当前执行到了哪一行程序的进程。通过fork的返回值可以判断当前进程是父进程(pid!=0)还是子进程(pid=0)。

因为复制了文件描述符表,而文件描述符都是指向整个内核统一的打开的文件列表的,因为父进程刚才因为accept创建的已连接socket也是一个文件描述符,同样也会被子进程获得。

接下来,子进程可以通过这个已经连接的socket和客户端进行通信了。通信完毕之后,可以退出进程。父进程可以通过子进程的进程号查看子进程是否退出。

2、多线程

linux下通过pthread_create创建一个线程,也是调用do_fork。不同的是,虽然新的线程在task列表会新创建一项,但是很多资源,如文件描述符列表、进程空间,还是共享的,只不过多了一个引用而已

新的线程也可以通过已连接socket处理请求,从而达到并发处理的目的。

3、IO多路复用,一个线程维护多个socket——select

由于socket的文件描述符,将文件描述符都放在文件描述符集合fd_set中,然后调用select函数来监听文件描述符集合是否有变化。一旦有变化,就会依次查看每个文件描述符。那些发生变化的文件描述符在fd_set对应的位都设为1,表示socket可读或者可写,从而可以进行读写操作。然后调用select盯着下一轮的变化。

select的问题就是,每次都是通过轮询的方式查看发生变化的文件描述符,时间复杂度比较高,因此常常用FD_SETSIZE限制。

4、IO多路复用——epoll

不需要通过轮询的方式来查看变化。发生变化的文件描述符会主动通知。epoll在内核中的实现不是通过轮询的方式,而是通过注册callback函数的方式,当某个文件描述符发生变化,就会主动通知

如图,进程打开了socket m,n,x等多个文件描述符,现在通过epoll来监听这些socket都有事件发生。其中,epoll_create创建一个epoll对象,也就是一个文件,也对应一个文件描述符,该文件描述符也对应着打开文件列中的一项。在这项里有一个红黑树,在红黑树里,保存这个epoll监听的所有socket。

当epoll_ctl添加一个socket的时候,其实是加入这个红黑树,同时红黑树里面的节点指向一个结构,将这个结构挂在被监听的socket的事件列表中。当一个socket带来一个事件的时候,可以从这个列表中得到epoll对象,并调用call back通知他。

这种通知方式使得监听的socket数据增加的时候,效率不会大幅度降低,能够同时监听的socket的数目非常多。上限就为系统定义的、进程打开的最大文焕描述符个数。

网络协议梳理(四)(socket、想要实现高并发,可以通过以下四种方式)相关推荐

  1. Linux进程最大socket数,Linux下高并发socket最大连接数所受的各种限制(详解)

    1.修改用户进程可打开文件数限制 在Linux平台上,无论编写客户端程序还是服务端程序,在进行高并发TCP连接处理时,最高的并发数量都要受到系统对用户单一进程同时可打开文件数量的限制(这是因为系统为每 ...

  2. Python高并发应用场景下四种写入SQLite数据库的速度比较

    "Python小屋"编程比赛正式开始 中国大学MOOC"Python程序设计基础"第5次开课 推荐图书: <Python程序设计基础(第2版)>,I ...

  3. 一个普通人,想改变命运,最靠谱的3种方式

    刚出社会的年轻人,都是心比天高的. 没有谁会承认自己比别人差,不信你去找人问问,不管当下混得如何,他一定相信自己以后肯定会赚大钱. 但生活却不是靠想象出来的. 现实情况是,很多人工作了多年,也只能拿个 ...

  4. 通用网络验证系统,承载能力强,支持高并发、高承载、多线路

    这个网络验证系统基于Php+MySql数据库架构的网络验证系统,安全稳定.性能强悍. 承载能力强,支持高并发.高承载.多线路,支持服务器集群架设,高性能设计,速度非常快,效率非常高. 客户端支持VC. ...

  5. 网络协议梳理(三)(网关和路由器、动态路由算法、Bellman-Ford算法、Dijkstra算法、动态路由协议、TCP和UDP)

    MAC 头和 IP 头的细节 在任何一台机器上,当要访问另一个IP地址的时候,都会使用CIDR和子网掩码去判断目标IP地址和当前机器的IP地址是否属于同一网段. 如果是同一网段--如果ARP缓存中存有 ...

  6. [ 网络协议篇 ] IGP 详解之 OSPF 详解(二)--- 四种网络类型 虚链路 详解

  7. 高并发负载均衡(四):基于keepalived的LVS高可用搭建

    LVS四层 & Nginx七层 对比 你要分清哪些程序是应用层的,哪些程序是内核的. LVS四层负载均衡服务器,是不会碰握手这一个步骤的. Nginx是基于反向代理(七层)的负载均衡服务器,要 ...

  8. 聊聊高并发(二十四)解析java.util.concurrent各个组件(六) 深入理解AQS(四)

    最近整体过了下AQS的结构,也在网上看了一些讲AQS的文章,大部分的文章都是泛泛而谈.重新看了下AQS的代码,把一些新的要点拿出来说一说. AQS是一个管程,提供了一个基本的同步器的能力,包含了一个状 ...

  9. 趣谈网络协议笔记 - 从二层到三层

    第五讲 从物理层到MAC层 第一层(物理层)   电脑连电脑,除了网线要交叉,还需要配置这两台电脑的 IP 地址.子网掩码和默认网关.这三个概念上一节详细描述过了.要想两台电脑能够通信,这三项必须配置 ...

  10. 网络协议枯燥难学?这个胖子要说No!

    参加过大厂面试的小伙伴应该都清楚,无论是去面试国内的互联网大厂还是硅谷的IT公司,面试的时候多多少少都会问一些网络协议的知识.例如: 1. TCP协议和UDP协议有什么区别? 2. HTTPS协议的底 ...

最新文章

  1. Spring中@Autowired注解、@Resource注解的区别
  2. Android获取顶部状态栏statusBar高度、底部导航栏navigationBar高度
  3. numba.jit警告:warnings.warn(errors.NumbaDeprecationWarning(msg, state.func_ir.loc))
  4. 区块链基础知识系列 第二课 区块链共识算法
  5. Android版本演进中的兼容性问题
  6. R语言︱集合运算——小而美法则
  7. 浅谈JavaScript代码预解析 + 示例详解
  8. python流程图自动生成_python自动化办公 自动生成PPT通报
  9. Linux 安装 OFFICE 2007
  10. 公众号网页能调用银联支付么_支付宝新一代刷脸支付硬件发布,自带“轮子”,三天就能开发小程序...
  11. 将VS2010的工程转换为VS2005,即用VS2005打开
  12. flutter大小单位:dp
  13. Ubuntu系统清理瘦身
  14. Java岗史上最全八股文面试真题汇总,堪称2022年面试天花板
  15. 大小写字母的ASCII的对照转换
  16. Android L 的手机,安卓新系统Android L上手评测:改变很大
  17. 使用MATLAB快速提取图片数据
  18. 【C语言】字符串函数详解
  19. Neo4j入门之中国电影票房排行浅析
  20. java并发工具包-ReadWriteLock

热门文章

  1. vue使用ntko控件完成word上传、html上传
  2. java往json里添加对象_将新数组元素添加到JSON对象
  3. Redis 设计与实现
  4. .config文件相关说明
  5. 2021年上半年系统分析师下午真题和答案解析
  6. kepware mysql_Kepware实现向数据库实时写入数据
  7. SitePoint播客#114:在WordCamp Raleigh上直播第1部分
  8. 标准输入输出流OutputStreamWriter:将字节输出流转换为字符输出流InputStreamReader:将字节输入流转换为字符输入流打印流添加输出数据的功能ObjectInputStrea
  9. 【C/C++笔记】之显式调用DLL、隐式调用DLL、查看DLL输出函数
  10. 什么软件能打开prt文件_prt文件怎么打开