java TCP/IP Socket编程-----NIO--初识-----笔记8
来源:互联网 发布:webservice json 编辑:程序博客网 时间:2024/04/26 20:04
概述:
NIO主要包括两个部分:java.nio.channels包介绍了Selector和Channel抽象,java.nio包介绍了Buffer抽象。这都是一些高级的特性,有许多微妙的使用细节,它与socket类似,但是它主要区别,socket是乡村公路,NIO就是高速公路,socket容易阻塞,而NIO可以设置不阻塞。NIO更加充分利用系统的资源。
术语:
Selector:选择渠道
Channel: (一个与设备连接的实例,与socket不同通常它调用静态的方法进行实例化)Channel直接使用的不是流,而是缓存区,Channel可以配置非阻塞
Buffer:缓存IO流 buffer是具体基本类型Buffer ,通过allocate进行分配,也可以包装现有的数组
1.一个简单例子package com.tcp.ip.chapter5;import java.net.InetSocketAddress;import java.net.SocketException;import java.nio.ByteBuffer;import java.nio.channels.SocketChannel;public class TCPEchoClientNonblocking {public static void main(String args[]) throws Exception {if((args.length < 2) || (args.length > 3)) {throw new IllegalArgumentException("Parameters : <Server> <Word> [<Port>]");}String server = args[0];byte[] argument = args[1].getBytes();int servPort = (args.length == 3) ? Integer.parseInt(args[2]) : 7;//socket 变成 SocketChannel ,它静态方法实例化SocketChannel clntChan = SocketChannel.open();//配置非阻塞快clntChan.configureBlocking(false);if(!clntChan.connect(new InetSocketAddress(server, servPort))) {//一直在连接,知道结束while (!clntChan.finishConnect()) {System.out.println(".");}}//包装流ByteBuffer writeBuf = ByteBuffer.wrap(argument);ByteBuffer readBuf = ByteBuffer.allocate(argument.length);int totalBytesRcvd = 0;int bytesRcvd;//一直读取数据while (totalBytesRcvd < argument.length) {//如果写缓存流有数据,继续写if(writeBuf.hasRemaining()) {clntChan.write(writeBuf);}//读取到-1表示最后的字符if ((bytesRcvd = clntChan.read(readBuf)) == -1) {throw new SocketException("Connection closed prematurely");}totalBytesRcvd += bytesRcvd;System.out.println(".");}//打印读取数据System.out.println("Received:" + new String (readBuf.array(), 0, totalBytesRcvd));clntChan.close();}}
总结:对比学习,来找茬
- 1.Socket 变成 SocketChannel ,而且不是new,是调用静态方法 open() ,(定位是高速公路)
- 2.SocketChannel可以设置是否阻塞 调用方法 configureBlocking(false), Socket不可以
- 3.对于传输的数据都是缓存,写缓存通过包装byte[] ,调用方法wrap(目标byte[]) (wrap本身就是包装,打包) ,而socket是通过getOutStream() 直接操作流
- 4.对于读缓存采用allocate(容器大小)(allocate 分配的意思) 就像你那个盒子来装东西,而socket是通过getInputStream
- 5.对于缓存区是否还有数据通过方法是 hasRemaining()
- 6.将缓存变成byte[] 调用 缓存对象.array()
服务端协议
package com.tcp.ip.chapter5;import java.io.IOException;import java.nio.channels.SelectionKey;public interface TCPProtocol {/**处理连接 * @param key * @throws IOException */void handleAccept(SelectionKey key) throws IOException;/** * 处理读 * @param key * @throws IOException */void handleRead(SelectionKey key) throws IOException;/** * 处理写 * @param key * @throws IOException */void handleWrite(SelectionKey key) throws IOException;}
总结:服务主要的干的活分一下类,一个请求,一个读,一个写
package com.tcp.ip.chapter5;import java.io.IOException;import java.nio.ByteBuffer;import java.nio.channels.SelectionKey;import java.nio.channels.ServerSocketChannel;import java.nio.channels.SocketChannel;public class EchoSelectorProtocol implements TCPProtocol {//缓存大小private int bufSize;public EchoSelectorProtocol(int bufSize) {this.bufSize = bufSize;}public void handleAccept(SelectionKey key) throws IOException {SocketChannel clntChan = ((ServerSocketChannel) key.channel()).accept();//非阻塞注册clntChan.configureBlocking(false);//clntChan.register(key.selector(), SelectionKey.OP_READ, ByteBuffer.allocate(bufSize));}public void handleRead(SelectionKey key) throws IOException {SocketChannel clntChan = (SocketChannel) key.channel();ByteBuffer buf = (ByteBuffer) key.attachment();long bytesRead = clntChan.read(buf);if(bytesRead == -1) {clntChan.close();} else if (bytesRead >0) {key.interestOps(SelectionKey.OP_READ | SelectionKey.OP_WRITE);}} public void handleWrite(SelectionKey key) throws IOException {//取回数据ByteBuffer buf = (ByteBuffer)key.attachment();//准备缓存区写buf.flip();SocketChannel clntChan = (SocketChannel)key.channel();clntChan.write(buf);//完全写完啦?if(!buf.hasRemaining()) {key.interestOps(SelectionKey.OP_READ);}buf.compact();}}总结:具体实现 ,是不是类似医院操作
1.handleAccept() 处理请求,也就相当于医院挂号,将你的信息录入到系统的中,完成注册功能
2.handleRead() 读取数据 ,这时候你到对于科室去看医院,医生根据你描述的症状进行判断
3.handleWrite() 写数据, 这时候医生根据你的描述,确诊什么?开什么?注意什么?,写病历本上,你就下去抓药
4.key.interestOps对什么感兴趣,SelectionKey.OP_READ 读 SelectKey.OP_WRITE。
5.key.attachment() 获取缓存数据
package com.tcp.ip.chapter5;import java.io.IOException;import java.net.InetSocketAddress;import java.nio.channels.SelectionKey;import java.nio.channels.Selector;import java.nio.channels.ServerSocketChannel;import java.util.Iterator;public class TCPServerSelector {private static final int BUFSIZE = 256;private static final int TIMEOUT = 3000;public static void main(String[] args) throws IOException{if(args.length < 1){throw new IllegalArgumentException("Parameter(s): <Port>...");}Selector selector = Selector.open();for (String arg : args){ServerSocketChannel listnChannel = ServerSocketChannel.open();//好像可以绑定多个端口listnChannel.socket().bind(new InetSocketAddress(Integer.parseInt(arg)));//非阻塞注册listnChannel.configureBlocking(false);//返回的key是忽略的listnChannel.register(selector, SelectionKey.OP_ACCEPT);TCPProtocol protocol = new EchoSelectorProtocol(BUFSIZE);//一直运行while(true) {//等待一些渠道if(selector.select(TIMEOUT) == 0) {System.out.println(".");continue;}//得到迭代IO 就是所有请求的该端口度应该经过selector管理,类似存在map中k-v键值对Iterator<SelectionKey> keyIter = selector.selectedKeys().iterator();while (keyIter.hasNext()) {SelectionKey key = keyIter.next();if(key.isAcceptable()) {protocol.handleAccept(key);}if(key.isReadable()){protocol.handleRead(key);}if(key.isValid() && key.isWritable()){protocol.handleWrite(key);}keyIter.remove();}}}}}
总结:
1.一个channel绑定一个端口
2.一个channel注册到selector上,用selector进行管理
3.selector根据当前状态对通道进行相应的处理
自己理解不够,如果什么误导的地方,深感歉意,也欢迎指出。
- java TCP/IP Socket编程-----NIO--初识-----笔记8
- java TCP/IP Socket编程-----NIO--TCP信道-----笔记11
- java TCP/IP Socket编程-----NIO--Buffer-----笔记10
- 初识Java TCP/IP Socket-TCP网络编程知识
- Java TCP/IP Socket 编程 笔记
- 初识Java TCP/IP Socket-UDP网络编程知识
- java TCP/IP Socket编程-----进阶--多线程-----笔记8
- TCP/IP的Socket编程(初识)
- Java TCP/IP Socket 编程 笔记—TCP的例子
- Java Socket编程(3)初识TCP Socket
- Java Socket编程(3)初识TCP Socket
- 《Java TCP/IP Socket编程》读书笔记(8)
- java tcp/ip socket编程
- Java TCP/IP Socket编程
- Java TCP/IP Socket编程
- Java、TCP/IP、Socket编程
- Java TCP/IP Socket,基于NIO的TCP通信
- java TCP/IP Socket编程-----纵览全书-----笔记1
- 自适应布局下的图片垂直水平居中,自适应手机横竖屏
- c++ list, vector, map, set 区别与用法比较
- tab标签(选项卡)切换实现
- DataSnap之000
- 兼容低版本浏览器的图片选择预览方案
- java TCP/IP Socket编程-----NIO--初识-----笔记8
- 数据连接池的工作机制是什么?
- cs call
- 如何分析GPSLog 转载
- Maven使用代理方式联网连接服务器
- css3动画:animation城市动画
- android MediaCodec解析
- UnityShader案例(四)——单张纹理
- SaaS架构设计