package nio;
import java.net.InetSocketAddress;
import java.net.ServerSocket;
import java.net.URLDecoder;
import java.net.URLEncoder;
import java.nio.ByteBuffer;
import java.nio.channels.SelectableChannel;
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 SocketServer1 {
static {
// BasicConfigurator.configure();
}
/**
* 日志
*/
public static void main(String[] args) throws Exception {
ServerSocketChannel serverChannel = ServerSocketChannel.open();
serverChannel.configureBlocking(false);
ServerSocket serverSocket = serverChannel.socket();
serverSocket.setReuseAddress(true);
serverSocket.bind(new InetSocketAddress(83));
Selector selector = Selector.open();
//注意、服务器通道只能注册SelectionKey.OP_ACCEPT事件
serverChannel.register(selector, SelectionKey.OP_ACCEPT);
try {
while(true) {
//如果条件成立,说明本次询问selector,并没有获取到任何准备好的、感兴趣的事件
//java程序对多路复用IO的支持也包括了阻塞模式 和非阻塞模式两种。
if(selector.select(100) == 0) {
//================================================
// 这里视业务情况,可以做一些然并卵的事情
//================================================
continue;
}
//这里就是本次询问操作系统,所获取到的“所关心的事件”的事件类型(每一个通道都是独立的)
Iterator<SelectionKey> selecionKeys = selector.selectedKeys().iterator();
while(selecionKeys.hasNext()) {
SelectionKey readyKey = selecionKeys.next();
//这个已经处理的readyKey一定要移除。如果不移除,就会一直存在在selector.selectedKeys集合中
//待到下一次selector.select() > 0时,这个readyKey又会被处理一次
selecionKeys.remove();
SelectableChannel selectableChannel = readyKey.channel();
if(readyKey.isValid() && readyKey.isAcceptable()) {
System.out.println("======channel通道已经准备好=======");
/*
* 当server socket channel通道已经准备好,就可以从server socket channel中获取socketchannel了
* 拿到socket channel后,要做的事情就是马上到selector注册这个socket channel感兴趣的事情。
* 否则无法监听到这个socket channel到达的数据
* */
ServerSocketChannel serverSocketChannel = (ServerSocketChannel)selectableChannel;
SocketChannel socketChannel = serverSocketChannel.accept();
registerSocketChannel(socketChannel , selector);
} else if(readyKey.isValid() && readyKey.isConnectable()) {
System.out.println("======socket channel 建立连接=======");
} else if(readyKey.isValid() && readyKey.isReadable()) {
System.out.println("======socket channel 数据准备完成,可以去读==读取=======");
readSocketChannel(readyKey);
}
}
}
} catch(Exception e) {
System.out.println(e);
} finally {
serverSocket.close();
}
}
/**
* 在server socket channel接收到/准备好 一个新的 TCP连接后。
* 就会向程序返回一个新的socketChannel。<br>
* 但是这个新的socket channel并没有在selector“选择器/代理器”中注册,
* 所以程序还没法通过selector通知这个socket channel的事件。
* 于是我们拿到新的socket channel后,要做的第一个事情就是到selector“选择器/代理器”中注册这个
* socket channel感兴趣的事件
* @param socketChannel 新的socket channel
* @param selector selector“选择器/代理器”
* @throws Exception
*/
private static void registerSocketChannel(SocketChannel socketChannel , Selector selector) throws Exception {
socketChannel.configureBlocking(false);
//socket通道可以且只可以注册三种事件SelectionKey.OP_READ | SelectionKey.OP_WRITE | SelectionKey.OP_CONNECT
socketChannel.register(selector, SelectionKey.OP_READ , ByteBuffer.allocate(2048));
}
/**
* 这个方法用于读取从客户端传来的信息。
* 并且观察从客户端过来的socket channel在经过多次传输后,是否完成传输。
* 如果传输完成,则返回一个true的标记。
* @throws Exception
*/
private static void readSocketChannel(SelectionKey readyKey) throws Exception {
SocketChannel clientSocketChannel = (SocketChannel)readyKey.channel();
//获取客户端使用的端口
InetSocketAddress sourceSocketAddress = (InetSocketAddress)clientSocketChannel.getRemoteAddress();
Integer resoucePort = sourceSocketAddress.getPort();
//拿到这个socket channel使用的缓存区,准备读取数据
//在后文,将详细讲解缓存区的用法概念,实际上重要的就是三个元素capacity,position和limit。
ByteBuffer contextBytes = (ByteBuffer)readyKey.attachment();
//将通道的数据写入到缓存区,注意是写入到缓存区。
//由于之前设置了ByteBuffer的大小为2048 byte,所以可以存在写入不完的情况
//没关系,我们后面来调整代码。这里我们暂时理解为一次接受可以完成
int realLen = -1;
try {
realLen = clientSocketChannel.read(contextBytes);
} catch(Exception e) {
//这里抛出了异常,一般就是客户端因为某种原因终止了。所以关闭channel就行了
System.out.println(e.getMessage());
clientSocketChannel.close();
return;
}
//如果缓存区中没有任何数据(但实际上这个不太可能,否则就不会触发OP_READ事件了)
if(realLen == -1) {
System.out.println("====缓存区没有数据? ====");
return;
}
//将缓存区从写状态切换为读状态(实际上这个方法是读写模式互切换)。
//这是java nio框架中的这个socket channel的写请求将全部等待。
contextBytes.flip();
//注意中文乱码的问题,我个人喜好是使用URLDecoder/URLEncoder,进行解编码。
//当然java nio框架本身也提供编解码方式,看个人咯
byte[] messageBytes = contextBytes.array();
String messageEncode = new String(messageBytes , "UTF-8");
String message = URLDecoder.decode(messageEncode, "UTF-8");
//如果收到了“over”关键字,才会清空buffer,并回发数据;
//否则不清空缓存,还要还原buffer的“写状态”
if(message.indexOf("over") != -1) {
//清空已经读取的缓存,并从新切换为写状态(这里要注意clear()和capacity()两个方法的区别)
contextBytes.clear();
System.out.println("端口:" + resoucePort + "客户端发来的信息======message : " + message);
//======================================================
// 当然接受完成后,可以在这里正式处理业务了
//======================================================
//回发数据,并关闭channel
没有合适的资源?快使用搜索试试~ 我知道了~
测试代码,包括各种数据结构的算法
共142个文件
java:139个
search:1个
xml:1个
需积分: 0 0 下载量 72 浏览量
2024-05-20
09:38:04
上传
评论
收藏 86KB ZIP 举报
温馨提示
测试代码,包括各种数据结构的算法
资源推荐
资源详情
资源评论
收起资源包目录
测试代码,包括各种数据结构的算法 (142个子文件)
testDemo.iml 901B
SocketServer1.java 8KB
Main.java 3KB
main.java 3KB
NIOServer.java 3KB
FutureTaskForMultiCompute.java 2KB
leet51.java 2KB
leet01.java 2KB
LCR060.java 2KB
leet92.java 2KB
CompletionServiceExample2.java 2KB
mergerSort.java 2KB
leet52.java 2KB
MyLockTest.java 2KB
Demo.java 2KB
OracleQuerySpeedTest.java 2KB
ArrayTest.java 2KB
CountDownLatchExample.java 2KB
leettest.java 2KB
Subtract.java 2KB
CountDownLatchModule.java 2KB
CompletionServiceExample.java 2KB
SemaphoreTest.java 2KB
LinkedBlockingQueueExample.java 2KB
leet662.java 2KB
ProducerConsumerExample.java 2KB
testThreadLocal.java 2KB
ABTest.java 1KB
leet76.java 1KB
JoinTest2.java 1KB
WorkerPool.java 1KB
leet438.java 1KB
leet567.java 1KB
MyMonitorThread.java 1KB
leet46.java 1KB
MyCircularQueue.java 1KB
leet124.java 1KB
leet322.java 1KB
testStream.java 1KB
leet92_02.java 1KB
FlattenTreeTest.java 1KB
testHashMap.java 1016B
testComparator.java 993B
TravelTask.java 989B
leet543.java 989B
leet34.java 985B
TaskCallAble.java 971B
leet39.java 925B
testString.java 921B
LCR044.java 895B
leet216.java 889B
MyQueue.java 888B
leet111.java 879B
leet03.java 878B
leet654.java 863B
ReferenceCountingGC.java 857B
leet25.java 853B
leet116.java 844B
SimpleThreadPool.java 821B
TestNull.java 814B
leet752.java 812B
ReorderListTest.java 806B
Trie.java 798B
SheduledThreadPoolExecutorExample.java 797B
Add.java 779B
MutexLock.java 770B
leet5.java 769B
TestJoin.java 754B
LCR044_2.java 733B
leet140.java 727B
leet77.java 704B
CustomLinkedBlockingQueue.java 695B
leet315.java 688B
leet23.java 680B
leet78.java 678B
leet83.java 666B
MyStack.java 663B
WorkerThread.java 662B
Test.java 658B
Client.java 656B
Singleton.java 636B
MinStack.java 621B
leet86.java 618B
leet143.java 617B
leet167.java 609B
leet19.java 577B
laohuguoji.java 565B
leet303.java 548B
leet704.java 543B
leet114.java 542B
leet142.java 536B
xunhuanList.java 529B
leet543_2.java 490B
Node.java 484B
leet26.java 463B
TourGuideTask.java 457B
leet239.java 447B
TestExecutor.java 445B
DoHystrix.java 429B
leet344.java 421B
共 142 条
- 1
- 2
资源评论
Artisan_w
- 粉丝: 1343
- 资源: 6
上传资源 快速赚钱
- 我的内容管理 展开
- 我的资源 快来上传第一个资源
- 我的收益 登录查看自己的收益
- 我的积分 登录查看自己的积分
- 我的C币 登录后查看C币余额
- 我的收藏
- 我的下载
- 下载帮助
安全验证
文档复制为VIP权益,开通VIP直接复制
信息提交成功