epoll nio区别_【总结】两种 NIO 实现:Selector 与 Epoll

我想用这个话题小结下最近这一阶段的各种测试和开发。其实文章的内容主要还是想总结一下

NIO Socket

,以及两种不同操作系统实现

NIO

的方式,

selector

epoll

问题应该从服务器端开始说起。我们都写过net包下的socket,用socket的accept方法来等待客户端的请求,请求来了则处理,没有则一直等待,然后反复循环。这样的方式,类似于重用进程,要说线程也可以,始终就在这一条路上堵着。这样没有并发可言,我们想到了可以用多线程,用线程池的方式来解决这个问题。这样一般的小问题能解决了,100个初始化的线程,解决几千个连接应该没什么问题。可是,如果我做的是传输的项目呢,这100个线程还是阻塞的,第101个线程连接的时候,如果前面的100个都还在传输,那这第101个人还是在空等,而且他连个回音都不能收到。而且这样的方式实现起来并不怎么容易,虽然线程池有Exectors这样的类帮你生成,可是遇到共享变量和协同等问题还是很头疼。一个更好的做法是,模仿FTP一样,将指令与传输分开进行,一个端口负责简短的指令,尽可能的端连接,而其他端口处理业务。这样至少服务器能返回消息了。

第三种解决方案,多数情况下,也是最快的一种被提出来了,选择器selector。用一个线程来查询一组socket,找出已经准备好读写的,然后按顺序处理socket,当然这种实现方式的前提是IO必须使用通道和缓冲区而不是流。

用java来开发NIO socket的程序,最先要理解的还是各种概念。

通道channel,在NIO socket中使用到的通道有三个,SocketChannel、ServerSocketChannel、DatagramChannel。前两种基于TCP,最后一种一种用来实现UDP的通信。ServerSocketChannel不做任何数据上的处理,只是提供通道,负责连接。SocketChannel职责和net包下的socket类似,只不过这里是以通道的形势来对接。

缓冲区Buffer,这里最常用的还是ByteBuffer,在mina中使用的IoBuffer也是基于ByteBuffer实现的。它的好处是可以自己拼装去想到的数据。当然利用通道后数据切换的速度也会更快了。

要实现非阻塞IO最重要的还是选择器:

Selector

The Selector class manages information about a set of registered channels and their readiness states. Channels are registered with selectors, and a selector can be asked to update the readiness states of the channels currently registered with it. When doing so, the invoking thread can optionally indicate that it would prefer to be suspended until one of the registered channels is ready.

SelectableChannel

This abstract class provides the common methods needed to implement channel selectability. It's the superclass of all channel classes that support readiness selection. FileChannel objects are not selectable because they don't extend from SelectableChannel. All the socket channel classes are selectable, as well as the channels obtained from a Pipe object. SelectableChannel objects can be registered with Selector objects, along with an indication of which operations on that channel are of interest for that selector. A channel can be registered with multiple selectors, but only once per selector.

SelectionKey

A SelectionKey encapsulates the registration relationship between a specific channel and a specific selector. A SelectionKey object is returned from SelectableChannel.register( ) and serves as a token representing the registration. SelectionKey objects contain two bit sets (encoded as integers) indicating which channel operations the registrant has an interest in and which operations the channel is ready to perform.

Selector

管理被注册的通道的集合的信息和其就绪状态,同时也更新通道的就绪状态。并且一个通道可以被注册到多个选择器上,而对于同一个选择器则只能被注册一次。

import java.io.IOException;

import java.net.InetSocketAddress;

import java.net.ServerSocket;

import java.nio.ByteBuffer;

import java.nio.channels.SelectableChannel;

import java.nio.channels.SelectionKey;

import java.nio.channels.Selector;

import java.nio.channels.ServerSocketChannel;

import java.nio.channels.SocketChannel;

import java.util.Iterator;

public class SelectSockets {

private static final int PORT = 8082;

private ByteBuffer buffer = ByteBuffer.allocate(1024);

public static void main(String[] args) throws IOException {

SelectSockets ss = new SelectSockets();

ss.go();

}

public void go() throws IOException {

System.out.println("listening on port:" + PORT);

ServerSocketChannel ssc = ServerSocketChannel.open();

ServerSocket ss = ssc.socket();

Selector selector = Selector.open();

ss.bind(new InetSocketAddress(PORT));

ssc.configureBlocking(false);

ssc.register(selector, SelectionKey.OP_ACCEPT);

while (true) {

int n = selector.select();

if (n == 0) {

continue;

}

Iterator iter = selector.selectedKeys().iterator();

while (iter.hasNext()) {

SelectionKey key = iter.next();

if (key.isAcceptable()) {

ServerSocketChannel server = (ServerSocketChannel) key

.channel();

SocketChannel client = server.accept();

register(selector, client, SelectionKey.OP_READ);

System.out.println("Accept client:" + client);

acceptClient(client);

}

if (key.isReadable()) {

readData(key);

}

iter.remove();

}

}

}

protected void register(Selector selector, SelectableChannel channel,

int ops) throws IOException {

if (channel == null) {

return;

}

channel.configureBlocking(false);

channel.register(selector, ops);

}

protected void readData(SelectionKey key) throws IOException {

SocketChannel socketChannel = (SocketChannel) key.channel();

int count;

while ((count = socketChannel.read(buffer)) > 0) {

buffer.flip();

while (buffer.hasRemaining()) {

socketChannel.write(buffer);

}

buffer.clear();

if (count < 0) {

socketChannel.close();

}

}

}

private void acceptClient(SocketChannel channel) throws IOException {

buffer.clear();

buffer.put("you have already connected server!".getBytes());

buffer.flip();

channel.write(buffer);

}

}

上面的代码就是一般的

NIO

服务器端实现的过程。

当然对于一个企业级的应用这样的代码肯定是太单薄了,仅仅就

selector

而言,

我们是不是能共通过用多线程的方式来增强他的处理能力?是不是只有一个线程在跑

selector

,让这一个线程处理那么多的连接有点儿过意不去。答案并不是和你想的一样

For the first scenario, in which you want to bring more threads into play to service channels,

resist the urge to use multiple selectors

. Performing readiness selection on large numbers of channels is not expensive;

most of the work is done by the underlying operating system

. Maintaining multiple selectors and randomly assigning channels to one of them is not a satisfactory solution to this problem. It simply makes smaller versions of the same scenario.

如果您想要将更多的线程来为通道提供服务,请抵抗住使用多个选择器的欲望。在大量通道上执行就绪选择并不会有很大的开销,大多数工作是由底层操作系统完成的。管理多个选择器并随机地将通道分派给它们当中的一个并不是这个问题的合理的解决方案。这只会形成这个场景的一个更小的版本。

一个更好的方案就是,让一个线程处理selector,让其他线程去处理就绪通道的业务。

模式就和上图上描述的一样,但是我的疑问来了,这样和线程池下的服务端连接好像看起来并没有多少大的优势。同样还是要启那么多的线程去处理这些业务。这也是我最近一直想从

mina

源码中找到的答案,可是还是没有发现我想要的,它也是通过

IoSession

用原型模型的方式来实现并发的。不过我估计

Mina

应该是有异步的实现,这样也会对性能上有影响。具体还有待研究。

最后要说的就是客户端了,最近其实也的客户端比较多,版本一个接一个,写了不下七八个,各种方式,各种测试,其实有几点心得可以分享:

l  如果是做大文件的传输,切分的性价比其实比连续传的性价比高不了多少,虽然像迅雷这样可以分好多块传输,但那毕竟是

P2P

的结构,文件本来就松散的。考虑到切分再校验再重组,这样还不如切大块,然后顺序传。

l  尽量将指令和传输分开,指令可以加密,然后更具协议,返回端口和地址让服务器端做到分布式的处理。

l  还有就是客户端是否要用非阻塞模式,客户端如果不是做出

P2P

模式的,而且能用多线程解决问题的,就没必要用非阻塞的模式,因为非阻塞模式的发送和接收的时机很难控制,特别是用原生的

NIO

写的

socket

l  在做两端通信的时候,特别是不同语言写的程序和不同操作系统下,要注意字节序(高有效和低有效)和进制的问题。

l

Mina

这样的框架很好,如果再配上

protobuf

这样的多平台序列化工具,可以很好的实现自定义协议的通信。自己订协议的好处就是安全,而且能做应答机制。

Epoll是Linux下多路复用IO接口select/poll的增强版本,它能显著提高程序在大量并发连接中只有少量活跃的情况下的系统CPU利用率,因为它会复用文件描述符集合来传递结果而不用迫使开发者每次等待事件之前都必须重新准备要被侦听的文件描述符集合,另一点原因就是获取事件的时候,它无须遍历整个被侦听的描述符集,只要遍历那些被内核IO事件异步唤醒而加入Ready队列的描述符集合就行了。epoll除了提供select/poll那种IO事件的电平触发(Level Triggered)外,还提供了边沿触发(Edge Triggered),这就使得用户空间程序有可能缓存IO状态,减少epoll_wait/epoll_pwait的调用,提高应用程序效率。

在linux下,NIO可以采用epoll来实现非阻塞,注意,是在linux下:

-Djava.nio.channels.spi.SelectorProvider=sun.nio.ch.EPollSelectorProvider

--------------------------------------------------------------------

下周就要开始弄kafka了,其实网络方面的测试还没有找到最好的解决方案,虽然测了很多东西,但是真的是没有时间去做更多更复杂的东西。接下来赶紧把mina的源码看完,再看看netty就要把重心放在kafka上了。其实网络编程还是很有必要的,好多分布式的通信方案都可以建立在一套比较完整的消息机制上。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/370769.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

MapReduce的工作原理

一、MapReduce模型框架 MapReduce是一个用于大规模数据处理的分布式计算模型&#xff0c;最初由Google工程师设计并实现的&#xff0c;Google已经将完整的MapReduce论文公开发布了。其中的定义是&#xff0c;MapReduce是一个编程模型&#xff0c;是一个用于处理和生成大规模数据…

react实现多行文本超出加省略号

http://www.css88.com/archives/5206 overflow : hidden; text-overflow: ellipsis; display: -webkit-box; -webkit-line-clamp: 2; -webkit-box-orient: vertical; 根据该文章方法&#xff0c;放在react项目中发现并不能实现&#xff0c;仔细观察发现原来react解析出来的css样…

Google Guava MultiMaps

番石榴 这是系列文章中的第一篇&#xff0c;我将尝试解释和探索Google很棒的Guava java库 。 我在搜索Apache Commons Collections的通用版本时遇到了番石榴&#xff08;Guava&#xff09;–我需要一个Bimap并且厌倦了必须使用强制类型转换来填充我的代码–但是我发现要好得多…

qq群 html,我的群组-普通群组.html

&#xfeff;我的群组&#xff0d;普通群组$axure.utils.getTransparentGifPath function() { return resources/images/transparent.gif; };$axure.utils.getOtherPath function() { return resources/Other.html; };$axure.utils.getReloadPath function() { return resou…

查看PLC IP 端口_西门子828D数控系统X130接口通讯怪异现象(X130手动设置的 IP)...

西门子828D数控系统&#xff0c;调试PLC过程中遇到网络通信怪异问题(不能直连非要加个路由器)&#xff0c;笔记本电脑的以太网网络直接连接显示网络电缆被拔出&#xff0c;如下图所示&#xff1a;奇怪&#xff0c;怎么出现这种情况了呢&#xff0c;因为我用这台电脑调试过别的P…

基于嵌入式系统的gnash最小库依赖关系

已经对gnash的依赖库作了详细的分析&#xff0c;下边是必须依赖的库&#xff1a;GIF Required libungif-devlibxml2 Required libxml2-devPNG Requir…

git 创建webpack项目_一次create-react-app创建项目升级webpack的流水账

不再赘述为什么要升级webpack4&#xff0c;有兴趣的小伙伴可以看一下 知乎&#xff1a;如何评价webpack4下面撸起袖子开干&#xff1a;克隆项目&#xff0c;新建分支git checkout -b feature_webpack_upgrade# 相当于以下两句的简写git branch feature_webpack_upgradegit chec…

bzoj1263

贪心 n%31 分出一个4&#xff0c;其余用3&#xff0c;n%32&#xff0c;分出一个2&#xff0c;其余用3&#xff0c;然后高精度就行了 #include<bits/stdc.h> using namespace std; const int N 5005; struct BigInt {int len;int a[N];BigInt() { memset(a, 0, sizeof(a)…

c语言volatile_[技术]为什么单片机C语言编程时某一变量有时乱码

最近一个项目里面&#xff0c;在KEIL中用C语言在单片机里面定义了一个状态机全局变量&#xff0c;这个变量随时会改变&#xff0c;用于切换触摸屏的界面&#xff0c;可是程序运行中出现了一个问题&#xff0c;这个状态机号总是出现了被莫名奇妙改变的问题&#xff0c;导致触屏不…

沙箱Java代码

在上一篇文章中&#xff0c;我们研究了如何保护移动Java代码 。 这样做的一种选择是在笼子或沙箱中运行代码。 这篇文章探讨了如何为Java应用程序设置这样的沙箱。 安全经理 Java中支持沙箱的安全性设施是java.lang.SecurityManager 。 默认情况下&#xff0c;Java在没有Se…

微型计算机2017年9月上,2017年9月计算机一级考试WPS Office冲刺题

2017年9月计算机一级考试WPS Office冲刺题2017年下半年计算机一级考试将在9月份进行&#xff0c;为了方便考生备考计算机一级考试。下面是小编为大家带来的计算机一级考试WPS Office冲刺题&#xff0c;欢迎阅读。冲刺题一&#xff1a;1、PowerPoint 演示文稿和模板的扩展名是【…

七. 多线程编程5.创建多线程

到目前为止&#xff0c;我们仅用到两个线程&#xff1a;主线程和一个子线程。然而&#xff0c;你的程序可以创建所需的更多线程。例如&#xff0c;下面的程序创建了三个子线程&#xff1a;// Create multiple threads.class NewThread implements Runnable { String name; /…

11尺寸长宽 iphone_弱电工程LED显示屏尺寸规格及计算方法

前言&#xff1a;led屏幕在生活中&#xff0c;随处可见&#xff0c;显示屏、广播屏等等&#xff0c;但是led尺寸怎么计算的&#xff0c;你知道吗&#xff1f;今天我们一起了解一下led屏幕尺寸的计算方法。正文&#xff1a;一、点间距的计算1、各单元板常见型号及尺寸LED屏普遍是…

marquee标签的使用

<!DOCTYPE html> <html> <head><meta charset"utf-8" /><title>演示marquee</title><style type"text/css">*{padding: 0px;margin: 0px;}marquee{border: 1px solid purple;}img{width: 360px;height: auto;}&…

32位数据源中没有mysql_[SpringBoot实战]快速配置多数据源(整合MyBatis)

前言由于业务需求&#xff0c;需要同时在SpringBoot中配置两套数据源&#xff08;连接两个数据库&#xff09;&#xff0c;要求能做到service层在调用各数据库表的mapper时能够自动切换数据源&#xff0c;也就是mapper自动访问正确的数据库。本文内容&#xff1a;在SpringbootM…

考研计算机冷门学校,考研5个冷门的985院校 别随大流,这些几所也是很不错的...

导语&#xff1a;想必大家考研的目的有很多&#xff0c;最主要的就是想去更好的学校提升自己&#xff0c;大部分会肯定是会更倾向于985这类的院校&#xff0c;每年其实除了那些被“挤破头”的985院校&#xff0c;其实还有不少“低调”的985院校是非常值得报考的&#xff0c;下面…

名为 cursor_jinserted 的游标不存在_质量工程师必须了解的测量常识,你不知道怎么行...

01测量器具的分类测量器具是一种具有固定形态、用以复现或提供一个或多个已知量值的器具。按用途的不同量具可分为以下几类&#xff1a;1. 单值量具只能体现一个单一量值的量具。可用来校对和调整其它测量器具或作为标准量与被测量直接进行比较&#xff0c;如量块、角度量块等。…

window.onload事件

!DOCTYPE html> <html> <head lang"en"><meta charset"UTF-8"><title>window.onload</title><!--window.onload注意点&#xff1a;01.在整个页面中只能存在一次&#xff0c;否则后面会覆盖前面02.页面中所有的内容加载…

bzoj4869

http://www.lydsy.com/JudgeOnline/problem.php?id4869 终于A了。。。参考了下dalao的代码。。。 拓展欧几里得定理&#xff0c;改了几次就不变了&#xff0c;但是用的时候要在快速幂里判是不是要用。 #include<bits/stdc.h> using namespace std; typedef long long ll…

一张图一个表——CSS选择器总结

CSS选择器总结&#xff1a; (这些表是一张图片^_^) 看底部 完整思维导图图片和表格的下载地址&#xff1a;https://download.csdn.net/download/denlnyyr/10597820 &#xff08;我不想选择要积分币下载的&#xff0c;但那里最低必须选择1个积分……&#xff09; 参考文献&…