客户端使用Java的阻塞IO

服务端使用Java的非阻塞NIO

package com.nio.echo;

import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.net.InetSocketAddress;
import java.net.Socket;
import java.util.Scanner; /**
* @author 作者 E-mail:
* @version 创建时间:2015-10-29 下午02:49:47 类说明
*/
public class EchoClient
{
public static final String REMOT_IP = "127.0.0.1"; public static final int REMOTE_PORT = 8080; public void connectServer() throws IOException
{
Socket socket = new Socket(); socket.connect(new InetSocketAddress(REMOT_IP, REMOTE_PORT)); if (socket.isConnected())
{
System.out.println("connect remote address success");
} // 启动线程监听server端消息
new Thread(new client2server(socket)).start();
Scanner scanner = new Scanner(System.in); OutputStream output = socket.getOutputStream();
while (true)
{
String str = scanner.nextLine(); if (str.equals("quit"))
{
socket.close();
break;
}
output.write(str.getBytes("UTF-8")); } } public static void main(String[] args) throws IOException
{
new EchoClient().connectServer();
}
} class client2server implements Runnable
{
private Socket socket = null; public client2server(Socket socket)
{
this.socket = socket;
} @Override
public void run()
{
InputStream inputStream;
try
{
inputStream = socket.getInputStream();
byte[] bytes = new byte[1024];
while (true)
{
int num = inputStream.read(bytes);
if (num != -1)
{
System.out.print(num + " ");
}
else
{
System.out.println("server is shutup");
break;
} String str = new String(bytes, 0, num, "UTF-8");
System.out.println("get data: " + str); }
}
catch(IOException e)
{
e.printStackTrace();
} }
}
package com.nio.echo;

import java.io.IOException;
import java.net.InetSocketAddress;
import java.net.ServerSocket;
import java.nio.ByteBuffer;
import java.nio.CharBuffer;
import java.nio.channels.SelectionKey;
import java.nio.channels.Selector;
import java.nio.channels.ServerSocketChannel;
import java.nio.channels.SocketChannel;
import java.nio.charset.Charset;
import java.nio.charset.CharsetDecoder;
import java.util.Iterator;
import java.util.Set; /**
* @author 作者 E-mail:
* @version 创建时间:2015-10-29 下午02:49:12 类说明
*/
public class NIOEchoServer
{
private static ServerSocketChannel ssc = null; private static Selector selector = null; private static final int PORT = 8080; public static void startServer() throws IOException
{
ssc = ServerSocketChannel.open();
selector = Selector.open();
ssc.configureBlocking(false); // nio 对socket 和serverSocket进行了怎样封装
final ServerSocket serverSocket = ssc.socket(); serverSocket.bind(new InetSocketAddress(PORT));
serverSocket.setReuseAddress(true); final AcceptHandler acceptHandler = new AcceptHandler();
ssc.register(selector, SelectionKey.OP_ACCEPT, acceptHandler);
while (true)
{
int n = selector.select();
if (n == 0)
continue; final Set<SelectionKey> readyKeys = selector.selectedKeys();
final Iterator<SelectionKey> it = readyKeys.iterator();
while (it.hasNext())
{
final SelectionKey key = it.next();
final Handle handler = (Handle) key.attachment();
handler.doHandle(key);
it.remove();
}
}
} public static void main(String[] args) throws IOException
{
NIOEchoServer.startServer();
}
} interface Handle
{
void doHandle(SelectionKey key) throws IOException;
} class AcceptHandler implements Handle
{ @Override
public void doHandle(SelectionKey key) throws IOException
{ final ServerSocketChannel ssc = (ServerSocketChannel) key.channel();
final SocketChannel sc = ssc.accept();
final IOHandler handler = new IOHandler(key.selector(), sc);
System.out.println("server: connect success");
} } class IOHandler implements Handle
{
private final ByteBuffer readBuffer = ByteBuffer.allocate(1024); private OutputBuffer outputBuffer = new OutputBuffer(); private SocketChannel socketChannel = null; // private Selector selector = null; private SelectionKey key = null; public IOHandler(Selector selector, SocketChannel sc) throws IOException
{
// this.selector = selector;
this.socketChannel = sc;
socketChannel.configureBlocking(false);
key = socketChannel.register(selector, SelectionKey.OP_READ, this);
} /**
* 增加输出缓存
*
* @param writeData
* 要写出的数据
* @throws IOException
* @return 返回处理的字节数
*/
private int addWriteBuffer(ByteBuffer bytebuffer, int num) throws IOException
{
int prevPositon = bytebuffer.position();
outputBuffer.size += num; outputBuffer.writeBuffer.put(bytebuffer).flip();
int nowPosition = bytebuffer.position(); this.interestOps(0, SelectionKey.OP_WRITE); return nowPosition - prevPositon;
} /**
* 增加删除相应事件
*
* @param remove
* @param add
*/
private void interestOps(int remove, int add)
{
int cur = key.interestOps();
int ops = (cur & ~remove) | add;
if (cur != ops)
{
key.interestOps(ops);
key.selector().wakeup();
}
} /**
* ByteBuffer 转换 String
*
* @param buffer
* @return
*/
public static String getString(ByteBuffer buffer)
{
Charset charset = null;
CharsetDecoder decoder = null;
CharBuffer charBuffer = null;
try
{
charset = Charset.forName("UTF-8");
decoder = charset.newDecoder();
// charBuffer = decoder.decode(buffer);//用这个的话,只能输出来一次结果,第二次显示为空
charBuffer = decoder.decode(buffer.asReadOnlyBuffer());
return charBuffer.toString();
}
catch(Exception ex)
{
ex.printStackTrace();
return "";
}
} @Override
public void doHandle(SelectionKey key) throws IOException
{
if (key.isReadable())
{
System.out.print("server: meet read event ,before read position = " + readBuffer.position()); int num = socketChannel.read(readBuffer); // 关闭
if (num == -1)
{
System.out.println("close the channel ");
key.channel();
key.channel().close();
return;
} // 将position置为0
readBuffer.flip(); System.out.print(" reveive data " + getString(readBuffer)); int dealsize = addWriteBuffer(readBuffer, num); System.out.println(" write to writeBuffer size = " + dealsize + " nowPostion = " + readBuffer.position()); // 将处理过的数据清除
readBuffer.compact();
}
else if (key.isWritable())
{
System.out.print("meet write event"); long num = socketChannel.write(outputBuffer.writeBuffer);
outputBuffer.size -= num; System.out.print("deal size = " + num + "left buffer size = " + outputBuffer.size);
if (outputBuffer.size == 0)
{
System.out.println(" deal over,cancel write event");
interestOps(SelectionKey.OP_WRITE, 0);
}
// 清除已经处理过的数据
outputBuffer.writeBuffer.compact(); }
}
} class OutputBuffer
{
public int size; public final ByteBuffer writeBuffer = ByteBuffer.allocate(1024); }

ByteBuffer没有提供有用数据的相关方法,只能自己写一个OutputBuffer来辅助处理

之前OutputBuffer只是封装了一个ByteBuffer以及一个size变量用于标示可以数据量

下面对OutputBuffer进行了重构,将size变量的修改以及数据的写入和写出操作都封装到方法中,其中output(SocketChannel socketChannel)

方法利用回调的思想,将socketChannel对象传入,在OutputBuffer当中实现数据的write输出

package com.nio.echo;

import java.io.IOException;
import java.net.InetSocketAddress;
import java.net.ServerSocket;
import java.nio.ByteBuffer;
import java.nio.CharBuffer;
import java.nio.channels.SelectionKey;
import java.nio.channels.Selector;
import java.nio.channels.ServerSocketChannel;
import java.nio.channels.SocketChannel;
import java.nio.charset.Charset;
import java.nio.charset.CharsetDecoder;
import java.util.Iterator;
import java.util.Set; /**
* @author 作者 E-mail:
* @version 创建时间:2015-10-29 下午02:49:12 类说明
*/
public class NIOEchoServer
{
private static ServerSocketChannel ssc = null; private static Selector selector = null; private static final int PORT = 8080; public static void startServer() throws IOException
{
ssc = ServerSocketChannel.open();
selector = Selector.open();
ssc.configureBlocking(false); // nio 对socket 和serverSocket进行了怎样封装
final ServerSocket serverSocket = ssc.socket(); serverSocket.bind(new InetSocketAddress(PORT));
serverSocket.setReuseAddress(true); final AcceptHandler acceptHandler = new AcceptHandler();
ssc.register(selector, SelectionKey.OP_ACCEPT, acceptHandler);
while (true)
{
int n = selector.select();
if (n == 0)
continue; final Set<SelectionKey> readyKeys = selector.selectedKeys();
final Iterator<SelectionKey> it = readyKeys.iterator();
while (it.hasNext())
{
final SelectionKey key = it.next();
final Handle handler = (Handle) key.attachment();
handler.doHandle(key);
it.remove();
}
}
} public static void main(String[] args) throws IOException
{
NIOEchoServer.startServer();
}
} interface Handle
{
void doHandle(SelectionKey key) throws IOException;
} class AcceptHandler implements Handle
{ @Override
public void doHandle(SelectionKey key) throws IOException
{ final ServerSocketChannel ssc = (ServerSocketChannel) key.channel();
final SocketChannel sc = ssc.accept();
final IOHandler handler = new IOHandler(key.selector(), sc);
System.out.println("server: connect success");
} } class IOHandler implements Handle
{
private final ByteBuffer readBuffer = ByteBuffer.allocate(1024); private OutputBuffer outputBuffer = new OutputBuffer(); private SocketChannel socketChannel = null; // private Selector selector = null; private SelectionKey key = null; public IOHandler(Selector selector, SocketChannel sc) throws IOException
{
// this.selector = selector;
this.socketChannel = sc;
socketChannel.configureBlocking(false);
key = socketChannel.register(selector, SelectionKey.OP_READ, this);
} /**
* 增加输出缓存
*
* @param writeData
* 要写出的数据
* @throws IOException
* @return 返回处理的字节数
*/
private int addWriteBuffer(ByteBuffer bytebuffer, int num) throws IOException
{
int prevPositon = bytebuffer.position(); outputBuffer.put(bytebuffer, num); int nowPosition = bytebuffer.position(); this.interestOps(0, SelectionKey.OP_WRITE); return nowPosition - prevPositon;
} /**
* 增加删除相应事件
*
* @param remove
* @param add
*/
private void interestOps(int remove, int add)
{
int cur = key.interestOps();
int ops = (cur & ~remove) | add;
if (cur != ops)
{
key.interestOps(ops);
key.selector().wakeup();
}
} /**
* ByteBuffer 转换 String
*
* @param buffer
* @return
*/
public static String getString(ByteBuffer buffer)
{
Charset charset = null;
CharsetDecoder decoder = null;
CharBuffer charBuffer = null;
try
{
charset = Charset.forName("UTF-8");
decoder = charset.newDecoder();
// charBuffer = decoder.decode(buffer);//用这个的话,只能输出来一次结果,第二次显示为空
charBuffer = decoder.decode(buffer.asReadOnlyBuffer());
return charBuffer.toString();
}
catch(Exception ex)
{
ex.printStackTrace();
return "";
}
} @Override
public void doHandle(SelectionKey key) throws IOException
{
if (key.isReadable())
{
System.out.print("server: meet read event ,before read position = " + readBuffer.position()); int num = socketChannel.read(readBuffer); // 关闭
if (num == -1)
{
System.out.println("close the channel ");
key.channel();
key.channel().close();
return;
} // 将position置为0
readBuffer.flip(); System.out.println(" reveive data " + getString(readBuffer)); int dealsize = addWriteBuffer(readBuffer, num); // 将处理过的数据清除
readBuffer.compact();
}
else if (key.isWritable())
{
System.out.print("meet write event"); // 写数据
outputBuffer.output(socketChannel); if (outputBuffer.size() == 0)
{
System.out.println(" deal over,cancel write event");
interestOps(SelectionKey.OP_WRITE, 0);
} }
}
} class OutputBuffer
{
private int size; private final ByteBuffer writeBuffer = ByteBuffer.allocate(1024); public void output(SocketChannel socketChannel) throws IOException
{
int num = socketChannel.write(writeBuffer);
writeBuffer.compact();
size -= num;
} public void put(ByteBuffer b, int num)
{
writeBuffer.put(b).flip();
this.size += num;
} public int size()
{
return this.size;
}
}

  

事实上在NIO网络编程中,写出数据的操作需要加入缓存才能保证效率,目的是为了写操作发生的时候不影响业务继续send消息,首先将send消息发送过来的数据缓存到A中,在写事件发生的时候将A中数据写出(此时仅短暂锁住A,将A中引用拿出,重新赋值新引用给A),这样写事件的处理过程和业务消息的send就可以高并发的进行。

Java网络编程--echo服务器的更多相关文章

  1. 网络编程-echo服务器

    代码: #coding="utf-8" #name=echo服务器 from socket import * #1.创建套接字 udpSocket = socket(AF_INET ...

  2. Java网络编程客户端和服务器通信

    在java网络编程中,客户端和服务器的通信例子: 先来服务器监听的代码 package com.server; import java.io.IOException; import java.io.O ...

  3. java网络编程serversocket

    转载:http://www.blogjava.net/landon/archive/2013/07/24/401911.html Java网络编程精解笔记3:ServerSocket详解ServerS ...

  4. JAVA网络编程【转】出处不详

    网络编程 网络编程对于很多的初学者来说,都是很向往的一种编程技能,但是很多的初学者却因为很长一段时间无法进入网络编程的大门而放弃了对于该部分技术的学习. 在 学习网络编程以前,很多初学者可能觉得网络编 ...

  5. 【转】JAVA 网络编程

    网络编程 网络编程对于很多的初学者来说,都是很向往的一种编程技能,但是很多的初学者却因为很长一段时间无法进入网络编程的大门而放弃了对于该部分技术的学习. 在 学习网络编程以前,很多初学者可能觉得网络编 ...

  6. Java网络编程和NIO详解开篇:Java网络编程基础

    Java网络编程和NIO详解开篇:Java网络编程基础 计算机网络编程基础 转自:https://mp.weixin.qq.com/s/XXMz5uAFSsPdg38bth2jAA 我们是幸运的,因为 ...

  7. Java网络编程和NIO详解9:基于NIO的网络编程框架Netty

    Java网络编程和NIO详解9:基于NIO的网络编程框架Netty 转自https://sylvanassun.github.io/2017/11/30/2017-11-30-netty_introd ...

  8. 实验五 Java网络编程

    实验五 Java网络编程 实验五 Java网络编程 实验五所涉及的密码学算法及编程思路 ## Java对称加密-DES算法 (1) 获取密钥生成器 KeyGenerator kg=KeyGenerat ...

  9. Java 网络编程初探

    Java 网络编程 网络编程 网络编程:进行服务器端与客户端编程的开发操作实现. java.net:网络操作包 B/S结构: 浏览器/服务器模式(Browser/Server) 不在开发客户端代码 开 ...

随机推荐

  1. ARCproject中加入非ARC文件,或者非ARC环境中加入ARC文件

    ARC与非ARC在一个项目中同一时候使用, 选择项目中的Targets,选中你所要操作的Target,选Build Phases,在当中Complie Sources中选择须要ARC的文件双击,并在输 ...

  2. Cocos2d-x在win32,android和IOS下的文件读写问题

    最近在学习和使用Cocos2d-x框架,虽然说的是跨平台,但是在用VS进行开发,然后移植到android或IOS下,也可能会出现各种问题,需要做细微的调整. 例如我在做文件读写操作的时候,很可能在wi ...

  3. 安装MySQL和HandlerSocket

    CentOS 6.5MySQL 5.6.33HandlerSocket 1.1.2 # Get packagesshell> wget http://dev.mysql.com/get/Down ...

  4. XC通讯录

    XC通讯录基于Android4.4开发的一个手机通讯录,具有手机拨号,添加联系人,查看联系人,管理编辑联系人,智能查找联系人,删除及批量删除,备份/还原数据,以及手机联系人导入等功能,界面简洁美观,欢 ...

  5. Java基础知识强化之IO流笔记28:BufferedOutputStream / BufferedInputStream(字节缓冲区流) 之BufferedOutputStream写出数据

    1. BufferedOutputStream / BufferedInputStream(字节缓冲区流)的概述 通过定义数组的方式确实比以前一次读取一个字节的方式快很多,所以,看来有一个缓冲区还是非 ...

  6. 编译安装 php 5.4.11

    第一步 先下载 tzr.gz 的php源码包然后 tar zxvf  php-5.4.11.tar.gz然后 cd php-5.4.11 然后复制如下编译代码 ./configure \--prefi ...

  7. JavaScript+DOM编程艺术【读书笔记】

    第四章笔记: 如何让一个a标签不跳转: <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.1//EN" "http://www. ...

  8. VB------VS2012 IDE

    当编辑器的前面出现很多小点不影响 运行的时候 Ctrl+E+S就可以取消

  9. Css3 兼容新旧浏览器

    想想10年前用 IE6,火狐,遨游,谷歌等浏览器学习css时,那叫一个艰苦,各种hack各种抓耳挠腮,不是margin塌陷就是元素飞了... 当前借着css3这个东风,如果各大浏览器厂商能统一一下,也 ...

  10. SqlSugar常用增删改操作

    一.添加数据 特别说明: 1.特别说明:对于自增长列的表插入数据后,当前自增长列的字段,仍旧为0,但可以通过Insert方法的返回值来获取 SqlSugarClient db = SugarConte ...