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对象了。
以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持。