`
coconut_zhang
  • 浏览: 543811 次
  • 性别: Icon_minigender_1
  • 来自: 天津
社区版块
存档分类
最新评论

Java Socket实战之六 使用NIO包实现Socket通信 .

    博客分类:
  • java
 
阅读更多

前面几篇文章介绍了使用java.io和java.net类库实现的Socket通信,下面介绍一下使用java.nio类库实现的Socket。

java.nio包是Java在1.4之后增加的,用来提高I/O操作的效率。在nio包中主要包括以下几个类或接口:

* Buffer:缓冲区,用来临时存放输入或输出数据。

* Charset:用来把Unicode字符编码和其它字符编码互转。

* Channel:数据传输通道,用来把Buffer中的数据写入到数据源,或者把数据源中的数据读入到Buffer。

* Selector:用来支持异步I/O操作,也叫非阻塞I/O操作。

 

nio包中主要通过下面两个方面来提高I/O操作效率:

* 通过Buffer和Channel来提高I/O操作的速度。

* 通过Selector来支持非阻塞I/O操作。

 

下面来看一下程序中是怎么通过这些类库实现Socket功能。

 

首先介绍一下几个辅助类

辅助类SerializableUtil,这个类用来把java对象序列化成字节数组,或者把字节数组反序列化成java对象。

 

  1. package com.googlecode.garbagecan.test.socket;  
  2.   
  3. import java.io.ByteArrayInputStream;  
  4. import java.io.ByteArrayOutputStream;  
  5. import java.io.IOException;  
  6. import java.io.ObjectInputStream;  
  7. import java.io.ObjectOutputStream;  
  8.   
  9. public class SerializableUtil {  
  10.       
  11.     public static byte[] toBytes(Object object) {  
  12.         ByteArrayOutputStream baos = new ByteArrayOutputStream();  
  13.         ObjectOutputStream oos = null;  
  14.         try {  
  15.             oos = new ObjectOutputStream(baos);  
  16.             oos.writeObject(object);  
  17.             byte[] bytes = baos.toByteArray();  
  18.             return bytes;  
  19.         } catch(IOException ex) {  
  20.             throw new RuntimeException(ex.getMessage(), ex);  
  21.         } finally {  
  22.             try {  
  23.                 oos.close();  
  24.             } catch (Exception e) {}  
  25.         }  
  26.     }  
  27.       
  28.     public static Object toObject(byte[] bytes) {  
  29.         ByteArrayInputStream bais = new ByteArrayInputStream(bytes);  
  30.         ObjectInputStream ois = null;  
  31.         try {  
  32.             ois = new ObjectInputStream(bais);  
  33.             Object object = ois.readObject();  
  34.             return object;  
  35.         } catch(IOException ex) {  
  36.             throw new RuntimeException(ex.getMessage(), ex);  
  37.         } catch(ClassNotFoundException ex) {  
  38.             throw new RuntimeException(ex.getMessage(), ex);  
  39.         } finally {  
  40.             try {  
  41.                 ois.close();  
  42.             } catch (Exception e) {}  
  43.         }  
  44.     }  
  45. }  

辅助类MyRequestObject和MyResponseObject,这两个类是普通的java对象,实现了Serializable接口。MyRequestObject类是Client发出的请求,MyResponseObject是Server端作出的响应。

 

 

  1. package com.googlecode.garbagecan.test.socket.nio;  
  2.   
  3. import java.io.Serializable;  
  4.   
  5. public class MyRequestObject implements Serializable {  
  6.   
  7.     private static final long serialVersionUID = 1L;  
  8.   
  9.     private String name;  
  10.       
  11.     private String value;  
  12.   
  13.     private byte[] bytes;  
  14.       
  15.     public MyRequestObject(String name, String value) {  
  16.         this.name = name;  
  17.         this.value = value;  
  18.         this.bytes = new byte[1024];  
  19.     }  
  20.       
  21.     public String getName() {  
  22.         return name;  
  23.     }  
  24.   
  25.     public void setName(String name) {  
  26.         this.name = name;  
  27.     }  
  28.   
  29.     public String getValue() {  
  30.         return value;  
  31.     }  
  32.   
  33.     public void setValue(String value) {  
  34.         this.value = value;  
  35.     }  
  36.       
  37.     @Override  
  38.     public String toString() {  
  39.         StringBuffer sb = new StringBuffer();  
  40.         sb.append("Request [name: " + name  + ", value: " + value + ", bytes: " + bytes.length+ "]");  
  41.         return sb.toString();  
  42.     }  
  43. }  
  44.   
  45. package com.googlecode.garbagecan.test.socket.nio;  
  46.   
  47. import java.io.Serializable;  
  48.   
  49. public class MyResponseObject implements Serializable {  
  50.   
  51.     private static final long serialVersionUID = 1L;  
  52.   
  53.     private String name;  
  54.       
  55.     private String value;  
  56.   
  57.     private byte[] bytes;  
  58.       
  59.     public MyResponseObject(String name, String value) {  
  60.         this.name = name;  
  61.         this.value = value;  
  62.         this.bytes = new byte[1024];  
  63.     }  
  64.       
  65.     public String getName() {  
  66.         return name;  
  67.     }  
  68.   
  69.     public void setName(String name) {  
  70.         this.name = name;  
  71.     }  
  72.   
  73.     public String getValue() {  
  74.         return value;  
  75.     }  
  76.   
  77.     public void setValue(String value) {  
  78.         this.value = value;  
  79.     }  
  80.       
  81.     @Override  
  82.     public String toString() {  
  83.         StringBuffer sb = new StringBuffer();  
  84.         sb.append("Response [name: " + name  + ", value: " + value + ", bytes: " + bytes.length+ "]");  
  85.         return sb.toString();  
  86.     }  
  87. }  


下面主要看一下Server端的代码,其中有一些英文注释对理解代码很有帮助,注释主要是来源jdk的文档和例子,这里就没有再翻译

 

 

  1. package com.googlecode.garbagecan.test.socket.nio;  
  2.   
  3. import java.io.ByteArrayOutputStream;  
  4. import java.io.IOException;  
  5. import java.net.InetSocketAddress;  
  6. import java.nio.ByteBuffer;  
  7. import java.nio.channels.ClosedChannelException;  
  8. import java.nio.channels.SelectionKey;  
  9. import java.nio.channels.Selector;  
  10. import java.nio.channels.ServerSocketChannel;  
  11. import java.nio.channels.SocketChannel;  
  12. import java.util.Iterator;  
  13. import java.util.logging.Level;  
  14. import java.util.logging.Logger;  
  15.   
  16. import com.googlecode.garbagecan.test.socket.SerializableUtil;  
  17.   
  18. public class MyServer3 {  
  19.   
  20.     private final static Logger logger = Logger.getLogger(MyServer3.class.getName());  
  21.       
  22.     public static void main(String[] args) {  
  23.         Selector selector = null;  
  24.         ServerSocketChannel serverSocketChannel = null;  
  25.           
  26.         try {  
  27.             // Selector for incoming time requests   
  28.             selector = Selector.open();  
  29.   
  30.             // Create a new server socket and set to non blocking mode   
  31.             serverSocketChannel = ServerSocketChannel.open();  
  32.             serverSocketChannel.configureBlocking(false);  
  33.               
  34.             // Bind the server socket to the local host and port   
  35.             serverSocketChannel.socket().setReuseAddress(true);  
  36.             serverSocketChannel.socket().bind(new InetSocketAddress(10000));  
  37.               
  38.             // Register accepts on the server socket with the selector. This   
  39.             // step tells the selector that the socket wants to be put on the   
  40.             // ready list when accept operations occur, so allowing multiplexed   
  41.             // non-blocking I/O to take place.   
  42.             serverSocketChannel.register(selector, SelectionKey.OP_ACCEPT);  
  43.       
  44.             // Here's where everything happens. The select method will   
  45.             // return when any operations registered above have occurred, the   
  46.             // thread has been interrupted, etc.   
  47.             while (selector.select() > 0) {  
  48.                 // Someone is ready for I/O, get the ready keys   
  49.                 Iterator<SelectionKey> it = selector.selectedKeys().iterator();  
  50.       
  51.                 // Walk through the ready keys collection and process date requests.   
  52.                 while (it.hasNext()) {  
  53.                     SelectionKey readyKey = it.next();  
  54.                     it.remove();  
  55.                       
  56.                     // The key indexes into the selector so you   
  57.                     // can retrieve the socket that's ready for I/O   
  58.                     execute((ServerSocketChannel) readyKey.channel());  
  59.                 }  
  60.             }  
  61.         } catch (ClosedChannelException ex) {  
  62.             logger.log(Level.SEVERE, null, ex);  
  63.         } catch (IOException ex) {  
  64.             logger.log(Level.SEVERE, null, ex);  
  65.         } finally {  
  66.             try {  
  67.                 selector.close();  
  68.             } catch(Exception ex) {}  
  69.             try {  
  70.                 serverSocketChannel.close();  
  71.             } catch(Exception ex) {}  
  72.         }  
  73.     }  
  74.   
  75.     private static void execute(ServerSocketChannel serverSocketChannel) throws IOException {  
  76.         SocketChannel socketChannel = null;  
  77.         try {  
  78.             socketChannel = serverSocketChannel.accept();  
  79.             MyRequestObject myRequestObject = receiveData(socketChannel);  
  80.             logger.log(Level.INFO, myRequestObject.toString());  
  81.               
  82.             MyResponseObject myResponseObject = new MyResponseObject(  
  83.                     "response for " + myRequestObject.getName(),   
  84.                     "response for " + myRequestObject.getValue());  
  85.             sendData(socketChannel, myResponseObject);  
  86.             logger.log(Level.INFO, myResponseObject.toString());  
  87.         } finally {  
  88.             try {  
  89.                 socketChannel.close();  
  90.             } catch(Exception ex) {}  
  91.         }  
  92.     }  
  93.       
  94.     private static MyRequestObject receiveData(SocketChannel socketChannel) throws IOException {  
  95.         MyRequestObject myRequestObject = null;  
  96.         ByteArrayOutputStream baos = new ByteArrayOutputStream();  
  97.         ByteBuffer buffer = ByteBuffer.allocate(1024);  
  98.           
  99.         try {  
  100.             byte[] bytes;  
  101.             int size = 0;  
  102.             while ((size = socketChannel.read(buffer)) >= 0) {  
  103.                 buffer.flip();  
  104.                 bytes = new byte[size];  
  105.                 buffer.get(bytes);  
  106.                 baos.write(bytes);  
  107.                 buffer.clear();  
  108.             }  
  109.             bytes = baos.toByteArray();  
  110.             Object obj = SerializableUtil.toObject(bytes);  
  111.             myRequestObject = (MyRequestObject)obj;  
  112.         } finally {  
  113.             try {  
  114.                 baos.close();  
  115.             } catch(Exception ex) {}  
  116.         }  
  117.         return myRequestObject;  
  118.     }  
  119.   
  120.     private static void sendData(SocketChannel socketChannel, MyResponseObject myResponseObject) throws IOException {  
  121.         byte[] bytes = SerializableUtil.toBytes(myResponseObject);  
  122.         ByteBuffer buffer = ByteBuffer.wrap(bytes);  
  123.         socketChannel.write(buffer);  
  124.     }  
  125. }  

下面是Client的代码,代码比较简单就是启动了100个线程来访问Server

 

 

  1. package com.googlecode.garbagecan.test.socket.nio;  
  2.   
  3. import java.io.ByteArrayOutputStream;  
  4. import java.io.IOException;  
  5. import java.net.InetSocketAddress;  
  6. import java.net.SocketAddress;  
  7. import java.nio.ByteBuffer;  
  8. import java.nio.channels.SocketChannel;  
  9. import java.util.logging.Level;  
  10. import java.util.logging.Logger;  
  11.   
  12. import com.googlecode.garbagecan.test.socket.SerializableUtil;  
  13.   
  14. public class MyClient3 {  
  15.   
  16.     private final static Logger logger = Logger.getLogger(MyClient3.class.getName());  
  17.       
  18.     public static void main(String[] args) throws Exception {  
  19.         for (int i = 0; i < 100; i++) {  
  20.             final int idx = i;  
  21.             new Thread(new MyRunnable(idx)).start();  
  22.         }  
  23.     }  
  24.       
  25.     private static final class MyRunnable implements Runnable {  
  26.           
  27.         private final int idx;  
  28.   
  29.         private MyRunnable(int idx) {  
  30.             this.idx = idx;  
  31.         }  
  32.   
  33.         public void run() {  
  34.             SocketChannel socketChannel = null;  
  35.             try {  
  36.                 socketChannel = SocketChannel.open();  
  37.                 SocketAddress socketAddress = new InetSocketAddress("localhost"10000);  
  38.                 socketChannel.connect(socketAddress);  
  39.   
  40.                 MyRequestObject myRequestObject = new MyRequestObject("request_" + idx, "request_" + idx);  
  41.                 logger.log(Level.INFO, myRequestObject.toString());  
  42.                 sendData(socketChannel, myRequestObject);  
  43.                   
  44.                 MyResponseObject myResponseObject = receiveData(socketChannel);  
  45.                 logger.log(Level.INFO, myResponseObject.toString());  
  46.             } catch (Exception ex) {  
  47.                 logger.log(Level.SEVERE, null, ex);  
  48.             } finally {  
  49.                 try {  
  50.                     socketChannel.close();  
  51.                 } catch(Exception ex) {}  
  52.             }  
  53.         }  
  54.   
  55.         private void sendData(SocketChannel socketChannel, MyRequestObject myRequestObject) throws IOException {  
  56.             byte[] bytes = SerializableUtil.toBytes(myRequestObject);  
  57.             ByteBuffer buffer = ByteBuffer.wrap(bytes);  
  58.             socketChannel.write(buffer);  
  59.             socketChannel.socket().shutdownOutput();  
  60.         }  
  61.   
  62.         private MyResponseObject receiveData(SocketChannel socketChannel) throws IOException {  
  63.             MyResponseObject myResponseObject = null;  
  64.             ByteArrayOutputStream baos = new ByteArrayOutputStream();  
  65.               
  66.             try {  
  67.                 ByteBuffer buffer = ByteBuffer.allocateDirect(1024);  
  68.                 byte[] bytes;  
  69.                 int count = 0;  
  70.                 while ((count = socketChannel.read(buffer)) >= 0) {  
  71.                     buffer.flip();  
  72.                     bytes = new byte[count];  
  73.                     buffer.get(bytes);  
  74.                     baos.write(bytes);  
  75.                     buffer.clear();  
  76.                 }  
  77.                 bytes = baos.toByteArray();  
  78.                 Object obj = SerializableUtil.toObject(bytes);  
  79.                 myResponseObject = (MyResponseObject) obj;  
  80.                 socketChannel.socket().shutdownInput();  
  81.             } finally {  
  82.                 try {  
  83.                     baos.close();  
  84.                 } catch(Exception ex) {}  
  85.             }  
  86.             return myResponseObject;  
  87.         }  
  88.     }  
  89. }  


最后测试上面的代码,首先运行Server类,然后运行Client类,就可以分别在Server端和Client端控制台看到发送或接收到的MyRequestObject或MyResponseObject对象了。

关于NIO和IO的比较,下面的两篇文章对理解很有帮助,可以参考一下。

 

http://tutorials.jenkov.com/java-nio/nio-vs-io.html

https://blogs.oracle.com/slc/entry/javanio_vs_javaio

分享到:
评论

相关推荐

    基于Java的源码-Java Socket通信实现.zip

    10. **实战应用**:Java Socket通信不仅限于命令行程序,还可以嵌入到Web应用、桌面应用中,例如,WebSocket协议就是基于TCP的Socket实现的,用于在Web浏览器和服务器之间进行全双工通信。 以上是对"基于Java的源码...

    《NIO与Socket编程技术指南》_高洪岩

    Socket通信基于TCP/IP协议,确保数据的可靠传输,通过输入流和输出流进行数据交换。在实际应用中,Socket常用于实现分布式服务、聊天应用、文件传输等场景。 本书可能涵盖了以下主题: 1. NIO基础:介绍NIO的基本...

    java socket教程.

    Java Socket教程是学习Java网络编程的核心内容,它涵盖了如何通过Java API进行客户端和服务器之间的通信。Socket在计算机网络中扮演着桥梁的角色,允许两台计算机(客户端和服务器)通过TCP/IP协议交换数据。本教程...

    java socket 中文教程

    Java Socket还支持其他高级功能,如SOCKET选项(如SO_REUSEADDR、SO_TIMEOUT)、SSL/TLS加密(javax.net.ssl包)以及NIO(非阻塞I/O)等,这些特性使得Java Socket在高性能、高安全性的网络应用中具有广泛的应用。...

    java socket 编程文档

    Java套接字编程是网络通信的核心技术之一,它允许Java应用程序之间或应用程序与远程服务器之间的双向数据传输。本文将深入探讨Java Socket编程的基础知识、关键概念以及如何在实践中应用。 一、Socket概述 Socket,...

    JAVA Socket 网络编程教程

    Java Socket网络编程是Java开发中一个重要的组成部分,它允许应用程序通过网络进行通信,实现客户端与服务器之间的数据交换。本教程将深入探讨Java Socket编程的基本概念、原理和实践应用。 一、Socket基本概念 ...

    java socket教程java socket教程

    除了基础的Socket通信,Java还提供了NIO(Non-blocking I/O)Socket,支持多路复用,提高并发性能。此外,还有SSLSocket,用于加密通信,保障数据安全。 总结,Java Socket教程涵盖了从基础的Socket通信机制到高级...

    java socket 学习资料

    Java Socket是Java编程语言中用于实现网络通信的核心API,它基于TCP/IP协议栈,提供了低级别的网络连接功能。Socket在Java中被广泛用于构建客户端-服务器应用,例如创建Web服务器、聊天应用程序、文件传输等。以下是...

    java socket通信h

    Java Socket通信是网络编程中的重要组成部分,主要用于实现客户端与服务器之间的双向通信。Socket在Java中提供了TCP(传输控制协议)的编程接口,使得开发者能够构建可靠的、基于连接的数据传输通道。下面将详细介绍...

    一站式学习Java网络编程 全面理解BIO:NIO:AIO1

    本课程旨在帮助学生全面理解 Java 网络编程中的 BIO、NIO、AIO 三剑客,掌握 RPC 编程的基础知识,并结合实战项目巩固所学。 一、网络编程三剑客 - BIO、NIO、AIO BIO(Blocking I/O)是一种同步阻塞式 I/O 模式,...

    Java TCP IP Socket编程 包含源码

    `java.nio.channels`包下的`ServerSocketChannel`和`SocketChannel`可以替代传统的`ServerSocket`和`Socket`。 9. **套接字选项**:`Socket`对象有多种配置选项,如设置超时时间、禁用Nagle算法等,可以通过`Socket...

    java Socket连接信息

    `java.nio.channels`包下的`SocketChannel`类提供了异步的Socket通信功能。 9. **实战示例**: - `NetDemo_17.java`可能是一个简单的Socket通信示例,它展示了如何创建Socket连接,交换数据以及关闭连接的基本步骤...

    java socket tcpip多线程网络通信服务器客户端

    在“java socket tcpip多线程网络通信服务器客户端”这个主题中,我们将深入探讨如何使用Java Socket实现基于TCP/IP协议的多线程服务器和客户端通信。 TCP(传输控制协议)是一种面向连接的、可靠的、基于字节流的...

    java基于socket手写协议的在线考试系统

    在Java中,`java.net.Socket`类和`ServerSocket`类是实现Socket通信的核心。开发者需要定义客户端和服务端的交互协议,包括数据格式、请求类型和响应格式等,这正是“手写协议”的含义。 在这个系统中,协议设计至...

    java的socket编程课件~~~

    它们共同构建了Socket通信的基本框架。 1. **创建Socket连接**: - 客户端通过`Socket(String host, int port)`构造函数建立到指定服务器的连接。`host`是服务器的IP地址或域名,`port`是服务器监听的端口号。 - ...

    java开发实战经典

    《Java开发实战经典》这本书是Java开发者的重要参考资料,它涵盖了Java编程语言的核心技术和实践应用。以下将详细解析这本书可能涉及的知识点。 1. **Java基础知识**:书中首先会介绍Java的基础概念,包括Java的...

    java socket,javasocket教程

    Java Socket是Java编程语言中用于网络通信的核心API,它提供了低级别的、面向连接的、基于TCP/IP的通信机制。在Java Socket编程中,我们可以创建服务器端(ServerSocket)来监听客户端(Socket)的连接请求,然后...

    java网络编程socket

    2. 使用Selector和NIO:对于高并发场景,可以使用Java NIO(New IO)的Selector,监听多个Socket通道,提高服务器的性能。 六、实战应用 1. 文件传输:Socket可用于实现简单的文件传输,客户端发送文件,服务器端...

    基于Java Socket网络编程的基础性应用研究.zip

    Java NIO(Non-blocking I/O)提供了另一种方式来处理Socket通信,它支持非阻塞I/O操作,可以提高服务器处理大量并发连接的能力。通过Selector和Channel,开发者可以更高效地管理多个Socket连接。 七、实战应用 ...

    java+IM实战项目.zip

    1. **Java Socket编程**:Java的Socket类提供了网络通信的基础,通过创建ServerSocket监听客户端连接,Socket建立客户端和服务端的通信链路,实现数据的双向传输。 2. **TCP/IP协议**:项目基于TCP协议,提供可靠的...

Global site tag (gtag.js) - Google Analytics