欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页  >  IT编程

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

程序员文章站 2024-03-08 09:40:52
前面几篇文章介绍了使用java.io和java.net类库实现的socket通信,下面介绍一下使用java.nio类库实现的socket。 java.nio包是jav...

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

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