- 浏览: 398439 次
- 性别:
- 来自: 杭州
文章分类
- 全部博客 (760)
- 股票日志 (26)
- Selenium (0)
- selenium 2 环境的搭建 (1)
- 并发 (7)
- 框架开发 (1)
- 动态代理 (2)
- Struts2 (2)
- POI (2)
- jdk (3)
- maven (31)
- spring (35)
- mysql (31)
- 工作机会 (3)
- xtream (1)
- oracle dbms_metadata GET_DDL (0)
- SSI (1)
- DB (61)
- powermock (4)
- java 基础 (25)
- 多线程 (11)
- 高手 (2)
- java 底层 (2)
- 专业网站 (1)
- 开发联想 (1)
- 开发联想 (1)
- bat文件 (2)
- 清queue 语句 (1)
- 清queue 语句 (1)
- jquery (7)
- html5 (1)
- Jenkins (10)
- Linux (17)
- 工作issue (2)
- tomcat log (3)
- jvm (23)
- 项目细节 (0)
- oracle (41)
- 泛型 (3)
- 新知识点 (1)
- 数据库ddl 语句 (0)
- AQ (2)
- jms (0)
- 网络资源 (6)
- github (6)
- Easymock (1)
- Dom 解析XML (1)
- windows命令 (2)
- java (7)
- 正则表达式 (5)
- sequence (1)
- oracle 表meta信息 (1)
- 小工具技巧 (1)
- 辅助工具 (1)
- Junit (1)
- 泛型 generic (2)
- Java程序设计 (1)
- cglib (2)
- 架构师之路 (1)
- 数据库连接池 (5)
- c3p0 (1)
- eclipse使用 (1)
- oracle sql plus (1)
- 码农人生 (3)
- SVN (15)
- sqlplus (2)
- jsoup (1)
- 网络爬虫 (2)
- 新技能 (1)
- zookeeper (4)
- hadoop (1)
- SVNKIT (1)
- 从工具到知识点的整理 (1)
- log4j (13)
- 读文件 (0)
- 转义字符 (1)
- command (1)
- web service (3)
- 锁 (1)
- shell 脚本 (1)
- 遇到的错误 (2)
- tomcat (14)
- 房产 (5)
- bootstrap jquery ui (1)
- easyui (2)
- 个人征信 (1)
- 读写分离 (1)
- 备份 (1)
- rmi (6)
- webservice (1)
- JMX (4)
- 内存管理 (3)
- java设计 (1)
- timer (1)
- lock (2)
- concurrent (2)
- collection (1)
- tns (1)
- java基础 (15)
- File (1)
- 本机资源 (1)
- bat (1)
- windows (4)
- 数据结构 (3)
- 代码安全 (1)
- 作用域 (1)
- 图 (2)
- jvm内存结构 (1)
- 计算机思想 (1)
- quartz (6)
- Mongo DB (2)
- Nosql (4)
- sql (5)
- 第三方Java 工具 jar 项目 (2)
- drools (1)
- java swing (2)
- 调用console (1)
- runtime (1)
- process (1)
- swing (2)
- grouplayout (1)
- dubbo (0)
- bootstrap (0)
- nodejs (2)
- SVN hooks (1)
- jdbc (3)
- jdbc error (1)
- precedure (1)
- partition_key (1)
- active mq (1)
- blob (2)
- Eclipse (6)
- web server (1)
- bootstrapt (2)
- struts (1)
- ajax (1)
- js call back (1)
- 思想境界拓展 (1)
- JIRA (1)
- log (1)
- jaxb (3)
- xml java互相转换 (1)
- 装修 (2)
- 互联网 (2)
- threadlocal (3)
- mybatis (22)
- xstream (1)
- 排序 (1)
- 股票资源 (1)
- RPC (2)
- NIO (3)
- http client (6)
- 他人博客 (1)
- 代理服务器 (1)
- 网络 (2)
- web (1)
- 股票 (5)
- deadlock (1)
- JConsole (2)
- activemq (3)
- oralce (1)
- 游标 (1)
- 12月13日道富内部培训 (0)
- grant (1)
- 速查 (2)
- classloader (4)
- netty (4)
- 设计模式 (2)
- 缓存 (2)
- ehcache (2)
- framework (1)
- 内存分析 (2)
- dump (1)
- memory (2)
- 多高线程,并发 (1)
- hbase (2)
- 分布式系统 (1)
- socket (3)
- socket (1)
- 面试问题 (1)
- jetty (2)
- http (2)
- 源码 (1)
- 日志 (2)
- jni (1)
- 编码约定 (1)
- memorycache (1)
- redis (13)
- 杂谈 (1)
- drool (1)
- blockingqueue (1)
- ScheduledExecutorService (1)
- 网页爬虫 (1)
- httpclient (4)
- httpparser (1)
- map (1)
- 单例 (1)
- synchronized (2)
- thread (1)
- job (1)
- hashcode (1)
- copyonwriteArrayList (2)
- 录制声音 (1)
- java 标准 (2)
- SSL/TLS (1)
- itext (1)
- pdf (1)
- 钻石 (2)
- sonar (1)
- unicode (1)
- 编码 (4)
- html (1)
- SecurityManager (1)
- 坑 (1)
- Restful (2)
- svn hook (1)
- concurrentHashMap (1)
- 垃圾回收 (1)
- vbs (8)
- visual svn (2)
- power shell (1)
- wmi (3)
- mof (2)
- c# (1)
- concurrency (1)
- 劳动法 (1)
- 三国志游戏 (2)
- 三国 (1)
- 洪榕 (2)
- 金融投资知识 (1)
- motan (1)
- tkmybatis mapper (1)
- 工商注册信息查询 (1)
- consul (1)
- 支付业务知识 (2)
- 数据库备份 (1)
- 字段设计 (1)
- 字段 (1)
- dba (1)
- 插件 (2)
- PropEdit插件 (1)
- web工程 (1)
- 银行业知识 (2)
- 国内托管银行 (1)
- 数据库 (1)
- 事务 (2)
- git (18)
- component-scan (1)
- 私人 (0)
- db2 (14)
- alias (1)
- 住房 (1)
- 户口 (1)
- fastjson (1)
- test (6)
- RSA (2)
- 密钥 (1)
- putty (1)
- sftp (1)
- 加密 (1)
- 公钥私钥 (3)
- markdown (1)
- sweet (1)
- sourcetree (1)
- 好工具 (1)
- cmd (1)
- scp (1)
- notepad++ (1)
- ssh免密登录 (1)
- https (1)
- ssl (2)
- js (2)
- h2 (1)
- 内存 (2)
- 浏览器 (1)
- js特效 (1)
- io (1)
- 乱码 (1)
- 小工具 (1)
- 每周技术任务 (1)
- mongodb (7)
- 内存泄漏 (1)
- 码云 (2)
- 如何搭建java 视频服务器 tomcat (1)
- 资源 (1)
- 书 (1)
- 四色建模法 (1)
- 建模 (1)
- 配置 (1)
- 职位 (1)
- nginx (1)
- excel (1)
- log4j2 (2)
- 做菜 (1)
- jmap (1)
- jspwiki (1)
- activiti (1)
- 工作流引擎 (1)
- 安卓 (1)
- acitviti 例子 (1)
- 二维码 (1)
- 工作流 (1)
- powerdesign (2)
- 软件设计 (1)
- 乐观锁 (1)
- 王者荣耀 (1)
- session (2)
- token (5)
- cookie (4)
- springboot (24)
- jwt (2)
- 项目路径 (1)
- magicbook (1)
- requestType (1)
- json (2)
- swagger (1)
- eolinker (1)
- springdata (1)
- springmvc (1)
- controlleradvice (1)
- profile (1)
- 银行四要素 (1)
- 支付人员资源 (1)
- 支付渠道 (1)
- yaml (1)
- 中文编码 (1)
- mongo (2)
- serializable (1)
- 序列化 (1)
- zyd (1)
- unittest (1)
- 工具 (1)
- Something (1)
- 通达信 (1)
- protobuf (1)
- 算法 (1)
- springcloud (2)
- hikari (1)
- rocketmq (7)
- cachecloud (1)
- serfj (1)
- axure (1)
- lombok (1)
- 分布式锁 (1)
- 线程 (2)
- 同步代码块 (1)
- cobar (1)
- mq (1)
- rabbitmq (1)
- 定时执行 (1)
- 支付系统 (3)
- 唱歌 (1)
- elasticjob (1)
- 定时任务 (1)
- 界面 (1)
- flink (2)
- 大数据 (1)
- 接私活 (0)
- 内部培训 (2)
最新评论
-
dannyhz:
做股票从短线 试水,然后 慢慢发现 波段和 中期的故事可挖, ...
搭台唱戏 -
dannyhz:
http://developer.51cto.com/art/ ...
如何自己开发框架 它的注意点是什么
我们都知道TCP是面向连接的传输层协议,一个socket必定会有绑定一个连接,在普通的BIO(阻塞式IO)中,需要有三次握手,然后一般的socket编程就是这样的形式。
Socket服务器端流程如下:加载套接字->创建监听的套接字->绑定套接字->监听套接字->处理客户端相关请求。
Socket客户端同样需要先加载套接字,然后创建套接字,不过之后不用绑定和监听了,而是直接连接服务器,发送相关请求。
他们一直就占用这个连接,如果有信息发送,那么就响应,否则就一直阻塞着。如果有多连接,那么就要使用多线程,一个线程处理一个连接,在连接还少的情况下,是允许的,但如果同时处理的连接过多比如说1000,那么在win平台上就会遇到瓶颈了如果2000,那么在linux上就遇到瓶颈了,因为在不同的平台上每一个进程能够创建的线程数是有限度的,并且过多的线程必将会引起系统对线程调度的效率问题,再怎么也要保证线程优先队列,阻塞队列;假设一千个线程,一个线程最少一兆的栈大小,对内存也是一个很大的消耗。
总之阻塞式的IO是:一连接<一一一>一线程 。
然后出现了NIO,在java1.4引入了java.nio包,java new I/O。引入了操作系统中常用的缓冲区和通道等概念。
缓冲区: 在操作系统中缓冲区是为了解决CPU的计算速度和外设输入输出速度不匹配的问题,因为外设太慢了,如果没有缓冲区,那么CPU在外设输入的时候就要一直等着,就会造成CPU处理效率的低下,引入了缓冲之后,外设直接把数据放到缓冲中,当数据传输完成之后,给CPU一个中断信号,通知CPU:“我的数据传完了,你自己从缓冲里面去取吧”。如果是输出也是一样的道理。
通道: 那么通道用来做什么呢?其实从他的名字就可以看出,它就是一条通道,您想传递出去的数据被放置在缓冲区中,然后缓冲区中怎么从哪里传输出去呢?或者外设怎么把数据传输到缓冲中呢?这里就要用到通道。它可以进一步的减少CPU的干预,同时更有效率的提高整个系统的资源利用率,例如当CPU要完成一组相关的读操作时,只需要向I/O通道发送一条指令,以给出其要执行的通道程序的首地址和要访问的设备,通道执行通道程序便可以完成CPU指定的I/O任务。
选择器: 另外一项创新是选择器,当我们使用通道的时候也许通道没有准备好,或者有了新的请求过来,或者线程遇到了阻塞,而选择器恰恰可以帮助CPU了解到这些信息,但前提是将这个通道注册到了这个选择器。
下面一个例子是我看过的一个讲述的很贴切的例子:
一辆从 A 开往 B 的公共汽车上,路上有很多点可能会有人下车。司机不知道哪些点会有哪些人会下车,对于需要下车的人,如何处理更好?
1. 司机过程中定时询问每个乘客是否到达目的地,若有人说到了,那么司机停车,乘客下车。 ( 类似阻塞式 )
2. 每个人告诉售票员自己的目的地,然后睡觉,司机只和售票员交互,到了某个点由售票员通知乘客下车。 ( 类似非阻塞 )
很显然,每个人要到达某个目的地可以认为是一个线程,司机可以认为是 CPU 。在阻塞式里面,每个线程需要不断的轮询,上下文切换,以达到找到目的地的结果。而在非阻塞方式里,每个乘客 ( 线程 ) 都在睡觉 ( 休眠 ) ,只在真正外部环境准备好了才唤醒,这样的唤醒肯定不会阻塞。
在非阻塞式IO中实现的是:一请求<一一一>一线程
下面这个例子实现了一个线程监听两个ServerSocket,只有等到请求的时候才会有处理。
Server
package cn.vicky.channel;
import java.io.IOException;
import java.net.InetSocketAddress;
import java.nio.ByteBuffer;
import java.nio.channels.SelectionKey;
import java.nio.channels.Selector;
import java.nio.channels.ServerSocketChannel;
import java.nio.channels.SocketChannel;
import java.nio.channels.spi.SelectorProvider;
import java.util.Iterator;
/**
* TCP/IP的NIO非阻塞方式
* 服务器端
* */
public class Server implements Runnable {
//第一个端口
private Integer port1 = 8099;
//第二个端口
private Integer port2 = 9099;
//第一个服务器通道 服务A
private ServerSocketChannel serversocket1;
//第二个服务器通道 服务B
private ServerSocketChannel serversocket2;
//连接1
private SocketChannel clientchannel1;
//连接2
private SocketChannel clientchannel2;
//选择器,主要用来监控各个通道的事件
private Selector selector;
//缓冲区
private ByteBuffer buf = ByteBuffer.allocate(512);
public Server() {
init();
}
/**
* 这个method的作用
* 1:是初始化选择器
* 2:打开两个通道
* 3:给通道上绑定一个socket
* 4:将选择器注册到通道上
* */
public void init() {
try {
//创建选择器
this.selector = SelectorProvider.provider().openSelector();
//打开第一个服务器通道
this.serversocket1 = ServerSocketChannel.open();
//告诉程序现在不是阻塞方式的
this.serversocket1.configureBlocking(false);
//获取现在与该通道关联的套接字
this.serversocket1.socket().bind(new InetSocketAddress("localhost", this.port1));
//将选择器注册到通道上,返回一个选择键
//OP_ACCEPT用于套接字接受操作的操作集位
this.serversocket1.register(this.selector, SelectionKey.OP_ACCEPT);
//然后初始化第二个服务端
this.serversocket2 = ServerSocketChannel.open();
this.serversocket2.configureBlocking(false);
this.serversocket2.socket().bind(new InetSocketAddress("localhost", this.port2));
this.serversocket2.register(this.selector, SelectionKey.OP_ACCEPT);
} catch (Exception e) {
e.printStackTrace();
}
}
/**
* 这个方法是连接
* 客户端连接服务器
* @throws IOException
* */
public void accept(SelectionKey key) throws IOException {
ServerSocketChannel server = (ServerSocketChannel) key.channel();
if (server.equals(serversocket1)) {
clientchannel1 = server.accept();
clientchannel1.configureBlocking(false);
//OP_READ用于读取操作的操作集位
clientchannel1.register(this.selector, SelectionKey.OP_READ);
} else {
clientchannel2 = server.accept();
clientchannel2.configureBlocking(false);
//OP_READ用于读取操作的操作集位
clientchannel2.register(this.selector, SelectionKey.OP_READ);
}
}
/**
* 从通道中读取数据
* 并且判断是给那个服务通道的
* @throws IOException
* */
public void read(SelectionKey key) throws IOException {
this.buf.clear();
//通过选择键来找到之前注册的通道
//但是这里注册的是ServerSocketChannel为什么会返回一个SocketChannel??
SocketChannel channel = (SocketChannel) key.channel();
//从通道里面读取数据到缓冲区并返回读取字节数
int count = channel.read(this.buf);
if (count == -1) {
//取消这个通道的注册
key.channel().close();
key.cancel();
return;
}
//将数据从缓冲区中拿出来
String input = new String(this.buf.array()).trim();
//那么现在判断是连接的那种服务
if (channel.equals(this.clientchannel1)) {
System.out.println("欢迎您使用服务A");
System.out.println("您的输入为:" + input);
} else {
System.out.println("欢迎您使用服务B");
System.out.println("您的输入为:" + input);
}
}
@Override
public void run() {
while (true) {
try {
System.out.println("running ... ");
//选择一组键,其相应的通道已为 I/O 操作准备就绪。
this.selector.select();
//返回此选择器的已选择键集
//public abstract Set<SelectionKey> selectedKeys()
Iterator selectorKeys = this.selector.selectedKeys().iterator();
while (selectorKeys.hasNext()) {
System.out.println("running2 ... ");
//这里找到当前的选择键
SelectionKey key = (SelectionKey) selectorKeys.next();
//然后将它从返回键队列中删除
selectorKeys.remove();
if (!key.isValid()) { // 选择键无效
continue;
}
if (key.isAcceptable()) {
//如果遇到请求那么就响应
this.accept(key);
} else if (key.isReadable()) {
//读取客户端的数据
this.read(key);
}
}
} catch (Exception e) {
e.printStackTrace();
}
}
}
public static void main(String[] args) {
Server server = new Server();
Thread thread = new Thread(server);
thread.start();
}
}
Client
package cn.vicky.channel;
import java.io.IOException;
import java.net.InetSocketAddress;
import java.nio.ByteBuffer;
import java.nio.channels.SocketChannel;
import java.net.InetAddress;
/**
* TCP/IP的NIO非阻塞方式
* 客户端
* */
public class Client {
//创建缓冲区
private ByteBuffer buffer = ByteBuffer.allocate(512);
//访问服务器
public void query(String host, int port) throws IOException {
InetSocketAddress address = new InetSocketAddress(InetAddress.getByName(host), port);
SocketChannel socket = null;
byte[] bytes = new byte[512];
while (true) {
try {
System.in.read(bytes);
socket = SocketChannel.open();
socket.connect(address);
buffer.clear();
buffer.put(bytes);
buffer.flip();
socket.write(buffer);
buffer.clear();
} catch (Exception e) {
e.printStackTrace();
} finally {
if (socket != null) {
socket.close();
}
}
}
}
public static void main(String[] args) throws IOException {
new Client().query("localhost", 8099);
}
}
以上的服务端一个线程监听两个服务,整个服务端只有一个阻塞的方法:
//选择一组键,其相应的通道已为 I/O 操作准备就绪。
this.selector.select();
当客户请求服务器的时候,那么这造成了TCP没有面向连接的假象,其实至少在传输数据的时候是连接的,只是在一次I/O请求结束之后服务器端就把连接给断开,继而继续去处理更多的请求。而在客户端,可以看到也是遇到一次请求的时候就connect服务端一次。所以TCP还是面向连接的。
现在终于知道了为什么叫非阻塞式IO了,大概就是这个意思。
Socket服务器端流程如下:加载套接字->创建监听的套接字->绑定套接字->监听套接字->处理客户端相关请求。
Socket客户端同样需要先加载套接字,然后创建套接字,不过之后不用绑定和监听了,而是直接连接服务器,发送相关请求。
他们一直就占用这个连接,如果有信息发送,那么就响应,否则就一直阻塞着。如果有多连接,那么就要使用多线程,一个线程处理一个连接,在连接还少的情况下,是允许的,但如果同时处理的连接过多比如说1000,那么在win平台上就会遇到瓶颈了如果2000,那么在linux上就遇到瓶颈了,因为在不同的平台上每一个进程能够创建的线程数是有限度的,并且过多的线程必将会引起系统对线程调度的效率问题,再怎么也要保证线程优先队列,阻塞队列;假设一千个线程,一个线程最少一兆的栈大小,对内存也是一个很大的消耗。
总之阻塞式的IO是:一连接<一一一>一线程 。
然后出现了NIO,在java1.4引入了java.nio包,java new I/O。引入了操作系统中常用的缓冲区和通道等概念。
缓冲区: 在操作系统中缓冲区是为了解决CPU的计算速度和外设输入输出速度不匹配的问题,因为外设太慢了,如果没有缓冲区,那么CPU在外设输入的时候就要一直等着,就会造成CPU处理效率的低下,引入了缓冲之后,外设直接把数据放到缓冲中,当数据传输完成之后,给CPU一个中断信号,通知CPU:“我的数据传完了,你自己从缓冲里面去取吧”。如果是输出也是一样的道理。
通道: 那么通道用来做什么呢?其实从他的名字就可以看出,它就是一条通道,您想传递出去的数据被放置在缓冲区中,然后缓冲区中怎么从哪里传输出去呢?或者外设怎么把数据传输到缓冲中呢?这里就要用到通道。它可以进一步的减少CPU的干预,同时更有效率的提高整个系统的资源利用率,例如当CPU要完成一组相关的读操作时,只需要向I/O通道发送一条指令,以给出其要执行的通道程序的首地址和要访问的设备,通道执行通道程序便可以完成CPU指定的I/O任务。
选择器: 另外一项创新是选择器,当我们使用通道的时候也许通道没有准备好,或者有了新的请求过来,或者线程遇到了阻塞,而选择器恰恰可以帮助CPU了解到这些信息,但前提是将这个通道注册到了这个选择器。
下面一个例子是我看过的一个讲述的很贴切的例子:
一辆从 A 开往 B 的公共汽车上,路上有很多点可能会有人下车。司机不知道哪些点会有哪些人会下车,对于需要下车的人,如何处理更好?
1. 司机过程中定时询问每个乘客是否到达目的地,若有人说到了,那么司机停车,乘客下车。 ( 类似阻塞式 )
2. 每个人告诉售票员自己的目的地,然后睡觉,司机只和售票员交互,到了某个点由售票员通知乘客下车。 ( 类似非阻塞 )
很显然,每个人要到达某个目的地可以认为是一个线程,司机可以认为是 CPU 。在阻塞式里面,每个线程需要不断的轮询,上下文切换,以达到找到目的地的结果。而在非阻塞方式里,每个乘客 ( 线程 ) 都在睡觉 ( 休眠 ) ,只在真正外部环境准备好了才唤醒,这样的唤醒肯定不会阻塞。
在非阻塞式IO中实现的是:一请求<一一一>一线程
下面这个例子实现了一个线程监听两个ServerSocket,只有等到请求的时候才会有处理。
Server
package cn.vicky.channel;
import java.io.IOException;
import java.net.InetSocketAddress;
import java.nio.ByteBuffer;
import java.nio.channels.SelectionKey;
import java.nio.channels.Selector;
import java.nio.channels.ServerSocketChannel;
import java.nio.channels.SocketChannel;
import java.nio.channels.spi.SelectorProvider;
import java.util.Iterator;
/**
* TCP/IP的NIO非阻塞方式
* 服务器端
* */
public class Server implements Runnable {
//第一个端口
private Integer port1 = 8099;
//第二个端口
private Integer port2 = 9099;
//第一个服务器通道 服务A
private ServerSocketChannel serversocket1;
//第二个服务器通道 服务B
private ServerSocketChannel serversocket2;
//连接1
private SocketChannel clientchannel1;
//连接2
private SocketChannel clientchannel2;
//选择器,主要用来监控各个通道的事件
private Selector selector;
//缓冲区
private ByteBuffer buf = ByteBuffer.allocate(512);
public Server() {
init();
}
/**
* 这个method的作用
* 1:是初始化选择器
* 2:打开两个通道
* 3:给通道上绑定一个socket
* 4:将选择器注册到通道上
* */
public void init() {
try {
//创建选择器
this.selector = SelectorProvider.provider().openSelector();
//打开第一个服务器通道
this.serversocket1 = ServerSocketChannel.open();
//告诉程序现在不是阻塞方式的
this.serversocket1.configureBlocking(false);
//获取现在与该通道关联的套接字
this.serversocket1.socket().bind(new InetSocketAddress("localhost", this.port1));
//将选择器注册到通道上,返回一个选择键
//OP_ACCEPT用于套接字接受操作的操作集位
this.serversocket1.register(this.selector, SelectionKey.OP_ACCEPT);
//然后初始化第二个服务端
this.serversocket2 = ServerSocketChannel.open();
this.serversocket2.configureBlocking(false);
this.serversocket2.socket().bind(new InetSocketAddress("localhost", this.port2));
this.serversocket2.register(this.selector, SelectionKey.OP_ACCEPT);
} catch (Exception e) {
e.printStackTrace();
}
}
/**
* 这个方法是连接
* 客户端连接服务器
* @throws IOException
* */
public void accept(SelectionKey key) throws IOException {
ServerSocketChannel server = (ServerSocketChannel) key.channel();
if (server.equals(serversocket1)) {
clientchannel1 = server.accept();
clientchannel1.configureBlocking(false);
//OP_READ用于读取操作的操作集位
clientchannel1.register(this.selector, SelectionKey.OP_READ);
} else {
clientchannel2 = server.accept();
clientchannel2.configureBlocking(false);
//OP_READ用于读取操作的操作集位
clientchannel2.register(this.selector, SelectionKey.OP_READ);
}
}
/**
* 从通道中读取数据
* 并且判断是给那个服务通道的
* @throws IOException
* */
public void read(SelectionKey key) throws IOException {
this.buf.clear();
//通过选择键来找到之前注册的通道
//但是这里注册的是ServerSocketChannel为什么会返回一个SocketChannel??
SocketChannel channel = (SocketChannel) key.channel();
//从通道里面读取数据到缓冲区并返回读取字节数
int count = channel.read(this.buf);
if (count == -1) {
//取消这个通道的注册
key.channel().close();
key.cancel();
return;
}
//将数据从缓冲区中拿出来
String input = new String(this.buf.array()).trim();
//那么现在判断是连接的那种服务
if (channel.equals(this.clientchannel1)) {
System.out.println("欢迎您使用服务A");
System.out.println("您的输入为:" + input);
} else {
System.out.println("欢迎您使用服务B");
System.out.println("您的输入为:" + input);
}
}
@Override
public void run() {
while (true) {
try {
System.out.println("running ... ");
//选择一组键,其相应的通道已为 I/O 操作准备就绪。
this.selector.select();
//返回此选择器的已选择键集
//public abstract Set<SelectionKey> selectedKeys()
Iterator selectorKeys = this.selector.selectedKeys().iterator();
while (selectorKeys.hasNext()) {
System.out.println("running2 ... ");
//这里找到当前的选择键
SelectionKey key = (SelectionKey) selectorKeys.next();
//然后将它从返回键队列中删除
selectorKeys.remove();
if (!key.isValid()) { // 选择键无效
continue;
}
if (key.isAcceptable()) {
//如果遇到请求那么就响应
this.accept(key);
} else if (key.isReadable()) {
//读取客户端的数据
this.read(key);
}
}
} catch (Exception e) {
e.printStackTrace();
}
}
}
public static void main(String[] args) {
Server server = new Server();
Thread thread = new Thread(server);
thread.start();
}
}
Client
package cn.vicky.channel;
import java.io.IOException;
import java.net.InetSocketAddress;
import java.nio.ByteBuffer;
import java.nio.channels.SocketChannel;
import java.net.InetAddress;
/**
* TCP/IP的NIO非阻塞方式
* 客户端
* */
public class Client {
//创建缓冲区
private ByteBuffer buffer = ByteBuffer.allocate(512);
//访问服务器
public void query(String host, int port) throws IOException {
InetSocketAddress address = new InetSocketAddress(InetAddress.getByName(host), port);
SocketChannel socket = null;
byte[] bytes = new byte[512];
while (true) {
try {
System.in.read(bytes);
socket = SocketChannel.open();
socket.connect(address);
buffer.clear();
buffer.put(bytes);
buffer.flip();
socket.write(buffer);
buffer.clear();
} catch (Exception e) {
e.printStackTrace();
} finally {
if (socket != null) {
socket.close();
}
}
}
}
public static void main(String[] args) throws IOException {
new Client().query("localhost", 8099);
}
}
以上的服务端一个线程监听两个服务,整个服务端只有一个阻塞的方法:
//选择一组键,其相应的通道已为 I/O 操作准备就绪。
this.selector.select();
当客户请求服务器的时候,那么这造成了TCP没有面向连接的假象,其实至少在传输数据的时候是连接的,只是在一次I/O请求结束之后服务器端就把连接给断开,继而继续去处理更多的请求。而在客户端,可以看到也是遇到一次请求的时候就connect服务端一次。所以TCP还是面向连接的。
现在终于知道了为什么叫非阻塞式IO了,大概就是这个意思。
相关推荐
这个例子包含了NIO在网络通信中的应用,包括服务器端(Server)和客户端(Client)的实现。 在Java NIO中,核心组件有通道(Channels)、缓冲区(Buffers)和选择器(Selectors)。通道是数据传输的途径,如套接字...
本例子中的"NioServer"可能是一个简单的Java NIO服务器端程序,用于演示如何使用NIO进行网络通信。下面我们将深入探讨Java NIO的关键组件和工作原理。 1. **通道(Channel)**:通道是数据传输的途径,类似于传统的...
myeclipse开发通信示例,框架netty,代码本人写的,而且已测试通过,先运行NettyService,再运行NettyClient即可看到效果。nio示例也有,原理一样,运行先后顺序同netty.
在这个“JAVA nio的一个简单的例子”中,我们将探讨如何使用Java NIO进行简单的服务器-客户端通信,并计算字符串的哈希值。 在传统的BIO模型中,每个连接都需要一个线程来处理,当并发连接数量增加时,系统会创建...
本例包含服务器端和客户端,多线程,每线程多次发送,Eclipse工程,启动服务器使用 nu.javafaq.server.NioServer,启动客户端使用 nu.javafaq.client.NioClient。另本例取自javafaq.nv上的程序修改而成
在这个"NIO 服务器客户端例子"中,`TestServer.java`和`TestClient.java`分别代表服务器端和客户端的实现。 **NIO服务器端(TestServer.java)的关键知识点:** 1. **选择器(Selector)**:服务器通常会创建一个...
标题中的“NIO的多播例子”指的是使用Java NIO实现的多播通信应用。NIO提供了选择器(Selector)、通道(Channel)和缓冲区(Buffer)等组件,使得在处理多个连接时可以更加高效。多播是IP层的UDP服务,它通过组播...
用java编写的nio通信的例子,nio是io编程的新版本,比io较流行。同时本例子是适用socket通信的。可以在此基础上,添加您的个人应用。本例子适用于:java通信的学习者,android平台通信的学习者。
总的来说,这个NIO服务端和客户端的例子可以帮助我们深入理解Java NIO和Netty框架的工作原理,学习如何构建高效、可靠的网络应用。通过实践和分析这个示例代码,我们可以更好地掌握异步I/O、事件驱动编程以及Netty...
总结来说,"NIO socket编程小例子 加法服务器"是一个很好的学习NIO网络编程的起点。通过这个实例,我们可以了解NIO Channel、Buffer和Selector的基本用法,以及如何构建一个简单的网络通信应用。对于任何想要提升...
为了更直观地理解NIO的优势,下面通过一个具体的例子来比较使用传统I/O和NIO读取文件的差异。 ```java // 使用传统I/O读取文件 public void ioRead(String file) throws IOException { FileInputStream in = new ...
描述中提到的"用nio想的一个不阻塞NIOSocket例子"可能是一个Java NIO的Socket通信示例,利用NIO的Channel和Selector来实现客户端和服务器之间的非阻塞通信。通常,NIO中的SocketChannel用于网络通信,Selector用于...
描述中的“java nio 编程一个实例子.服务端程序”提示我们,这个实例是一个服务器端的应用,它利用Java NIO来处理客户端的连接请求。在NIO服务端编程中,通常会使用`Selector`来监听多个通道的事件,当有新的连接、...
在“NIO_MINA学习例子_源代码”中,你可以找到以下学习要点: 1. **NIO基础**:研究源代码中的通道和缓冲区的使用,理解如何通过Channel.read()和Channel.write()进行数据传输,以及如何使用Selector注册和监听通道...
我研究并实现的Java Nio selector例子。java侧起server(NioUdpServer1.java),基于Java Nio的selector 阻塞等候,一个android app(NioUdpClient1文件夹)和一个java程序(UI.java)作为两个client分别向该server...
此外,这个例子应该包含了异常处理,确保在出现错误时能够正确关闭资源,防止资源泄露。 总的来说,这个javaNIO实例是一个很好的学习资源,通过实践了解NIO的基本用法和优势。对于希望提升Java I/O性能或者处理高...
Java NIO,全称为Non-Blocking ..."NIO修正版書面例子"这个压缩包文件很可能是包含了一些示例代码,可以帮助你更深入地理解和实践Java NIO的各种特性。通过结合这些示例和Java API文档,你将能够更好地掌握NIO的使用。
在这个例子中,可能会包含类图、序列图或状态图,来描绘服务器和客户端的架构、交互流程以及对象状态的变迁。 5. **源码分析** - **服务器源码**:服务器主要代码可能包括设置监听、接受连接、注册选择器、处理...
在这个例子中,我们首先打开一个文件通道,然后创建一个ByteBuffer并从文件通道中读取数据。当缓冲区满时,我们反转缓冲区以读取数据,然后清空缓冲区以接收更多的数据。这个过程一直持续到文件读取完毕。 通过以上...
这些例子可以帮助开发者深入理解NIO的工作原理,掌握如何在实际项目中应用NIO技术,提高Java应用程序的性能和并发处理能力。通过分析和学习这些示例,可以更好地理解和实践Java NIO的各种特性。