java nio socket通信简单入门示例
2015-11-22 12:11
429 查看
基本的Java套接字对于小规模系统可以很好地运行,但当涉及到要同时处理上千个客户端的服务器时,可能就会产生一些问题.由于创建、维护和切换线程需要的系统开销,一客户一线程方式在系统扩展性方面受到了限制。使用线程池可以节省那种系统开销,同时允许实现者利用并行硬件的优势。但对于连接生存期比较长的协议来说,线程池的大小仍然限制了系统可以同时处理的客户端数量。考虑一个在客户端之间传递消息的即时消息服务器(Instant
Messaging)。客户端必须不停地连接服务器以接收即时消息,因此线程池的大小限制了系统可以同时服务的客户端总数。如果增加线程池的大小,将带来更多的线程处理开销,而不能提升系统的性能,因为在大部分的时间里客户端是处于闲置状态的。
如果这就是所有问题,可能NIO还不是必要的。不幸的是,在使用线程的扩展性方面还涉及一些更加难以把握的挑战。其中一个挑战就是程序员几乎不能对什么时候哪个线程将获得服务进行控制。你可以设置一个线程实例的优先级(priority)(高优先级的线程相对于低优先级的线程有优先权),但是这个优先级只是一种"建议"--下一个选择执行的线程完全取决于具体实现。因此,如果程序员想要保证某些连接优先获得服务,或想要指定一定的服务顺序,线程可能就很难做到。
我们需要一种方法来一次轮询一组客户端,以查找哪个客户端需要服务。这正是NIO中将要介绍的Selector和Channel抽象的关键点。一个Channel实例代表了一个"可轮询的(pollable)"I/O目标,如套接字(或一个文件、设备等)。Channel能够注册一个Selector类的实例。Selector的select()方法允许你询问"在一组信道中,哪一个当前需要服务(即,被接受,读或写)?"大量的细节将在后文中介绍,但这就是使用Selector和Channel的基本动机。这两个类都包含在java.nio.channels包中。
摘自《java tcp/ip socket编程》
下面自己实现了一个单线程的通信。
server:
import java.io.BufferedReader; import java.io.InputStreamReader; 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.util.Iterator; /* * Server */ public class NioTcpServer1 { public static void main(String[] args) throws Exception { //open ServerSocketChannel ServerSocketChannel server = ServerSocketChannel.open(); // bind port server.bind(new InetSocketAddress(10000)); //set noblocking server.configureBlocking(false); //open selector Selector selector = Selector.open(); //register accept event server.register(selector, SelectionKey.OP_ACCEPT); System.out.println("=======server start======="); while (true) { while (selector.select() > 0) { Iterator<SelectionKey> iter = selector.selectedKeys() .iterator(); while (iter.hasNext()) { SelectionKey key = iter.next(); //avoid duplication iter.remove(); //accept if (key.isAcceptable()) { SocketChannel channel = ((ServerSocketChannel) (key .channel())).accept(); channel.configureBlocking(false); //register read and write channel.register(selector, SelectionKey.OP_READ | SelectionKey.OP_WRITE); System.out.println("server accept client"); channel.write(ByteBuffer.wrap("server already \r\n".getBytes())); } //read if (key.isReadable()) { SocketChannel channel = (SocketChannel) key.channel(); ByteBuffer buffer = ByteBuffer.allocate(20); int len = 0; while (0 != (len = channel.read(buffer))) { System.out.println(new String(buffer.array(), 0, len)); buffer.clear(); } } //write if (key.isWritable()) { System.out.print("server#: "); BufferedReader read = new BufferedReader( new InputStreamReader(System.in)); String line = read.readLine(); SocketChannel channel = (SocketChannel) key.channel(); //send some data channel.write(ByteBuffer.wrap((line + "\r\n").getBytes())); } //set network delay Thread.sleep(2000); } } } } }
client:
import java.io.BufferedReader; import java.io.InputStreamReader; import java.net.InetSocketAddress; import java.nio.ByteBuffer; import java.nio.channels.SelectionKey; import java.nio.channels.Selector; import java.nio.channels.SocketChannel; import java.util.Iterator; /* * Client */ public class NioTcpClient1 { public static void main(String[] args)throws Exception { //get socketchannel SocketChannel client = SocketChannel.open(); //set no blocking client.configureBlocking(false); //connect to remote address client.connect(new InetSocketAddress("localhost", 10000)); //open selector Selector selector = Selector.open(); //register connection event client.register(selector, SelectionKey.OP_CONNECT); System.out.println("=====client start===="); while(true) { if(selector.select()>0) { Iterator<SelectionKey> iter = selector.selectedKeys().iterator(); while(iter.hasNext()) { SelectionKey key = iter.next(); //avoid duplication iter.remove(); //obtain current channel SocketChannel channel = (SocketChannel) key.channel(); //connect if(key.isConnectable()) { //register read and write channel.register(selector, SelectionKey.OP_READ | SelectionKey.OP_WRITE); //finish connect channel.finishConnect(); System.out.println("client connection server"); channel.write(ByteBuffer.wrap("client prepare \r\n".getBytes())); } //read if(key.isReadable()) { ByteBuffer buffer = ByteBuffer.allocate(20); int len = -1; while(0 != (len = channel.read(buffer))) { System.out.println(new String(buffer.array(), 0, len)); buffer.clear(); } } //write if(key.isWritable()) { System.out.print("client#: "); BufferedReader read = new BufferedReader( new InputStreamReader(System.in)); String line = read.readLine(); //send some data channel.write(ByteBuffer.wrap((line + "\r\n").getBytes())); } //set network delay Thread.sleep(2000); } } } } }
效果:
相关文章推荐
- jaxws webservice spring 注入 解决NullPointerException
- java设计模式-装饰者模式
- java制作简单日历
- 《疯狂Java讲义》第1章——Java语言概述与开发环境
- 我的第三个java程序 两数相加
- sublime添加eclipse快捷键
- java后台发起请求方式
- rk3288_android5.1__android4.4 jdk1.6和jdk1.7共存问题 ubuntu java7 The required version is: "1.7.x"
- springMvc实现
- 我的第二个java程序 循环
- Java学习笔记之卡片式布局CardLayout
- java环境搭建
- Eclipse导入第三方库的方法
- 使用最新版的eclipse配置sturts2的常见错误及解决方案
- Java局部变量
- java AES对称加解密
- Java实现1900年1月1日到2016年5月7日一共多少天?
- Java多态中的注意事项
- java中sleep和wait区别
- springMVC与shiro整合与自定义验证码用户类型类