package nonblock;
import java.io.*;
import java.nio.*;
import java.nio.channels.*;
import java.nio.charset.*;
import java.net.*;
import java.util.*;
public class EchoServer{
private Selector selector = null;
private ServerSocketChannel serverSocketChannel = null;
private int port = 8000;
private Charset charset=Charset.forName("GBK");
public EchoServer()throws IOException{//构造类的方法启动服务器,把它绑定到一个本地端口
//创建一个Selector对象
// 监听作用 ServerSocketChannel—接收就绪事件 SocketChannel—连接就绪、读就绪和写就绪 注册事件过程
selector = Selector.open();
//创建一个ServerSocketChannel对象
serverSocketChannel= ServerSocketChannel.open();
//使得在同一个主机上关闭了服务器程序,紧接着启动该服务器程序时能顺利绑定到同一个端口
serverSocketChannel.socket().setReuseAddress(true);
//使ServerSocketChannel工作与非阻塞模式
serverSocketChannel.configureBlocking(false);
//把服务器进程与一个本地端口绑定
serverSocketChannel.socket().bind(new InetSocketAddress(port));
System.out.println("服务器启动");
}
public void service() throws IOException{
//server()方法通过SelectionKey的channel()的方法获得与它关联的ServerSocketChannel对象
// 然后调用它的accept()方法获得与客户链接的SocketChannel对象
//一般来说SocketChannel对象默情况处于阻塞模式,希望它执行非阻塞IO,调用以下的方法
serverSocketChannel.register(selector, SelectionKey.OP_ACCEPT );
//ServerSocketChannel向Selector注册连接就绪事件,如果监控到该事件发生,就会把相应的SelectionKey对象加入到selected-keys集合
while (selector.select() > 0 ){//第一层while循环 轮询方式询问Selector已经发生的事件,然后依次处理每个事件
Set readyKeys = selector.selectedKeys();//获得Selector的selected-keys集合
Iterator it = readyKeys.iterator();
while (it.hasNext()){ //第二层while循环 从selected-keys集合中依次取出每个SelectionKey对象,然后删除
//调用方法判断哪种事件发生,做出相应的处理。放在try语句里面,
// 如果异常,在catch语句里面使这个SelectionKey失效,并且关闭与之关联的Channel
SelectionKey key=null; //SelectionKey用来追踪被注册的事件
try{//处理SelectionKey
key = (SelectionKey) it.next();//取出一个SelectionKey
it.remove();//把一个SelectionKey从Selector的selected-keys集合中删除
if (key.isAcceptable()) {//处理接收连接就绪事件
//获得与SelectionKey关联的ServerSocketChannel
ServerSocketChannel ssc = (ServerSocketChannel) key.channel();
SocketChannel socketChannel = (SocketChannel) ssc.accept();
System.out.println("接收到客户连接,来自:" +
socketChannel.socket().getInetAddress() +
":" + socketChannel.socket().getPort());
//把socketChannel设置为非阻塞模式
socketChannel.configureBlocking(false);
//创建一个用于存放用户发送来的数据的缓冲区
ByteBuffer buffer = ByteBuffer.allocate(1024);
//SocketChannel向Selector注册读就绪和写就绪事件
socketChannel.register(selector,
SelectionKey.OP_READ |
SelectionKey.OP_WRITE, buffer);//关联一个buffer附件
}
if (key.isReadable()) {//处理读就绪事件
receive(key);
}
if (key.isWritable()) {//处理写就绪事件
send(key);
}
}catch(IOException e){
e.printStackTrace();
try{
if(key!=null){//使这个SelectionKey失效,使得Selector不再监控这个SelectionKet感兴趣事件
key.cancel();
key.channel().close();
}
}catch(Exception ex){e.printStackTrace();}
}
}//#while
}//#while
}
public void send(SelectionKey key)throws IOException{
//从ByteBuffer中取出数据,获取与SelectionKey相关联的ByteBuffer
ByteBuffer buffer=(ByteBuffer)key.attachment();
//获取与SelectionKey相关联的SocketChannel
SocketChannel socketChannel=(SocketChannel)key.channel();
buffer.flip(); //把极限设为位置,把位置设为0
String data=decode(buffer);
//如果还没有读到一行数据就返回
if(data.indexOf("\r\n")==-1)return;
//截取一行数据
String outputData=data.substring(0,data.indexOf("\n")+1);
//把输出的字符串按照GBK编码,转换为字节,放在outputBuffer中
System.out.print(outputData);
ByteBuffer outputBuffer=encode("echo:"+outputData);
//输出outputBuffer中的所有字节按照GBK编码,转换为字节,放在outputBuffer中
while(outputBuffer.hasRemaining())//判断是否还有未处理的字节
socketChannel.write(outputBuffer);
//把outputData字符串
ByteBuffer temp=encode(outputData);
//把buffer的位置设置为temp的极限
buffer.position(temp.limit());
//删除buffer中已经处理的数据
buffer.compact();
//如果已经输出了字符串"bye\r\n",使得SelectionKey失效,并且关闭SocketChannel
if(outputData.equals("bye\r\n")){
key.cancel();
socketChannel.close();
System.out.println("关闭与客户的连接");
}
}
public void receive(SelectionKey key)throws IOException{
//先获得这个SelectionKey关联的ByteBuffer和SocketChannel,SocketChannel每次读到的数据都被添加到这个ByteBuffer中
ByteBuffer buffer=(ByteBuffer)key.attachment();
//获得与SelectionKey关联的socketChannel
SocketChannel socketChannel=(SocketChannel)key.channel();
//创建一个ByteBuffer,用于存放读到的数据
ByteBuffer readBuff= ByteBuffer.allocate(32);
socketChannel.read(readBuff);
readBuff.flip();
//把buffer的极限设置为容量
buffer.limit(buffer.capacity());
//把readBuffer的内容拷贝到buffer中,假定buffer的容量足够大,不会出现缓冲区异常溢出异常
buffer.put(readBuff);
}
public String decode(ByteBuffer buffer){ //解码
CharBuffer charBuffer= charset.decode(buffer);
return charBuffer.toString();
}
public ByteBuffer encode(String str){ //编码
return charset.encode(str);
}
public static void main(String args[])throws Exception{
EchoServer server = new EchoServer();
server.service();
}
}
没有合适的资源?快使用搜索试试~ 我知道了~
资源详情
资源评论
资源推荐
收起资源包目录
socket非阻塞通信.zip (48个子文件)
非阻塞通信.docx 2.22MB
chapter04
out
production
chapter04
block
Handler.class 3KB
EchoServer.class 2KB
_desktop.ini 9B
EchoClient.class 3KB
nonblock
PingClient.class 5KB
EchoServer.class 5KB
PingClient$Printer.class 597B
EchoClient$1.class 587B
Target.class 2KB
_desktop.ini 9B
EchoClient.class 5KB
PingClient$Connector.class 1KB
_desktop.ini 9B
thread2
EchoServer.class 6KB
_desktop.ini 9B
EchoServer$1.class 573B
chapter04.iml 433B
_desktop.ini 9B
src
block
_desktop.ini 9B
EchoServer.java 3KB
EchoClient.java 2KB
nonblock
_desktop.ini 9B
EchoServer.java 6KB
EchoClient.java 4KB
PingClient.java 6KB
_desktop.ini 9B
thread2
_desktop.ini 9B
EchoServer.java 4KB
.idea
.gitignore 292B
workspace.xml 6KB
encodings.xml 162B
misc.xml 263B
modules.xml 265B
chapter4code.rar 8KB
classes
block
Handler.class 3KB
EchoServer.class 2KB
EchoClient.class 3KB
nonblock
PingClient.class 5KB
EchoServer.class 5KB
PingClient$Printer.class 587B
EchoClient$1.class 590B
Target.class 2KB
EchoClient.class 5KB
PingClient$Connector.class 1021B
thread2
EchoServer.class 6KB
EchoServer$1.class 576B
build.xml 825B
共 48 条
- 1
傲娇味的草莓
- 粉丝: 360
- 资源: 31
上传资源 快速赚钱
- 我的内容管理 展开
- 我的资源 快来上传第一个资源
- 我的收益 登录查看自己的收益
- 我的积分 登录查看自己的积分
- 我的C币 登录后查看C币余额
- 我的收藏
- 我的下载
- 下载帮助
安全验证
文档复制为VIP权益,开通VIP直接复制
信息提交成功
评论0