这是第一篇NIO学习笔记,至于会不会有第二篇到时候再说
最近也是刚刚开始接触NIO,主要用于替换ServerSocket
备忘:cat</dev/tcp/ip/port可以直接创建tcp连接,不过只能显示服务器的返回信息,把小于号改成大于号就可以向服务器发送消息
双向的话还是用telnet比较好。当然这是没来得及写客户端情况下的应付手段
首先是ServerSocketChannel的例子
首先是开启服务器
//创建一个选择器
selector = Selector.open();
//创建ServerSocketChannel并将其绑定在端口上
ServerSocketChannel server = ServerSocketChannel.open();
server.bind(new InetSocketAddress(PORT));
//设置为非阻塞模式
server.configureBlocking(false);
//注册这个channel
server.register(selector, SelectionKey.OP_ACCEPT);
这里我刚开始的时候犯了个错误,bind的时候new InetSocketAddress我输入了localhost和port两个参数,结果造成服务器只能通过localhost访问
我从路由器设置到selinux到iptables来回检查了无数便,最后netstat -na发现了真相。顿时有种吐血的感觉。
之后就进入一个while true循环获取事件了
while(true){
// select操作会把发生关注事件的Key加入到selectionKeys中(只管加不管减)
if(selector.select()==0){
continue;
}
//获取发生了关注时间的KEY集合
//selector.keys()会返回所有的SelectionKey(包括没有发生事件的)
Set<SelectionKey> keys = selector.selectedKeys();
for(SelectionKey key:keys){
process(key);
//移除处理完成的key
keys.remove(key);
}
}
这里我设置了一个Hashtable保存每个连接和key的对应关系,便于应对服务器需要主动向某个地址发送数据的情况
private void process(SelectionKey key) throws IOException{
//OP_ACCEPT事件,这个只有ServerSocketChannel会触发
if(key.isAcceptable()){
SocketChannel channel = ((ServerSocketChannel)key.channel()).accept();
//非阻塞
channel.configureBlocking(false);
//取得刚注册的key保存到连接map中
SelectionKey nkey = channel.register(key.selector(),SelectionKey.OP_READ,ByteBuffer.allocate(1024));
// get address
InetSocketAddress addr = (InetSocketAddress)channel.getRemoteAddress();
targetMap.put(addr.toString(), nkey);
}
//OP_READ事件,可读取的数据
if(key.isReadable()){
TCPReader.processRead(key);
}
//OP_WRITE事件,写数据
if(key.isWritable()){
TCPWriter.processWrite(key);
}
}
【主动通信】
这个虽然是后做的,不过既然提到了还是做一个说明吧
说实话这方面我没有在网上查找到任何可用的资料,完全是自己摸索出来的
首先,连接到服务器的TCP连接的channel可以通过getRemoteAddress()方法取得来源地址,强制转换未InetSocketAddress后可以直接调用.toString()方式,得到的结果是:/ip:port 形式的字符串,通过这个可以很容易区分开每个SelectionKey。刚好可以作为Hashtable的Key
然后就是这个SelectionKey的获取问题了,最开始以为产生OP_ACCEPT事件的key直接就能拿走,测试后发现这是服务器端的Key,如果需要取得对应客户端连接的Key则需要多一个步骤。
我注意到
channel.register(key.selector(),SelectionKey.OP_READ,ByteBuffer.allocate(1024));
这个注册方法返回值就是一个SelectionKey,取出测试后发现就是和客户端连接的Key。
初步目标达成!
不过单单取得SelectionKey没用,还需要完成发送流程,这里我在网上看到有一种设想是把要发送的对象attach到key上然后在Write流程中通过attachment取出,实测后发现此方式数据极容易在Read流程中被当作ByteBuffer读取,出现强制转换类型错误。即使使用ByteBuffer作为介质也可能被Read流程当作输入数据取出。传递方面还是用其他方式吧。
常规的流程先检测Read状态后检测Write状态,但是实测发现直接修改key.interestOps为OP_WRITE状态并没有被检测器捕获,还是要自己另外实现channel的write流程。不过要注意一个channel的write一定要放在同一个线程中,不然极可能将要发送的数据插入到正在发送的数据包中造成数据混乱无法读取。这个大家都是老手就不赘述了。
注意取得channel并调用write方法前一定要把key设置为OP_WRITE模式,否则会报异常
【数据包分离】
TCP数据流一个很大的特点是实际上并不清楚数据包的长度大小,也不清楚何时结束。所有的数据都按顺序叠在一起。因此发送的数据包可能因为过大而被分割成几个小部分发过来,也可能前后两个包首尾相连一起发过来,将数据流按协议一个个剥离出来是一个必须妥善解决的问题。
在此有必要列出我使用的字节流协议详情:
字节序号 内容
0 数据包的类型(视频流、图片、RSA的public key申请、视频流终止信号等)
1-4 4个字节组成int值,表示数据的目标用户id(target)
5-9 4个字节组成的int值,表示正文数据的长度(length)
10-(length+9) 正文数据
读取线程采用此算法(UML学的不好,能看懂最好。。。哈哈),使用了2个ByteArrayOutputStream双缓冲来缓存数据。留有一个填加数据的方法。使用一个static Hashtable管理线程池,在static方法中传入一个SelectionKey,通过key的地址寻找目标线程并将ByteBuffer中的byte[]数据输入stream1缓冲流
而线程中则将stream1中的数据转入stream2中,随后对数据进行读取和处理。处理完一个包后如果还有剩余数据则放回stream2继续处理。线程末尾检查stream1是否有新的数据,如果有则循环,没有就结束线程并从线程池中删除对象。
今天暂时到这里,由于是自学,个人见解难免错漏,也在此抛砖引玉,也希望有高人能给出更有效的处理方法
- 大小: 57.8 KB
分享到:
相关推荐
Nio学习笔记
java NIO的基本知识点学习笔记,不包含具体代码
java学习笔记1(java io/nio)设计模式
javaNIO学习笔记(csdn)————程序
文章同步:http://blog.csdn.net/wgyscsf/article/details/50953318
NULL 博文链接:https://zheng12tian.iteye.com/blog/1094811
IO 是主存和外部设备 ( 硬盘、终端和网络等 ) 拷贝数据的过程。 IO 是操作系统的底层功能实现,底层通过 I/O 指令进行完成。 所有语言运行时系统提供执行 I/O 较高级别的工具。 (c 的 printf scanf,java 的面向对象...
Contents: 1 核心概念以及基本读写 2 缓冲区的实现机制 3 连网与异步IO 4 分散和聚集IO 5 文件锁定
NULL 博文链接:https://copperfield.iteye.com/blog/1454238
自己总结的java中NIO的笔记,绘制了详细的思维导图,每个思维导图中均有详细的博文解释,方便大家学习和理解,免费分享给大家。适合java的爱好者和学习者
JDK1.7新特性,NIO2异步学习笔记。
集合、NIO、Netty、Thread、MySql、Hive、HBase、Kafka、Spark、Fink等学习笔记
JAVA学习笔记,包含JAVA编程思想,JAVA多线程设计模式,JAVA网络编程,以及JAVA NIO,适合初学者学习JAVA语言及项目开发模式
Java I/O学习笔记: 磁盘操作 字节操作 字符操作 对象操作 网络操作 NIO & AIO Java I/O Java是一种面向对象的编程语言,由Sun Microsystems于1995年推出。它是一种跨平台的语言,意味着可以在不同的操作系统上运行...
丛书名: 学习笔记 出版社:清华大学出版社 ISBN:9787302282082 上架时间:2012-5-9 出版日期:2012 年5月 开本:16开 页码:564 版次:1-1 所属分类:计算机 > 软件与程序设计 > JAVA(J#) > Java 编辑推荐 ...
尚硅谷java教程全程跟听,手动整理,从面向对象开始按章节按课时整理,适合对照视频作为笔试使用/java知识脉络梳理/八股理解背诵
Apache的Mina(Multipurpose Infrastructure Networked Applications)是一个网络应用框架,可以帮助...它提供了一个抽象的、事件驱动的异步API,使Java NIO在各种传输协议(如TCP/IP,UDP/IP协议等)下快速高效开发。
丰富的MINA实例介绍,java NIO 学习,mina快速入门宝典
最近使用Mina开发一个Java的NIO服务端程序,因此也特意学习了Apache的这个Mina框架。 引言 1 一. Mina入门 2 第一步.下载使用的Jar包 2 第二步.工程创建配置 2 第三步.服务端程序 3 第四步.客户端程序 6 第五步.长...