Java使用NIO包实现Socket通信的实例代码

前面几篇文章介绍了使用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对象。

package com.googlecode.garbagecan.test.socket; 

import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream; 

public class SerializableUtil { 

  public static byte[] toBytes(Object object) {
    ByteArrayOutputStream baos = new ByteArrayOutputStream();
    ObjectOutputStream oos = null;
    try {
      oos = new ObjectOutputStream(baos);
      oos.writeObject(object);
      byte[] bytes = baos.toByteArray();
      return bytes;
    } catch(IOException ex) {
      throw new RuntimeException(ex.getMessage(), ex);
    } finally {
      try {
        oos.close();
      } catch (Exception e) {}
    }
  } 

  public static Object toObject(byte[] bytes) {
    ByteArrayInputStream bais = new ByteArrayInputStream(bytes);
    ObjectInputStream ois = null;
    try {
      ois = new ObjectInputStream(bais);
      Object object = ois.readObject();
      return object;
    } catch(IOException ex) {
      throw new RuntimeException(ex.getMessage(), ex);
    } catch(ClassNotFoundException ex) {
      throw new RuntimeException(ex.getMessage(), ex);
    } finally {
      try {
        ois.close();
      } catch (Exception e) {}
    }
  }
}

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

package com.googlecode.garbagecan.test.socket.nio; 

import java.io.Serializable; 

public class MyRequestObject implements Serializable { 

  private static final long serialVersionUID = 1L; 

  private String name; 

  private String value; 

  private byte[] bytes; 

  public MyRequestObject(String name, String value) {
    this.name = name;
    this.value = value;
    this.bytes = new byte[1024];
  } 

  public String getName() {
    return name;
  } 

  public void setName(String name) {
    this.name = name;
  } 

  public String getValue() {
    return value;
  } 

  public void setValue(String value) {
    this.value = value;
  } 

  @Override
  public String toString() {
    StringBuffer sb = new StringBuffer();
    sb.append("Request [name: " + name + ", value: " + value + ", bytes: " + bytes.length+ "]");
    return sb.toString();
  }
} 

package com.googlecode.garbagecan.test.socket.nio; 

import java.io.Serializable; 

public class MyResponseObject implements Serializable { 

  private static final long serialVersionUID = 1L; 

  private String name; 

  private String value; 

  private byte[] bytes; 

  public MyResponseObject(String name, String value) {
    this.name = name;
    this.value = value;
    this.bytes = new byte[1024];
  } 

  public String getName() {
    return name;
  } 

  public void setName(String name) {
    this.name = name;
  } 

  public String getValue() {
    return value;
  } 

  public void setValue(String value) {
    this.value = value;
  } 

  @Override
  public String toString() {
    StringBuffer sb = new StringBuffer();
    sb.append("Response [name: " + name + ", value: " + value + ", bytes: " + bytes.length+ "]");
    return sb.toString();
  }
}

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

package com.googlecode.garbagecan.test.socket.nio; 

import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.net.InetSocketAddress;
import java.nio.ByteBuffer;
import java.nio.channels.ClosedChannelException;
import java.nio.channels.SelectionKey;
import java.nio.channels.Selector;
import java.nio.channels.ServerSocketChannel;
import java.nio.channels.SocketChannel;
import java.util.Iterator;
import java.util.logging.Level;
import java.util.logging.Logger; 

import com.googlecode.garbagecan.test.socket.SerializableUtil; 

public class MyServer3 { 

  private final static Logger logger = Logger.getLogger(MyServer3.class.getName()); 

  public static void main(String[] args) {
    Selector selector = null;
    ServerSocketChannel serverSocketChannel = null; 

    try {
      // Selector for incoming time requests
      selector = Selector.open(); 

      // Create a new server socket and set to non blocking mode
      serverSocketChannel = ServerSocketChannel.open();
      serverSocketChannel.configureBlocking(false); 

      // Bind the server socket to the local host and port
      serverSocketChannel.socket().setReuseAddress(true);
      serverSocketChannel.socket().bind(new InetSocketAddress(10000)); 

      // Register accepts on the server socket with the selector. This
      // step tells the selector that the socket wants to be put on the
      // ready list when accept operations occur, so allowing multiplexed
      // non-blocking I/O to take place.
      serverSocketChannel.register(selector, SelectionKey.OP_ACCEPT); 

      // Here's where everything happens. The select method will
      // return when any operations registered above have occurred, the
      // thread has been interrupted, etc.
      while (selector.select() > 0) {
        // Someone is ready for I/O, get the ready keys
        Iterator<SelectionKey> it = selector.selectedKeys().iterator(); 

        // Walk through the ready keys collection and process date requests.
        while (it.hasNext()) {
          SelectionKey readyKey = it.next();
          it.remove(); 

          // The key indexes into the selector so you
          // can retrieve the socket that's ready for I/O
          execute((ServerSocketChannel) readyKey.channel());
        }
      }
    } catch (ClosedChannelException ex) {
      logger.log(Level.SEVERE, null, ex);
    } catch (IOException ex) {
      logger.log(Level.SEVERE, null, ex);
    } finally {
      try {
        selector.close();
      } catch(Exception ex) {}
      try {
        serverSocketChannel.close();
      } catch(Exception ex) {}
    }
  } 

  private static void execute(ServerSocketChannel serverSocketChannel) throws IOException {
    SocketChannel socketChannel = null;
    try {
      socketChannel = serverSocketChannel.accept();
      MyRequestObject myRequestObject = receiveData(socketChannel);
      logger.log(Level.INFO, myRequestObject.toString()); 

      MyResponseObject myResponseObject = new MyResponseObject(
          "response for " + myRequestObject.getName(),
          "response for " + myRequestObject.getValue());
      sendData(socketChannel, myResponseObject);
      logger.log(Level.INFO, myResponseObject.toString());
    } finally {
      try {
        socketChannel.close();
      } catch(Exception ex) {}
    }
  } 

  private static MyRequestObject receiveData(SocketChannel socketChannel) throws IOException {
    MyRequestObject myRequestObject = null;
    ByteArrayOutputStream baos = new ByteArrayOutputStream();
    ByteBuffer buffer = ByteBuffer.allocate(1024); 

    try {
      byte[] bytes;
      int size = 0;
      while ((size = socketChannel.read(buffer)) >= 0) {
        buffer.flip();
        bytes = new byte[size];
        buffer.get(bytes);
        baos.write(bytes);
        buffer.clear();
      }
      bytes = baos.toByteArray();
      Object obj = SerializableUtil.toObject(bytes);
      myRequestObject = (MyRequestObject)obj;
    } finally {
      try {
        baos.close();
      } catch(Exception ex) {}
    }
    return myRequestObject;
  } 

  private static void sendData(SocketChannel socketChannel, MyResponseObject myResponseObject) throws IOException {
    byte[] bytes = SerializableUtil.toBytes(myResponseObject);
    ByteBuffer buffer = ByteBuffer.wrap(bytes);
    socketChannel.write(buffer);
  }
}

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

package com.googlecode.garbagecan.test.socket.nio; 

import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.net.InetSocketAddress;
import java.net.SocketAddress;
import java.nio.ByteBuffer;
import java.nio.channels.SocketChannel;
import java.util.logging.Level;
import java.util.logging.Logger; 

import com.googlecode.garbagecan.test.socket.SerializableUtil; 

public class MyClient3 { 

  private final static Logger logger = Logger.getLogger(MyClient3.class.getName()); 

  public static void main(String[] args) throws Exception {
    for (int i = 0; i < 100; i++) {
      final int idx = i;
      new Thread(new MyRunnable(idx)).start();
    }
  } 

  private static final class MyRunnable implements Runnable { 

    private final int idx; 

    private MyRunnable(int idx) {
      this.idx = idx;
    } 

    public void run() {
      SocketChannel socketChannel = null;
      try {
        socketChannel = SocketChannel.open();
        SocketAddress socketAddress = new InetSocketAddress("localhost", 10000);
        socketChannel.connect(socketAddress); 

        MyRequestObject myRequestObject = new MyRequestObject("request_" + idx, "request_" + idx);
        logger.log(Level.INFO, myRequestObject.toString());
        sendData(socketChannel, myRequestObject); 

        MyResponseObject myResponseObject = receiveData(socketChannel);
        logger.log(Level.INFO, myResponseObject.toString());
      } catch (Exception ex) {
        logger.log(Level.SEVERE, null, ex);
      } finally {
        try {
          socketChannel.close();
        } catch(Exception ex) {}
      }
    } 

    private void sendData(SocketChannel socketChannel, MyRequestObject myRequestObject) throws IOException {
      byte[] bytes = SerializableUtil.toBytes(myRequestObject);
      ByteBuffer buffer = ByteBuffer.wrap(bytes);
      socketChannel.write(buffer);
      socketChannel.socket().shutdownOutput();
    } 

    private MyResponseObject receiveData(SocketChannel socketChannel) throws IOException {
      MyResponseObject myResponseObject = null;
      ByteArrayOutputStream baos = new ByteArrayOutputStream(); 

      try {
        ByteBuffer buffer = ByteBuffer.allocateDirect(1024);
        byte[] bytes;
        int count = 0;
        while ((count = socketChannel.read(buffer)) >= 0) {
          buffer.flip();
          bytes = new byte[count];
          buffer.get(bytes);
          baos.write(bytes);
          buffer.clear();
        }
        bytes = baos.toByteArray();
        Object obj = SerializableUtil.toObject(bytes);
        myResponseObject = (MyResponseObject) obj;
        socketChannel.socket().shutdownInput();
      } finally {
        try {
          baos.close();
        } catch(Exception ex) {}
      }
      return myResponseObject;
    }
  }
}

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

以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持我们。

(0)

相关推荐

  • 深入理解Java Socket通信

    简述 Java中Socket分为普通Socket和NioSocket两种,这里介绍Socket. 我们可以把Socket比作两个城市间的交通工具,有了它可以在两城之间来回穿梭,交通工具有很多种,每种交通工具也有相应的交通规则.Socket也一样,也有多种.大多情况下使用的是TCP/IP的流套接字,它是一种稳定的通信协议.(TCP/IP与UDP的对比) Java中的网络通信是通过Socket实现的,Socket分为ServerSocket和Socket两大类,ServerSocket用于服务端,通

  • Java Socket实现多线程通信功能示例

    本文实例讲述了Java Socket实现多线程通信功能的方法.分享给大家供大家参考,具体如下: 前面的文章<Java Socket实现单线程通信的方法示例>说到怎样写一个最简单的Java Socket通信,但是文章中的例子有一个问题就是Server只能接受一个Client请求,当第一个Client连接后就占据了这个位置,后续Client不能再继续连接,所以需要做些改动,当Server没接受到一个Client连接请求之后,都把处理流程放到一个独立的线程里去运行,然后等待下一个Client连接请求

  • Java实现的基于socket通信的实例代码

    服务器端代码: 复制代码 代码如下: import java.io.BufferedReader; import java.io.InputStreamReader; import java.net.ServerSocket; import java.net.Socket; public class Server {     public static void main(String[] args) {         ServerSocket server;         try{    

  • Java使用Socket通信传输文件的方法示例

    本文实例讲述了Java使用Socket通信传输文件的方法.分享给大家供大家参考,具体如下: 前面几篇文章介绍了使用Java的Socket编程和NIO包在Socket中的应用,这篇文章说说怎样利用Socket编程来实现简单的文件传输. 这里由于前面一片文章介绍了NIO在Socket中的应用,所以这里在读写文件的时候也继续使用NIO包,所以代码看起来会比直接使用流的方式稍微复杂一点点. 下面的示例演示了客户端向服务器端发送一个文件,服务器作为响应给客户端回发一个文件.这里准备两个文件E:/test/

  • java中处理socket通信过程中粘包的情况

    这两天学习了java中处理socket通信过程中粘包的情况,而且很重要,所以,今天添加一点小笔记. 处理粘包程序是客户端的接受消息线程: 客户端: import java.io.InputStream; import java.io.InputStreamReader; import java.io.OutputStreamWriter; import java.io.PrintWriter; import java.io.Reader; import java.net.Socket; impo

  • JAVA中实现原生的 socket 通信机制原理

    本文介绍了JAVA中实现原生的 socket 通信机制原理,分享给大家,具体如下: 当前环境 jdk == 1.8 知识点 socket 的连接处理 IO 输入.输出流的处理 请求数据格式处理 请求模型优化 场景 今天,和大家聊一下 JAVA 中的 socket 通信问题.这里采用最简单的一请求一响应模型为例,假设我们现在需要向 baidu 站点进行通信.我们用 JAVA 原生的 socket 该如何实现. 建立 socket 连接 首先,我们需要建立 socket 连接(核心代码) impor

  • JAVA实现基于Tcp协议的简单Socket通信实例

    好久没写博客了,前段时间忙于做项目,耽误了些时间,今天开始继续写起~ 今天来讲下关于Socket通信的简单应用,关于什么是Socket以及一些网络编程的基础,这里就不提了,只记录最简单易懂实用的东西.  1.首先先来看下基于TCP协议Socket服务端和客户端的通信模型: Socket通信步骤:(简单分为4步) 1.建立服务端ServerSocket和客户端Socket 2.打开连接到Socket的输出输入流 3.按照协议进行读写操作 4.关闭相对应的资源 2.相关联的API: 1.首先先来看下

  • Java Socket实现单线程通信的方法示例

    本文实例讲述了Java Socket实现单线程通信的方法.分享给大家供大家参考,具体如下: 现在做Java直接使用Socket的情况是越来越少,因为有很多的选择可选,比如说可以用spring,其中就可以支持很多种远程连接的操作,另外jboss的remoting也是不错的选择,还有Apache的Mina等等,但是在有些时候一些特殊情况仍然逃脱不了直接写Socket的情况,比如公司内部一些莫名其妙的游戏规则. 废话不说了,下面就看看如果自己写Socket应该怎么做吧. 首先是写一个Server类,这

  • Java使用NIO包实现Socket通信的实例代码

    前面几篇文章介绍了使用java.io和java.net类库实现的Socket通信,下面介绍一下使用java.nio类库实现的Socket. java.nio包是Java在1.4之后增加的,用来提高I/O操作的效率.在nio包中主要包括以下几个类或接口: Buffer:缓冲区,用来临时存放输入或输出数据. Charset:用来把Unicode字符编码和其它字符编码互转. Channel:数据传输通道,用来把Buffer中的数据写入到数据源,或者把数据源中的数据读入到Buffer. Selector

  • Java基于TCP协议的Socket通信

    目录 简介 TCP简介 JAVA Socket简介 SocketImpl介绍 TCP 编程 构造ServerSocket 1.1 绑定端口 1.2 设定客户连接请求队列的长度 1.3 设定绑定的IP 地址 1.4 默认构造方法的作用 多线程示例 简介 TCP简介 TCP(Transmission Control Protocol 传输控制协议)是一种面向连接的.可靠的.基于字节流的传输层通信协议,由IETF的RFC 793定义.在简化的计算机网络OSI模型中,它完成第四层传输层所指定的功能,用户

  • Java Web项目中使用Socket通信多线程、长连接的方法

    很多时候在javaweb项目中我们需要用到Socket通信来实现功能,在web中使用Socket我们需要建立一个监听程序,在程序启动时,启动socket监听.我们的应用场景是在java项目中,需要外接如一个硬件设备,通过tcp通信,获取设备传上来的数据,并对数据做回应. 先看一下web的监听代码: import javax.servlet.ServletContextEvent; import javax.servlet.ServletContextListener; public class

  • java生成jar包并且单进程运行的实例

    java文件打包jar运行 有效步骤: 1.cmd 到当前目录(默认包主类所在目录为例) set classpath = 默认包主类所在目录 2.javac 主类名.java 3.java 主类名 4.写清单文件 Manifest-Version: 1.0 Created-By: 1.8.0 (Sun Microsystems Inc.) Main-Class: 主类名 created-by 版本号 不知道 -> 进cmd 输入java -version 5.jar cfm 自定义.jar MA

  • java 使用memcached以及spring 配置memcached完整实例代码

    Memcached是一个高性能的分布式内存对象缓存系统,本文介绍了java 使用memcached以及spring 配置memcached完整实例代码,分享给大家 本文涉及以下内容: 1,要使用的jar包 2,java 使用memcached 3,spring 配置memcached 导入jar java_memcached-release_2.6.6.jar commons-pool-1.5.6.jar slf4j-api-1.6.1.jar slf4j-simple-1.6.1.jar 示例

  • Java类和成员上的一些方法实例代码

    isInstance和isAssignableFrom obj instanceof Class 判断obj是不是Class或者Class的子类的实例 clazz.isInstance(obj) 判断obj能不能强制转换成clazz类型,亦即obj是不是clazz或者clazz的子类的实例 clazz1.isAssignableFrom(clazz2) 如果clazz2和clazz1相同,或者clazz1是clazz2的父类则返回True,否则返回Flase static class Paren

  • linux IPC之socket解析及实例代码

    Linux下的Socket通信是一种基于文件的IPC通信,也可以是基于其他设备的IPC通信.它可以在本机内不同进程间实现通信,也可以在实现不同主机之间的通信. socket的创建步骤 服务端 1.通过socket()函数创建socket 2.通过bind函数绑定socket于设备地址 3.通过listen监听指定的socket 4.通过accept等待客户端的连接 客户端 1.通过socket()函数创建socket 2.通过connect连接到服务端 待经过上面的步骤后,服务端和客户端已经建立

  • 枚举java语言中的修饰符组合的实例代码

    枚举java语言中的修饰符组合,代码如下所示: package model; /*22:37 2019/7/20*/ /* top class的修饰符组合 abstract final public * 2 * 2 warning: abstract final 冲突 最终,共有2*(2*2-1)=6种修饰符组合用于top class */ /* public abstract class PublicAbstractClass{} public final class PublicFinalC

随机推荐