NIO之SocketChannel;ServerSocketChannel

来源:互联网 发布:软件职位 编辑:程序博客网 时间:2024/05/04 22:03

package com.zsb.io.nio.server;
import java.io.IOException;
import java.net.InetSocketAddress;
import java.nio.ByteBuffer;
import java.nio.channels.SelectionKey;
import java.nio.channels.Selector;
import java.nio.channels.ServerSocketChannel;
import java.nio.channels.SocketChannel;
import java.util.HashMap;
import java.util.Iterator;
import java.util.Map;


/**
 * NIO服务器
 * Date: 2017年4月4日 <br>
 * @author zhousb
 * Copyright (c) 2016 asiainfo.com <br>
 */
public class NIOServer {

//通道管理器(多路复用器)
private Selector selector;

private ServerSocketChannel serverChannel = null;

private Map<SelectionKey,String> sessionMap = new HashMap<SelectionKey,String>();

/**
* 获得一个ServerSocket通道,并对该通道做一些初始化的工作
* @param port  绑定的端口号
* @throws IOException
*/
public void init(int port) throws IOException {
// 获取一个socket高速双工通道
serverChannel = ServerSocketChannel.open();
// 设置通道为非阻塞
serverChannel.configureBlocking(false);
// 通道socket 绑定监听端口
serverChannel.socket().bind(new InetSocketAddress(port));
// 创建多路复用器
setSelector(Selector.open());
//通道关联多路复用器,同时向多路复用器注册客户端连接事件监听
serverChannel.register(getSelector(), SelectionKey.OP_ACCEPT);
System.out.println("NIO服务器已启动,且监听端口为:"+port);
}

/**
* 采用轮询的方式监听selector上是否有需要处理的事件,如果有,则进行处理
* @throws IOException
*/
public void listen() throws IOException {
// 轮询访问selector
while (true) {
//此方法一直阻塞,直到建立channel连接
int eventCount = getSelector().select();
if(eventCount == 0){
continue;
}
//System.out.println(eventCount);
//多路复用器中获取获取事件处理
Iterator<SelectionKey> itr = this.getSelector().selectedKeys().iterator();
while (itr.hasNext()) {
SelectionKey key = (SelectionKey) itr.next();
handleClient(key);
itr.remove();
}


}
}

/**
* 处理客户端连接
* @param key
*/
private void handleClient(SelectionKey key) {
SocketChannel client = null;
try{
if(!key.isValid()){
return;
}
if(key.isAcceptable()){
//客户端连接上服务器
client = serverChannel.accept();
client.configureBlocking(false);
System.out.println("客户端【"+client.getRemoteAddress()+"已连接上服务器】");
client.register(getSelector(), SelectionKey.OP_READ);
}
if(key.isReadable()){
ByteBuffer buf = ByteBuffer.allocate(2048);
client = (SocketChannel) key.channel();
String msg = "";
if((client.read(buf)) >= 0){
msg = new String(buf.array());
}
System.out.println("服务器接收到消息:【"+msg.trim()+"】");
sessionMap.put(key, msg.trim());
client.register(getSelector(), SelectionKey.OP_WRITE);
}
if(key.isWritable()){
if(sessionMap.containsKey(key)){
//回复客户端消息
client = (SocketChannel) key.channel();
client.write(ByteBuffer.wrap(("你发送的消息【"+sessionMap.get(key)+"】已被服务接收到").getBytes()));
client.register(getSelector(), SelectionKey.OP_READ);
}
}
}
catch(Exception e){
e.printStackTrace();
try {
client = (SocketChannel)key.channel();
client.socket().close();
client.close();
key.cancel();
System.out.println("客户端【"+client.getRemoteAddress()+"】操作异常");
} catch (Exception e1) {
e1.printStackTrace();
}
}

}

/**
* 启动服务端测试
* @throws IOException 
*/
public static void main(String[] args) throws IOException {
NIOServer server = new NIOServer();
server.init(8000);
server.listen();


}
public Selector getSelector() {
return selector;
}
public void setSelector(Selector selector) {
this.selector = selector;
}
}


package com.zsb.io.nio.client;
import java.io.IOException;
import java.net.InetSocketAddress;
import java.nio.ByteBuffer;
import java.nio.channels.SelectionKey;
import java.nio.channels.Selector;
import java.nio.channels.SocketChannel;
import java.util.Iterator;
import java.util.Scanner;




/**
 * NIO客户端
 * Date: 2017年4月4日 <br>
 * @author zhousb
 * Copyright (c) 2016 asiainfo.com <br>
 */
public class NIOClient {

//通道管理器(多路复用器)
private Selector selector;

private SocketChannel clientChannel = null;

public void init(String host,int port) throws IOException {
// 获取一个socket高速双工通道
clientChannel = SocketChannel.open();
// 设置通道为非阻塞
clientChannel.configureBlocking(false);
//连接服务器
clientChannel.connect(new InetSocketAddress(host, port));
// 创建多路复用器
setSelector(Selector.open());
clientChannel.register(getSelector(), SelectionKey.OP_CONNECT);

}


/**
* 采用轮询的方式监听selector上是否有需要处理的事件,如果有,则进行处理
* @throws IOException
*/
public void listen() throws IOException {
// 轮询访问selector
while (true) {
//此方法一直阻塞,直到建立channel连接
int eventCount = getSelector().select();
if(eventCount == 0){
continue;
}
//多路复用器中获取获取事件处理
Iterator<SelectionKey> itr = this.getSelector().selectedKeys().iterator();
while (itr.hasNext()) {
SelectionKey key = (SelectionKey) itr.next();
handleClient(key);
itr.remove();
}


}
}

/**
* 处理客户端连接
* @param key
*/
private void handleClient(SelectionKey key) {
SocketChannel client = null;
try{

if(!key.isValid()){
return;
}
if(key.isConnectable()){
client = (SocketChannel)key.channel();
if(client.isConnectionPending()){
client.finishConnect();
}
client.configureBlocking(false);
client.write(ByteBuffer.wrap(("你好服务器我是:张"+System.currentTimeMillis()).getBytes()));
client.register(getSelector(), SelectionKey.OP_READ);
}
if(key.isReadable()){
client = (SocketChannel)key.channel();
byte []bytes = new byte[1024];
client.read(ByteBuffer.wrap(bytes));
System.out.println(new String(bytes));
client.register(getSelector(), SelectionKey.OP_WRITE);
}
if(key.isWritable()){
client = (SocketChannel)key.channel();
@SuppressWarnings("resource")
Scanner sc = new Scanner(System.in);
String message = sc.next();
client.write(ByteBuffer.wrap(message.getBytes()));
client.register(getSelector(), SelectionKey.OP_READ);
}
}
catch(Exception e){
e.printStackTrace();
client = (SocketChannel) key.channel();
try {
client.socket().close();
client.close();
key.cancel();
System.out.println("连接中断");
} catch (IOException e1) {
e1.printStackTrace();
}

}


}

/**
* 启动服务端测试
* @throws IOException 
*/
public static void main(String[] args) throws IOException {
NIOClient client = new NIOClient();
client.init("127.0.0.1",8000);
client.listen();


}
public Selector getSelector() {
return selector;
}

public void setSelector(Selector selector) {
this.selector = selector;
}

}



0 0
原创粉丝点击