当前位置: 移动技术网 > IT编程>开发语言>Java > Java使用NIO包实现Socket通信的实例代码

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

2019年07月22日  | 移动技术网IT编程  | 我要评论

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

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

如对本文有疑问, 点击进行留言回复!!

相关文章:

验证码:
移动技术网