java nio socket

jdk供的无阻塞I/O(NIO)有效解决了多线程服务器存在的线程开销问题,但在使用上略显得复杂一些。在NIO中使用多线程,主要目的已不是为了应对每个客户端请求而分配独立的服务线程,而是通过多线程充分使用用多个CPU的处理能力和处理中的等待时间,达到提高服务能力的目的。

这段时间在研究NIO,写篇博客来记住学过的东西。还是从最简单的Hello World开始,

client多线程请求server端,server接收client的名字,并返回Hello! +名字的字符格式给client。当然实际应用并不这么简单,实际可能是访问文件或者数据库获取信息返回给client。非阻塞的NIO有何神秘之处?代码:

1)server端代码

Java代码  

  1. /**
  2. *
  3. * @author Jeff
  4. *
  5. */
  6. public class HelloWorldServer {
  7. static int BLOCK = 1024;
  8. static String name = "";
  9. protected Selector selector;
  10. protected ByteBuffer clientBuffer = ByteBuffer.allocate(BLOCK);
  11. protected CharsetDecoder decoder;
  12. static CharsetEncoder encoder = Charset.forName("GB2312").newEncoder();
  13. public HelloWorldServer(int port) throws IOException {
  14. selector = this.getSelector(port);
  15. Charset charset = Charset.forName("GB2312");
  16. decoder = charset.newDecoder();
  17. }
  18. // 获取Selector
  19. protected Selector getSelector(int port) throws IOException {
  20. ServerSocketChannel server = ServerSocketChannel.open();
  21. Selector sel = Selector.open();
  22. server.socket().bind(new InetSocketAddress(port));
  23. server.configureBlocking(false);
  24. server.register(sel, SelectionKey.OP_ACCEPT);
  25. return sel;
  26. }
  27. // 监听端口
  28. public void listen() {
  29. try {
  30. for (;;) {
  31. selector.select();
  32. Iterator iter = selector.selectedKeys().iterator();
  33. while (iter.hasNext()) {
  34. SelectionKey key = (SelectionKey) iter.next();
  35. iter.remove();
  36. process(key);
  37. }
  38. }
  39. } catch (IOException e) {
  40. e.printStackTrace();
  41. }
  42. }
  43. // 处理事件
  44. protected void process(SelectionKey key) throws IOException {
  45. if (key.isAcceptable()) { // 接收请求
  46. ServerSocketChannel server = (ServerSocketChannel) key.channel();
  47. SocketChannel channel = server.accept();
  48. //设置非阻塞模式
  49. channel.configureBlocking(false);
  50. channel.register(selector, SelectionKey.OP_READ);
  51. } else if (key.isReadable()) { // 读信息
  52. SocketChannel channel = (SocketChannel) key.channel();
  53. int count = channel.read(clientBuffer);
  54. if (count > 0) {
  55. clientBuffer.flip();
  56. CharBuffer charBuffer = decoder.decode(clientBuffer);
  57. name = charBuffer.toString();
  58. // System.out.println(name);
  59. SelectionKey sKey = channel.register(selector,
  60. SelectionKey.OP_WRITE);
  61. sKey.attach(name);
  62. } else {
  63. channel.close();
  64. }
  65. clientBuffer.clear();
  66. } else if (key.isWritable()) { // 写事件
  67. SocketChannel channel = (SocketChannel) key.channel();
  68. String name = (String) key.attachment();
  69. ByteBuffer block = encoder.encode(CharBuffer
  70. .wrap("Hello !" + name));
  71. channel.write(block);
  72. //channel.close();
  73. }
  74. }
  75. public static void main(String[] args) {
  76. int port = 8888;
  77. try {
  78. HelloWorldServer server = new HelloWorldServer(port);
  79. System.out.println("listening on " + port);
  80. server.listen();
  81. } catch (IOException e) {
  82. e.printStackTrace();
  83. }
  84. }
  85. }

server主要是读取client发过来的信息,并返回一条信息

2)client端代码

Java代码  

  1. /**
  2. *
  3. * @author Jeff
  4. *
  5. */
  6. public class HelloWorldClient {
  7. static int SIZE = 10;
  8. static InetSocketAddress ip = new InetSocketAddress("localhost", 8888);
  9. static CharsetEncoder encoder = Charset.forName("GB2312").newEncoder();
  10. static class Message implements Runnable {
  11. protected String name;
  12. String msg = "";
  13. public Message(String index) {
  14. this.name = index;
  15. }
  16. public void run() {
  17. try {
  18. long start = System.currentTimeMillis();
  19. //打开Socket通道
  20. SocketChannel client = SocketChannel.open();
  21. //设置为非阻塞模式
  22. client.configureBlocking(false);
  23. //打开选择器
  24. Selector selector = Selector.open();
  25. //注册连接服务端socket动作
  26. client.register(selector, SelectionKey.OP_CONNECT);
  27. //连接
  28. client.connect(ip);
  29. //分配内存
  30. ByteBuffer buffer = ByteBuffer.allocate(8 * 1024);
  31. int total = 0;
  32. _FOR: for (;;) {
  33. selector.select();
  34. Iterator iter = selector.selectedKeys().iterator();
  35. while (iter.hasNext()) {
  36. SelectionKey key = (SelectionKey) iter.next();
  37. iter.remove();
  38. if (key.isConnectable()) {
  39. SocketChannel channel = (SocketChannel) key
  40. .channel();
  41. if (channel.isConnectionPending())
  42. channel.finishConnect();
  43. channel
  44. .write(encoder
  45. .encode(CharBuffer.wrap(name)));
  46. channel.register(selector, SelectionKey.OP_READ);
  47. } else if (key.isReadable()) {
  48. SocketChannel channel = (SocketChannel) key
  49. .channel();
  50. int count = channel.read(buffer);
  51. if (count > 0) {
  52. total += count;
  53. buffer.flip();
  54. while (buffer.remaining() > 0) {
  55. byte b = buffer.get();
  56. msg += (char) b;
  57. }
  58. buffer.clear();
  59. } else {
  60. client.close();
  61. break _FOR;
  62. }
  63. }
  64. }
  65. }
  66. double last = (System.currentTimeMillis() - start) * 1.0 / 1000;
  67. System.out.println(msg + "used time :" + last + "s.");
  68. msg = "";
  69. } catch (IOException e) {
  70. e.printStackTrace();
  71. }
  72. }
  73. }
  74. public static void main(String[] args) throws IOException {
  75. String names[] = new String[SIZE];
  76. for (int index = 0; index < SIZE; index++) {
  77. names[index] = "jeff[" + index + "]";
  78. new Thread(new Message(names[index])).start();
  79. }
  80. }
  81. }
时间: 2024-08-24 06:24:17

java nio socket的相关文章

java NIO socket 通信实例

java Nio 通信与Bio通信主要不同点: 1.Nio中的单个channel即可支持读操作也可以支持写操作,而bio中读操作要用inputstream,写操作要outputstream. 2.nio 采用byteBuffer 作为内存缓存区,向channel里写或者度操作,bio基本是用byte[] 3.nio采用 selector组件轮询读取就绪channel 服务端demo代码: package com.my.socket3; import java.io.ByteArrayOutput

Java nio socket与as3 socket(粘包解码)连接的应用实例

对Java nio socket与as3 socket连接的简单应用 <ignore_js_op>Java nio socket与as3 socket连接的应用实例.rar (9.61 KB, 下载次数: 1691) 这个从基本的弄起太复杂了,我弄个了mina与flash通信的,通信数据模式是dataLength+data(数据长度+数据内容),对于socket字节流通信,我习惯用这种方式,方便粘包解码处理.其中已包含所需的jar包,客户端代码须另自写,不可沿用.flash socket发送的

动手编写Java NIO Socket测试工具

最近一年接触到些使用Java NIO编写的服务器程序,客户程序通过建立Socket连接并发送消息的方式调用服务端提供的交易接口. 开发的时候通常需要发些消息来调试程序,所以自己动手写了个工具.工具使用Swing编写,主要作用就是向指定的IP.端口发送请求消息,并接收响应消息.非常简单,但是足够了. 源代码涉及到以下内容: (1)Java Swing编程中的EDT线程与任务线程,在后台任务线程中执行耗时操作,并在适当的时候更新UI: (2)提供一种Swing界面的构造方式:构造Component.

Java Nio Socket通讯

Server端: #############服务器端连接请求处理############### public class MultiplexerServer implements Runnable { /**多路复用器,SocketChannel注册到Selector.Selector轮询监听Channel网络事件*/ private Selector selector; private ServerSocketChannel serverSocketChannel; private boole

基于Java NIO的Socket通信

Java NIO模式的Socket通信,是一种同步非阻塞IO设计模式,它为Reactor模式实现提供了基础. 下面看看,Java实现的一个服务端和客户端通信的例子. NIO模式的基本原理描述如下: 服务端打开一个通道(ServerSocketChannel),并向通道中注册一个选择器(Selector),这个选择器是与一些感兴趣的操作的标识(SelectionKey,即通过这个标识可以定位到具体的操作,从而进行响应的处理)相关联的,然后基于选择器(Selector)轮询通道(ServerSock

java,Socket,NIO随笔记录

这个答案答的很好.Socket与SocketChannel是俩套api而已,对于网络tcp通信而言不会关心你上层是用何api实现通信的.所以答案是肯定的.SocketChannel可以设置为非阻塞的,所以在某种情况下性能更好,线程不会被挂住.SocketChannel还能注册selector和感兴趣的事件.selector多路复用器这里就不多做介绍了. 在这里介绍一下通信过程中数据的流动过程.首先当数据被网卡接收后,会被保存到内核中,电脑进行拆包解析,看源端口号,会将此数据包保存到对应链接的tc

Java nio 笔记:系统IO、缓冲区、流IO、socket通道

一.Java IO 和 系统 IO 不匹配 在大多数情况下,Java 应用程序并非真的受着 I/O 的束缚.操作系统并非不能快速传送数据,让 Java 有事可做:相反,是 JVM 自身在 I/O 方面效率欠佳.操作系统与 Java 基于流的 I/O模型有些不匹配.操作系统要移动的是大块数据(缓冲区),这往往是在硬件直接存储器存取(DMA)的协助下完成的.而 JVM 的 I/O 操作类喜欢操作小块数据--单个字节.几行文本.结果,操作系统送来整缓冲区的数据,java.io 包的流数据类再花大量时间

Java NIO 非阻塞Socket服务器构建

部分内容引用自xpbug的Blog. 说到socket服务器,第一反应是java.net.Socket这个类.事实上在并发和响应时间要求不高的场合,是可以用java.net.Socket来实现的,比如写一个局域网聊天工具.发送文件等.但它的缺点也很明显,需要自行对接受的线程进行维护,管理缓冲区的分配等,我尝试过用java.net.Socket完成一个瞬时负载在千人左右的服务器,却因后期改动和维护异常麻烦而放弃. Java自1.4以后,加入了新IO特性,这便是本文要介绍的NIO.下面是一段服务器的

Java NIO 之 Socket Channel

在Java NIO中用Channel来对程序与进行I/O操作主体的连接关系进行抽象,这些IO主体包括如文件.Socket或其他设备.简而言之,指代了一种与IO操作对象间的连接关系. 按照Channel接口的定义,Channel只有open和closed两种状态,只有在channel处于open状态下对其操作时才有效,而对closed的channel进行操作会导致抛出异常.相应的Channel接口也仅有isOpen()和close()两种方法. 在Socket编程中,常用的Channel类是Ser