NIO Socket非阻塞模式代码示例

jdk供的无阻塞I/O(NIO)有效解决了多线程服务器存在的线程开销问题,但在使用上略显得复杂一些。在NIO中使用多线程,主要目的已不是为了应对每个客户端请求而分配独立的服务线程,而是通过多线程充分使用用多个CPU的处理能力和处理中的等待时间,达到提高服务能力的目的。
从最简单的Hello World开始,client多线程请求server端,server接收client的名字,并返回Hello! +名字的字符格式给client。当然实际应用并不这么简单,实际可能是访问文件或者数据库获取信息返回给client。非阻塞的NIO有何神秘之处?代码:

1)server端代码
Java代码
  1. /**
  2. *
  3. *@authorJeff
  4. *
  5. */
  6. publicclassHelloWorldServer{
  7. staticintBLOCK=1024;
  8. staticStringname="";
  9. protectedSelectorselector;
  10. protectedByteBufferclientBuffer=ByteBuffer.allocate(BLOCK);
  11. protectedCharsetDecoderdecoder;
  12. staticCharsetEncoderencoder=Charset.forName("GB2312").newEncoder();
  13. publicHelloWorldServer(intport)throwsIOException{
  14. selector=this.getSelector(port);
  15. Charsetcharset=Charset.forName("GB2312");
  16. decoder=charset.newDecoder();
  17. }
  18. //获取Selector
  19. protectedSelectorgetSelector(intport)throwsIOException{
  20. ServerSocketChannelserver=ServerSocketChannel.open();
  21. Selectorsel=Selector.open();
  22. server.socket().bind(newInetSocketAddress(port));
  23. server.configureBlocking(false);
  24. server.register(sel,SelectionKey.OP_ACCEPT);
  25. returnsel;
  26. }
  27. //监听端口
  28. publicvoidlisten(){
  29. try{
  30. for(;;){
  31. selector.select();
  32. Iteratoriter=selector.selectedKeys().iterator();
  33. while(iter.hasNext()){
  34. SelectionKeykey=(SelectionKey)iter.next();
  35. iter.remove();
  36. process(key);
  37. }
  38. }
  39. }catch(IOExceptione){
  40. e.printStackTrace();
  41. }
  42. }
  43. //处理事件
  44. protectedvoidprocess(SelectionKeykey)throwsIOException{
  45. if(key.isAcceptable()){//接收请求
  46. ServerSocketChannelserver=(ServerSocketChannel)key.channel();
  47. SocketChannelchannel=server.accept();
  48. //设置非阻塞模式
  49. channel.configureBlocking(false);
  50. channel.register(selector,SelectionKey.OP_READ);
  51. }elseif(key.isReadable()){//读信息
  52. SocketChannelchannel=(SocketChannel)key.channel();
  53. intcount=channel.read(clientBuffer);
  54. if(count>0){
  55. clientBuffer.flip();
  56. CharBuffercharBuffer=decoder.decode(clientBuffer);
  57. name=charBuffer.toString();
  58. //System.out.println(name);
  59. SelectionKeysKey=channel.register(selector,
  60. SelectionKey.OP_WRITE);
  61. sKey.attach(name);
  62. }else{
  63. channel.close();
  64. }
  65. clientBuffer.clear();
  66. }elseif(key.isWritable()){//写事件
  67. SocketChannelchannel=(SocketChannel)key.channel();
  68. Stringname=(String)key.attachment();
  69. ByteBufferblock=encoder.encode(CharBuffer
  70. .wrap("Hello!"+name));
  71. channel.write(block);
  72. //channel.close();
  73. }
  74. }
  75. publicstaticvoidmain(String[]args){
  76. intport=8888;
  77. try{
  78. HelloWorldServerserver=newHelloWorldServer(port);
  79. System.out.println("listeningon"+port);
  80. server.listen();
  81. }catch(IOExceptione){
  82. e.printStackTrace();
  83. }
  84. }
  85. }

server主要是读取client发过来的信息,并返回一条信息

2)client端代码
Java代码
  1. /**
  2. *
  3. *@authorJeff
  4. *
  5. */
  6. publicclassHelloWorldClient{
  7. staticintSIZE=10;
  8. staticInetSocketAddressip=newInetSocketAddress("localhost",8888);
  9. staticCharsetEncoderencoder=Charset.forName("GB2312").newEncoder();
  10. staticclassMessageimplementsRunnable{
  11. protectedStringname;
  12. Stringmsg="";
  13. publicMessage(Stringindex){
  14. this.name=index;
  15. }
  16. publicvoidrun(){
  17. try{
  18. longstart=System.currentTimeMillis();
  19. //打开Socket通道
  20. SocketChannelclient=SocketChannel.open();
  21. //设置为非阻塞模式
  22. client.configureBlocking(false);
  23. //打开选择器
  24. Selectorselector=Selector.open();
  25. //注册连接服务端socket动作
  26. client.register(selector,SelectionKey.OP_CONNECT);
  27. //连接
  28. client.connect(ip);
  29. //分配内存
  30. ByteBufferbuffer=ByteBuffer.allocate(8*1024);
  31. inttotal=0;
  32. _FOR:for(;;){
  33. selector.select();
  34. Iteratoriter=selector.selectedKeys().iterator();
  35. while(iter.hasNext()){
  36. SelectionKeykey=(SelectionKey)iter.next();
  37. iter.remove();
  38. if(key.isConnectable()){
  39. SocketChannelchannel=(SocketChannel)key
  40. .channel();
  41. if(channel.isConnectionPending())
  42. channel.finishConnect();
  43. channel
  44. .write(encoder
  45. .encode(CharBuffer.wrap(name)));
  46. channel.register(selector,SelectionKey.OP_READ);
  47. }elseif(key.isReadable()){
  48. SocketChannelchannel=(SocketChannel)key
  49. .channel();
  50. intcount=channel.read(buffer);
  51. if(count>0){
  52. total+=count;
  53. buffer.flip();
  54. while(buffer.remaining()>0){
  55. byteb=buffer.get();
  56. msg+=(char)b;
  57. }
  58. buffer.clear();
  59. }else{
  60. client.close();
  61. break_FOR;
  62. }
  63. }
  64. }
  65. }
  66. doublelast=(System.currentTimeMillis()-start)*1.0/1000;
  67. System.out.println(msg+"usedtime:"+last+"s.");
  68. msg="";
  69. }catch(IOExceptione){
  70. e.printStackTrace();
  71. }
  72. }
  73. }
  74. publicstaticvoidmain(String[]args)throwsIOException{
  75. Stringnames[]=newString[SIZE];
  76. for(intindex=0;index<SIZE;index++){
  77. names[index]="jeff["+index+"]";
  78. newThread(newMessage(names[index])).start();
  79. }
  80. }
  81. }
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值