网络编程14

jdk下的bio

SocksSocketImpl

  • 这两类操作系统都还存在一个 SocksSocketImpl 类,它其实主要是实现了防火墙安全会话转换协议,包括 SOCKS V4 和 V5(SOCKS:防火墙安全会话转换协议 (Socks: Protocol for sessions traversal across firewall securely) SOCKS 协议提供一个框架,为在 TCP 和 UDP 域中的客户机/服务器应用程序能更方便安全地使用网络防火墙所提供的服务,并提供一个通用框架来使这些协议安全透明地穿过防火墙) 。

AbstractPlainSocketImpl

  • doConnect

    • socketConnect,在linux下由原生方法实现
  • 其它的bind、create都是类似的,最后用原生方法实现的

  • AbstractPlainSocketImpl只是linux下网络编程的浅包装

  • 这个类是很简单的,只是定义了socket相关的框架,都是由子类里面具体的方法实现

ServerSocket

  • 有五种构造方法

    • (1.)backlog是连接数,在tcp协议三次握手时,当前用来保存已经建立连接的、以及正在建立连接的,backlog主要是对这两个队列进行控制,具体大小跟操作内核相关,有的是乘二,有的是直接相加。

      (2).backlog的默认值只有5

    • setImpl()

      (1).设置socket的实际实现对象

      (2).

      private void setImpl() {
              if (factory != null) {
                  impl = factory.createSocketImpl();
                  checkOldImpl();
              } else {
                  // No need to do a checkOldImpl() here, we know it's an up to date
                  // SocketImpl!
                  impl = new SocksSocketImpl();
              }
              if (impl != null)
                  impl.setServerSocket(this);
          }
      

      不过 ServerSocket 和 Socket 为何要使用 SocksSocketImpl ?这是很古怪的行为,具体原 因没有官方解释,目前比较合理的推测是: 这是从 JDK1.4 保持下来的传统,对代理服务器连接的实验性支持。在实际环境中,JRE可能已经通过系统属性-DsocksProxyHost 和-DsocksProxyPort 或 ProxySelector.setDefault()或通过 JRE 安装的默认 ProxySelect 从外部配置为使用 SOCKS 进行代理。但是 PlainSocketImpl 不会参考这些属性或类,所以这些外部配置将被忽略不起作用,而 SocksSocketImpl 则会进行检查。

PlainSocketImpl

  • 在 Linux 下 JDK 的 PlainSocketImpl 非常简单,直接调用 JDK 中的 native 方法。并最终调用了操作系统的相关方法。

Linux 下的 IO 复用编程

select

  • int select (int n, fd_set *readfds, fd_set *writefds, fd_set *exceptfds, struct timeval *timeout);
    
    • readfds是可读的、writefds是可写的、exceptfds是异常的fds
  • 所以操作系统都提供了支持

  • select能监视的文件描述符是有限的,是1024,虽然可以修改,但是select机制在文件描述符很多的情况时效率会越来越低

poll

  • int poll (struct pollfd *fds, unsigned int nfds, int timeout);
    
  • 和select基本一样

  • poll用一个结构体pollfd描述select中的3种文件描述符

  • 虽然监视的最大描述符没有限制,但是是用链表实现的,所以性能相比select并没有高很多,只是监视文件描述符相比select要多很多

epoll

  • int epoll_create(int size)int epoll_ctl(int epfd, int op, int fd, struct epoll_event *event)int epoll_wait(int epfd, struct epoll_event * events, int maxevents, int timeout);
    
  • 是linux2.6版本提出来的,是前两者的增强版本

  • 使用起来也比前两个更麻烦,有三个方法联合起来使用

    • epoll_create是创建一个epoll的句柄,注意epoll虽然经常用在网络读写,但是在linux角度,将epoll设计成一个文件系统,在net目录下找不到,而是在fs目录下

      1.什么是句柄?

      简单理解成JVM里面对象的引用,jvm的堆上面有很多对象,方法在线程栈上执行,通过引用可以找到相应的对象,而句柄也是类似的作用

    • epoll_ctl对指定的描述符执行某种相关的操作

      1.相当于在select中监听什么事件,服务器关心连接事件,socketChannel关心读写事件,会用register进行一个相关的注册,epoll_ctl就是进行一个相关注册,但不止是注册

      (1)epfd是上面epoll_create返回的句柄,op是当前要做什么事(增加、删除或修改),fd是监听的具体的文件描述符(对哪一个channel做监听),epoll_event是我们要监听什么事件

    • epoll_wait是获取fd所能获取到的io事件,events表示轮询出的事件集合,

      1.epoll_wait的返回值类似于之前用java写的selector.select()的返回值,是差不多的,告诉我们selector有多少通道就绪返回

    • 首先通过epoll_create创建相关的句柄,然后调用epoll_ctl在我们监视的fd上面进行相关事件的注册,相当于register,而epoll_wait则相当于select,epoll_create已经被jdk给隐藏并实现了。

epoll 高效原理和底层机制分析

  • 从网卡接受数据
    • 当计算机收到一个网络数据包,首先是网卡接受数据,通过硬件电路的传输写到内存中的某一个地址,中间牵扯到DMA传输、IO通道选择、中断等等,网卡最终会把数据写到内存,然后操作系统去读取它们
  • CPU如何知道接受了数据?
    • 使用中断机制
  • 进程阻塞
    • 创建进程后,需要分配一块内存
    • 但是进程被阻塞后,不占用cpu资源

进程阻塞

  • 当bio通讯时,某个进程A负责网络通讯,调用socket,绑定、接受连接、读数据read()

  • 既然read()方法是阻塞式io,网络上没有数据过来,read()方法会阻塞当前线程,直到有数据过来,进程A才会继续往下走

  • 操作系统是多任务系统,会出现进程切换,运行态是指线程获取到了cpu的使用权,正在执行的状态,当前线程处于等待状态,也就是阻塞状态,例如read()方法,当有数据来了,就会由阻塞状态转换成运行态

  • socket = new socket()		
    bind();
    accept();
    read();
    
    • 不仅是生成一个实例,还会创建一个由文件系统管理的文件,这个文件包括发送缓冲区、接受缓冲区、等待队列
    • 执行read()方法,在之前的场景中,进程A被阻塞,就会把进程A从内核空间的工作队列中移动到socket所属的等待队列中,所以进程A也就不会分配CPU资源

内核接收网络数据全过程

  • 当网络上游数据传递过来了,网卡接受数据,网卡写入数据,中断,通知CPU,CPU执行中断(硬中断和软中断)

  • 软中断会把网卡缓冲区里面的数据交给linux内核的协议栈处理以后,再交给内存中的应用程序本身的socket缓冲区里面去

  • 中断的过程除了说在socket接受缓冲区里面填入数据外,还有第二部,就是唤醒进程A,重新被挂到工作队列后面,操作系统又重新对进程A进行一个事件调度

  • 操作系统怎么知道接受到的数据,在协议栈解包后应该交给那个socket?

    • 端口号
    • 网络数据包包含ip地址和端口号,内核就可以通过端口号找到对应的socket

select方法

  • 对于服务器而言,一个应用程序同时会和很多客户端进行通讯,对于维护多个socket的情况,服务器应该怎么监视多个socket有没有数据需要处理?

    • // 同时监视多个socket
      int fds[] = 存放需要监听的socket
      while(1){
      	int n = select(...,fds,...);
      	for(int i=0;i < fds.count; i++){
      		if(FD_ISSET(fds[i],..)){
      			// fds[i]的数据处理
      		}
      	}
      }
      
    • 1.弄一个socket列表

    • 2.进程A是对应的服务器程序,它管理3个socket,调用select后,把进程A挂到每一个socket下面的等待列表中,如果有任意一个socket收到数据,唤醒进程A,并把进程A从所有socket的等待列表移除,现在需要把进程A重新放到操作系统的工作队列中,方便进程A对这些socket进行相关检查

    • 3.把这里面的socket全部遍历一遍,找到接受到数据的socket,然后做处理

  • 优点

    • 简单有效
  • 缺点

    • 1.有多少个socket需要监视,就需要把进程A加到多少个socket里面的等待列表,而进程A被唤醒后,又需要把进程A从监视的socket的等待列表中移除,所以需要两次遍历

    • 2.所谓的fds列表,需要监听的socket列表,每次都要从用户空间传递内核,所以也需要一定的开销

    • 所以fds[]列表不能超过1024,超过性能急速下降,但是操作简单,所以在所有系统上都适用

epoll的设计思路

  • 功能分离,select的一大缺陷把维护等待列表和进程阻塞合二为一了,每次调用select操作,这两步都要走,epoll就把这两个操作分开了

    • int epfd = epoll_create(...);
      epoll_ctl(epfd,...);//将所有需要监听的socket添加到epfd中
      while(1){
      	int n = epoll_wait(...);
      	for(接受到数据的socket){
      		// 处理
      	}
      }
      
    • 1.首先调用epoll_create拿到epfd文件句柄,具体的,会在系统内核产生一个eventpoll这么一个对象,而epfd指向eventpoll这个对象

    • 2.然后调用epoll_ctl()方法,把所有需要监听的socket添加到epfd中,假如现在有3个socket需要epoll监听,就把eventpoll放到这三个socket的等待队列上

    • 3.调用epoll_wait(),把进程A加到eventpoll的等待队列中,

    • 4.只处理接受到数据的socket,此处epoll内部维护一个就绪列表,避免不必要的遍历,具体的,如果某一个socket收到相关的数据,它不像select操作进程,而是在eventpoll里面创建一个rdlist的数据结构,而rdlist就会引用收到数据的socket,同时唤醒进程A,进入内核工作队列,进程A只需要读取rdlist,就知道哪些socket收到数据了

  • epoll里面,socket列表只需要传递一次,当进行数据遍历时,只需要遍历有数据变化的socket

    • epoll并不是在所有情况都比select效率高,在连接数少,并且socket都比较活跃,此时select效率可能更好
    • select只有一次系统调用,而epoll需要各种函数的回调,假如要维护十万个连接,select每次都要轮询十万个连接,找到其中二百个活跃的,效率会很低
  • rdllist用双向链表实现,eventpoll用红黑树实现

eventpoll

  • struct eventpoll {
    	/*
    	 * This mutex is used to ensure that files are not removed
    	 * while epoll is using them. This is held during the event
    	 * collection loop, the file cleanup path, the epoll file exit
    	 * code and the ctl operations.
    	 */
    	struct mutex mtx;
    
    	/* Wait queue used by sys_epoll_wait() */
    	wait_queue_head_t wq;
    
        // 红黑树
    	/* Wait queue used by file->poll() */
    	wait_queue_head_t poll_wait;
    
        // 双向链表
    	/* List of ready file descriptors */
    	struct list_head rdllist;
    
    	/* Lock which protects rdllist and ovflist */
    	rwlock_t lock;
    
    	/* RB tree root used to store monitored fd structs */
    	struct rb_root_cached rbr;
    
    	/*
    	 * This is a single linked list that chains all the "struct epitem" that
    	 * happened while transferring ready events to userspace w/out
    	 * holding ->lock.
    	 */
    	struct epitem *ovflist;
    
    	/* wakeup_source used when ep_scan_ready_list is running */
    	struct wakeup_source *ws;
    
    	/* The user that created the eventpoll descriptor */
    	struct user_struct *user;
    
    	struct file *file;
    
    	/* used to optimize loop detection check */
    	u64 gen;
    	struct hlist_head refs;
    
    #ifdef CONFIG_NET_RX_BUSY_POLL
    	/* used to track busy poll napi_id */
    	unsigned int napi_id;
    #endif
    
    #ifdef CONFIG_DEBUG_LOCK_ALLOC
    	/* tracks wakeup nests for lockdep validation */
    	u8 nests;
    #endif
    };
    
    

epitem—socket的包装节点

  • struct epitem {
    	union {
    		/* RB tree node links this structure to the eventpoll RB tree */
    		struct rb_node rbn;
    		/* Used to free the struct epitem */
    		struct rcu_head rcu;
    	};
    
    	/* List header used to link this structure to the eventpoll ready list */
    	struct list_head rdllink;
    
    	/*
    	 * Works together "struct eventpoll"->ovflist in keeping the
    	 * single linked chain of items.
    	 */
    	struct epitem *next;
    
    	/* The file descriptor information this item refers to */
    	struct epoll_filefd ffd;
    
    	/* List containing poll wait queues */
    	struct eppoll_entry *pwqlist;
    
    	/* The "container" of this item */
    	struct eventpoll *ep;
    
    	/* List header used to link this item to the "struct file" items list */
    	struct hlist_node fllink;
    
    	/* wakeup_source used when EPOLLWAKEUP is set */
    	struct wakeup_source __rcu *ws;
    
    	/* The structure that describe the interested events and the source fd */
    	struct epoll_event event;
    };
    
已标记关键词 清除标记
相关推荐
<p> <strong> </strong> </p> <p class="MsoNormal" style="text-align:left;margin-left:21pt;text-indent:21pt;"> <br /> </p> <p class="MsoNormal"> <strong><span style="font-size:18px;"></span></strong> </p> <p class="ql-long-24357476"> <strong><span style="font-size:18px;color:#E53333;"><strong>想学好</strong></span><strong><span style="font-size:18px;color:#E53333;">JAVA必须要报两万的培训班吗?</span></strong><span style="color:#E53333;"></span><span id="__kindeditor_bookmark_start_82__"></span><br /> </strong> </p> <p class="ql-long-24357476"> <span id="__kindeditor_bookmark_end_83__"></span><strong><span style="color:#337FE5;">【课程背景】</span></strong> </p> <p class="ql-long-24357476"> <strong>JAVA是市场份额最大的编程语言,每天各大招聘网站上都会有数万个JAVA开发工程师的在招岗位,但是JAVA的技术体系庞大复杂,要想扎实掌握JAVA不是一件容易的事,线上学习相比线下两万起的高昂费用便宜了很多,而且具备学习时间灵活的优势,但是线上学习的劣势也很明显,没有线下那种学习氛围,碰到问题没法解决,在家学习很容易偷懒,极简JAVA学习营充分考虑到这些问题,通过每日实战编程练习,分队pk,助教答疑,作业点评,作业讲解,项目答辩等诸多环节充分激发你的学习热情,解决你学习中碰到的问题,让你花十分之一的钱学到JAVA的精髓,开启你的人生逆袭之路。</strong> </p> <p class="ql-long-24357476"> <strong><br /> </strong> </p> <strong><span style="color:#337FE5;">【专项的贴心服务】</span> <p class="ql-long-24357476"> 1. 学练结合:定期布置视频任务和编程实战练习:通过每天的视频任务统一大家的进度,以便同学更好的交流,针对每天的任务会有相应的编程实战练习,通过练习内化知识。<br /> 2. 分队PK:将就业营的同学分成几队,通过作业统计表统计每队提交作业情况进行PK,激发你的学习动力。<br /> 3. 助教讲师答疑:碰到任何问题,发到群里,助教和讲师十分钟内帮你解决问题,扫清学习中的障碍。<br /> 4. 助教点评讲解作业:你每天提交作业都会有助教进行点评,让你知道有什么问题怎么解决,每三天一次视频讲解作业,互动解答问题<br /> 5. 项目答辩:每个阶段学完会有项目答辩,通过做项目巩固前一阶段的知识点,锻炼编码能力。 </p> <p class="ql-long-24357476"> <img src="https://img-bss.csdnimg.cn/202007070905305336.png" alt="" /> </p> <p class="ql-long-24357476"> <span style="color:#337FE5;">【往期训练营学习展示】</span> </p> <p class="ql-long-24357476"> <img src="https://img-bss.csdnimg.cn/202007070914574571.png" alt="" /> </p> <p class="ql-long-24357476"> <span style="color:#337FE5;">【套餐内容简介】</span> </p> <p class="ql-long-24357476"> 本套课以市场就业和职位需求为核心,从JAVA入门到多领域实战,设计出学习路线,共分为二十大模块,分别是:JAVA面向对象、Object类与常用API、集合框架、IO流、反射注解、多线程与网络编程、Object类与常用API等等。 </p> <p> 同时采用理论讲解加实战演练的方式,既能让学员听懂听明白达到理解透彻,又能够在一个个真实实战案例中,让学员掌握真正有用的开发技能,从而进阶 JAVA 工程师! </p> <p> <br /> </p> <p class="ql-long-24357476"> 套餐中一共包含21门JAVA程,助你从零进阶JAVA工程师! </p> <p class="ql-long-24357476"> <span style="color:#337FE5;">阶段一:</span><span style="color:#337FE5;">JAVA</span><span style="color:#337FE5;">基</span><span style="color:#337FE5;">础</span> </p> <p class="ql-long-24357476"> 课程1:《极简JAVA学习营开营篇》 </p> <p class="ql-long-24357476"> 课程2:《极简JAVA:JAVA面向对象》 </p> <p class="ql-long-24357476"> 课程3:《极简JAVA:Object类与常用API》 </p> <p class="ql-long-24357476"> 课程4:《极简JAVA:集合框架》 </p> <p class="ql-long-24357476"> 课程5:《极简JAVA:IO流》 </p> <p class="ql-long-24357476"> 课程6:《极简JAVA:反射注解》 </p> <p class="ql-long-24357476"> 课程7:《极简JAVA:多线程与网络编程》 </p> <p class="ql-long-24357476"> <span style="color:#337FE5;">阶段二:</span><span style="color:#337FE5;">数据库入门</span> </p> <p class="ql-long-24357476"> 课程8:《极简JAVA:MySql数据库》 </p> <p class="ql-long-24357476"> 课程9:《极简JAVA:JDBC与连接池》 </p> <p class="ql-long-24357476"> <span style="color:#337FE5;">阶段三:</span><span style="color:#337FE5;">JAVA WEB</span> </p> <p class="ql-long-24357476"> 课程10:《极简JAVA:HTML5与CSS3》 </p> <p class="ql-long-24357476"> 课程11:《极简JAVA:极简JAVA十一:Javascript与Jquery》 </p> <p> 课程12:《极简JAVA:BootStrap》 </p> <p class="ql-long-24357476"> 课程13:《极简JAVA:JAVA Web》 </p> <p class="ql-long-24357476"> <span style="color:#337FE5;">阶段四:框架实战</span> </p> <p class="ql-long-24357476"> 课程14:《极简JAVA:Mavean入门》 </p> <p class="ql-long-24357476"> 课程15:《极简JAVA:MyBatis框架》 </p> <p class="ql-long-24357476"> 课程16:《极简JAVA:Spring框架》 </p> <p class="ql-long-24357476"> 课程17:《极简JAVA:Spring Mvc》 </p> <p class="ql-long-24357476"> <span id="__kindeditor_bookmark_end_251__"></span><span id="__kindeditor_bookmark_end_247__"></span>课程18:《极简JAVA:Oracle数据库》 </p> <p class="ql-long-24357476"> 课程19:《极简JAVA:Git入门》 </p> <p class="ql-long-24357476"> 课程20:《极简JAVA:Linux入门》 </p> <p class="ql-long-24357476"> 课程21:《极简JAVA:SpringBoot》 </p> <p> <br /> </p> <p class="ql-long-24357476"> <span style="color:#337FE5;">【课程特色】</span> </p> <p class="ql-long-24357476"> 1、易理解:讲师思路清晰、节奏明确、从易到难讲解透彻明白; </p> <p class="ql-long-24357476"> 2、知识全:知识全面系统,从JAVA入门到实战,由易到难,让你彻底掌握JAVA开发; </p> <p class="ql-long-24357476"> 3、重实战:涵盖大量实战项目,锻炼你的动手实操能力,面向工作编程; </p> <p> <br /> </p> <p class="ql-long-24357476"> <span style="color:#337FE5;">【面向人群】</span> </p> <p class="ql-long-24357476"> 1、在校计算机专业或者对软件编程感兴趣的学生; </p> <p class="ql-long-24357476"> 2、零基础想学JAVA却不知道从何入手 </p> <p class="ql-long-24357476"> 3、囊中羞涩,面对两万起的JAVA培训班不忍直视 </p> <p class="MsoNormal"> 4、在职没有每天大块的时间专门学习JAVA </p> </strong>
©️2020 CSDN 皮肤主题: 深蓝海洋 设计师:CSDN官方博客 返回首页