引用
JAVA NIO实现服务端与客户端简单数据传输
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;
/**
* 服务端
*/
public class SocketServer {
/**
* 服务器默认绑定端口
*/
public static final int DEFAULT_PORT = 9999;
/**
* 选择器
*/
public Selector selector;
public SocketServer(String ip, int port) {
ServerSocketChannel ssc = null;
try {
int _port = DEFAULT_PORT;
if (port > 0)
_port = port;
/* 获取通道 */
ssc = ServerSocketChannel.open();
/* 配置非阻塞 */
ssc.configureBlocking(false);
/**
* 配置绑定端口 ServerSocketChannel没有bind()方法,
* 因此有必要取出对等的ServerSocket并使用它来绑定到一
* 个端口以开始监听连接
*/
ssc.socket().bind(new InetSocketAddress(ip, _port));
/* 获取选择器 */
this.selector = Selector.open();
/* 将通道注册到选择器 */
ssc.register(this.selector, SelectionKey.OP_ACCEPT);
}catch(ClosedChannelException e1){
System.out.println("关闭的通道,无法注册到选择器");
e1.printStackTrace();
} catch (IOException e2) {
try {
if(ssc != null) ssc.close();
} catch (IOException e) {
e.printStackTrace();
}
System.out.println("服务器绑定端口冲突");
e2.printStackTrace();
}
}
/**
* 轮询选择器
* @throws Exception
*/
public void pollSelect() throws Exception {
/* (阻塞)轮询选择器,直到有事件 */
while (this.selector.select()>0) {
/* 获取事件通知列表 */
Iterator<SelectionKey> it = this.selector.selectedKeys().iterator();
while (it.hasNext()) {
SelectionKey selectKey = it.next();
it.remove();
try {
process(selectKey);
} catch (Exception e) {
e.printStackTrace();
continue;
}
}
}
}
/**
* 事件处理
* @param selectKey
*/
public void process(SelectionKey selectKey) throws Exception{
if (selectKey.isAcceptable()) { /* 客户端连接事件 */
accept(selectKey);
} else if (selectKey.isReadable()) { /* 可读事件 */
read(selectKey);
}
}
/**
* 连接事件
* @param selectKey
*/
public void accept(SelectionKey selectKey) throws Exception {
ServerSocketChannel ssc = null;
try {
ssc = (ServerSocketChannel) selectKey
.channel();
SocketChannel sc = ssc.accept();
sc.configureBlocking(false);
/* 发送信息 */
sc.write(ByteBuffer.wrap(new String("Hello World!")
.getBytes()));
/* 注册读事件 */
sc.register(this.selector, SelectionKey.OP_READ);
} catch (ClosedChannelException e) {
if(ssc!=null)
ssc.close();
throw new IOException("关闭的通道,无法注册到选择器");
} catch (IOException e) {
if(ssc!=null)
ssc.close();
throw new IOException("连接服务或配置失败!");
}
}
/**
* 可读事件
* @param selectKey
*/
public void read(SelectionKey selectKey) throws Exception{
SocketChannel channel = null;
try {
// 服务器可读取消息:得到事件发生的Socket通道
channel = (SocketChannel) selectKey.channel();
// 创建读取的缓冲区
ByteBuffer buffer = ByteBuffer.allocate(100);
channel.read(buffer);
byte[] data = buffer.array();
String msg = new String(data).trim();
System.out.println("客户端:" + msg);
// ByteBuffer outBuffer = ByteBuffer.wrap(msg.getBytes());
// 将消息回送给客户端
// channel.write(outBuffer);
} catch (Exception e) {
if(channel != null)
channel.close();
throw new Exception("客户端将通道关闭,无法从通道读入缓冲或将缓冲数据写回通道!");
}
}
public static void main(String[] args) {
SocketServer ss = null;
try {
ss = new SocketServer("localhost", 9999);
ss.pollSelect();
} catch (Exception e) {
e.printStackTrace();
}
}
}
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.SocketChannel;
import java.util.Iterator;
/**
* 客户端
*/
public class SocketClient {
public Selector selector;
public SocketClient(String ip, int port){
SocketChannel channel = null;
try {
//channel = SocketChannel.open(new InetSocketAddress(ip,port));
channel = SocketChannel.open();
// 设置通道为非阻塞
channel.configureBlocking(false);
// 获得一个通道管理器
this.selector = Selector.open();
// 客户端连接服务器,其实方法执行并没有实现连接
channel.connect(new InetSocketAddress(ip, port));
/**while(!channel.finishConnect()){
System.out.println("尝试连接....");
}*/
// 注册连接事件。
channel.register(this.selector, SelectionKey.OP_CONNECT);
} catch(ClosedChannelException e1){
System.out.println("关闭的通道,无法注册到选择器");
e1.printStackTrace();
} catch (IOException e2) {
System.out.println("连接异常!");
try {
if(channel != null) channel.close();
} catch (IOException e) {
e.printStackTrace();
}
e2.printStackTrace();
}
}
/**
* 轮询选择器
* @throws IOException
*/
public void pollSelect() throws Exception {
/* (阻塞)轮询选择器,直到有事件 */
while ( this.selector.select() > 0 ) {
/* 获取事件通知列表 */
Iterator<SelectionKey> ite = this.selector.selectedKeys().iterator();
while (ite.hasNext()) {
SelectionKey selectKey = (SelectionKey) ite.next();
// 删除已选的key,以防重复处理
ite.remove();
process(selectKey);
}
}
}
/**
* 处理事件
* @param selectKey
*/
public void process(SelectionKey selectKey) throws Exception{
if (selectKey.isConnectable()) {
connect(selectKey);
} else if (selectKey.isReadable()) {
read(selectKey);
}
}
/**
* 连接事件
* @param selectKey
* @throws Exception
*/
public void connect(SelectionKey selectKey) throws Exception{
try {
SocketChannel channel = (SocketChannel) selectKey
.channel();
/* 如果正在连接,则完成连接 */
if(channel.isConnectionPending()){
/**
* connect()方法尚未被调用,调用finishConnect()方法,
* 那么将产生NoConnectionPendingException
*/
channel.finishConnect();
}
/**
* 在非阻塞模式下调用connect()方法之后,SocketChannel又被切换回了阻塞模式;那么如果
* 有必要的话,调用线程会阻塞直到连接建立完成,finishConnect()方法接着就会返回true
* 值。
*/
/* 设置成非阻塞 */
channel.configureBlocking(false);
/* 给服务端发送信息 */
channel.write(ByteBuffer.wrap(new String("编号001客户端连接成功!").getBytes()));
/* 注册读事件 */
channel.register(this.selector, SelectionKey.OP_READ);
} catch (ClosedChannelException e) {
throw new IOException("关闭的通道,无法注册到选择器");
} catch (IOException e) {
throw new IOException("连接服务或配置失败!");
}
}
/**
* 读事件
* @param selectKey
* @throws Exception
*/
public void read(SelectionKey selectKey) throws Exception{
try {
// 服务器可读通道
SocketChannel channel = (SocketChannel) selectKey.channel();
// 创建读取的缓冲区
ByteBuffer buffer = ByteBuffer.allocate(100);
channel.read(buffer);
byte[] data = buffer.array();
String msg = new String(data).trim();
System.out.println(msg);
ByteBuffer outBuffer = ByteBuffer.wrap(msg.getBytes());
// 将消息回送给服务端
//channel.write(outBuffer);
} catch (Exception e) {
throw new IOException("服务端将通道关闭,无法从通道读入缓冲或将缓冲数据写回通道!");
}
}
public static void main(String[] args) {
SocketClient sc = null;
try {
sc = new SocketClient("localhost", 9999);
sc. pollSelect();
} catch (Exception e) {
e.printStackTrace();
}
}
}