之前一直在使用“everythreadperconnection”服务器端模式,今天尝试了NIO非阻塞模式服务器。但是java无法实现I/O完成端口模型,很遗憾。packagecom.vista.Server;importjava.io.IOException;importjava.net.InetSocketAddress;importjava.net.ServerSocket;importjava.nio.ByteBuffer;importjava.nio.channels.SelectionKey;importjava.nio.channels.Selector;importjava.nio。channels.ServerSocketChannel;importjava.nio.channels.SocketChannel;importjava.util.Iterator;importjava.util.LinkedList;importjava.util.Set;publicclassSelectorServer{privatestaticintDEFAULT_SERVERPORT=6018;//默认端口privatestaticintDEFAULT_BUFFERSI42大小;/=privateServerSocketChannelchannel;privateLinkedListclients;privateSelectorreadSelector;privateByteBufferbuffer;//字节缓冲区privateintport;publicSelectorServer(intport)throwsIOException{this.port=port;this.clients=newLinkedList=null;this.readSelector=Selector.open();//打开selectorthis.buffer=ByteBuffer.allocate(DEFAULT_BUFFERSIZE);}//服务端程序在服务循环中调用sericeClients()方法为接受的客户服务publicvoidserviceClients()throwsIOException{Setkeys;Iteratorit;SelectionKeykey;SocketChannelclient;//在readSelector上调用select()方法,参数1表示如果调用select,最多阻塞1秒,等待可用的客户端连接if(readSelector.select(1)>0){keys=readSelector.selectedKeys();//获取代表渠道的key集合it=keys.iterator();//遍历并为每个客户服务while(it.hasNext()){key=(SelectionKey)it.next();if(key.isReadable()){//如果channel是可读的,则读取这个channel进行缓冲intbytes;client=(SocketChannel)key.channel();//获取对应的channelkeybuffer.clear();//清空buffer中的内容,设置position和limit,准备接收数据bytes=client.read(buffer);//从channel读取数据到buffer,并返回读取的字节数if(bytes>=0){buffer.flip();//准备将缓冲区中的数据写回通道client.write(buffer);//将数据写回通道}elseif(bytes<0){//如果返回A值小于大于零表示已经读取到流的结尾clients.remove(client);//关闭通道时,选择键也被取消client.close();}}}}}publicvoidregisterClient(SocketChannelclient)throwsIOException{//配置和注册Client.configureBlocking(false);//设置这个通道使用非阻塞模式client.register(readSelector,SelectionKey.OP_READ);//注册这个通道到selectorclients.add(client);//保存这个通道对象}publicvoidlisten()throwsIOException{//服务器开始监听端口并提供服务ServerSocketsocket;SocketChannelclient;cchannel=ServerSocketChannel.open();//打开通道socket=channel.socket();//获取通道相关的socket对象socket.bind(newInetSocketAddress(port),10);//设置scoket列表in在指定的端口上//配置为使用非阻塞模式,在非阻塞模式下,可以编写多通道程序同时避免使用复杂的多线程channel.configureBlocking(false);try{while(true){//与通常的程序不同。这里的channel.accpet()用于接受客户端连接请求,而不是在套接字对象上调用accept()。如果调用accept()方法时通道配置为非阻塞模式,accept()方法立即返回null,不阻塞client=channel.accept();if(client!=null){registerClient(client);//注册客户信息}serviceClients();//服务连接的客户端}}finally{socket.close();//关闭套接字,关闭套接字也会关闭与这个套接字关联的通道}}publicstaticvoidmain(String[]args)throwsIOException{System.out.println("Serverstartup");SelectorServerserver=newSelectorServer(SelectorServer.DEFAULT_SERVERPORT);server.listen();//服务器开始监听端口并提供服务}}修改版本:packagecom.vista.Server;importjava.io.BufferedWriter;importjava.io.FileInputStream;importjava.io.IOException;导入java.io。OutputStreamWriter;importjava.io.PrintWriter;importjava.net.InetSocketAddress;importjava.net.ServerSocket;importjava.nio.ByteBuffer;importjava.nio.CharBuffer;importjava.nio.channels.FileChannel;importjava.nio.channels.SelectionKey;importjava.nio.channels.Selector;importjava.nio.channels.ServerSocketChannel;importjava.nio.channels.SocketChannel;importjava.nio.charset.Charset;importjava.nio.charset.CharsetDecoder;importjava.util.Iterator;importjava.util.LinkedList;importjava.util.Set;publicclassSelectorServer{privatestaticintDEFAULT_SERVERPORT=6018;//默认端口privatestaticintDEFAULT_BUFFERSIZE=1024;//默认缓冲区大小为1024字节privatestaticStringDEFAULT_CHARSET="GB2312";//默认代码集privatestaticStringDEFAULT_FILENAME="bigfile.dat";privateServerSocketChannelchannel;privateLinkedListclients;privateSelectorselector;//选择器privateByteBuffer/字节缓冲区;/privateintport;privateCharsetcharset;//字符集privateCharsetDecoderdecoder;//解码器publicSelectorServer(intport)throwsIOException{this.port=port;this.clients=newLinkedList();this.chann埃尔=null;this.selector=Selector.open();//打开选择器this.buffer=ByteBuffer.allocate(DEFAULT_BUFFERSIZE);this.charset=Charset.forName(DEFAULT_CHARSET);this.decoder=this.charset.newDecoder();}privateclassHandleClient{privateStringstrGreeting="welcometoVistaQQ";publicHandleClient()throwsIOException{}publicStringreadBlock(){//读取区块数据returnthis.strGreeting;}publicvoidclose(){}}protectedvoidhandleKey(SelectionKeykey)throwsIOException{key//处理事件if(isAcceptable()){//接收请求ServerSocketChannelserver=(ServerSocketChannel)key.channel();//获取对应的服务器通道SocketChannelchannel=server.accept();channel.configureBlocking(false);channel.register(selector,SelectionKey.OP_READ);//客户socket通道注册读操作}elseif(key.isReadable()){//读取信息SocketChannelchannel=(SocketChannel)key.channel();intcount=channel.read(this.buffer);if(count>0){this.buffer.flip();CharBuffercharBuffer=decoder.decode(this.buffer);System.out.println("Client>>"+charBuffer.toString());SelectionKeywKey=channel.register(selector,SelectionKey.OP_WRITE);//注册客户端sockt通道的写操作wKey.attach(newHandleClient());}else{//客户端断开channel.close();}this.buffer.clear();//清空缓冲区}elseif(key.isWritable()){//写事件wrap(handle.readBlock().getBytes());channel.write(block);//channel.socket().getInputStream().(block);//PrintWriterout=newPrintWriter(newBufferedWriter(newOutputStreamWriter(//channel.socket().getOutputStream())),true);//out.write(block.toString());}}publicvoidlisten()throwsIOException{//服务器开始监听端口并提供服务ServerSocketsocket;channel=ServerSocketChannel.open();//打开通道socket=channel.socket();//获取通道相关的socket对象socket.bind(newInetSocketAddress(port));//设置socket到指定端口//配置使用非blo锁定模式。在非阻塞模式下,可以编写多程序,同时避免复杂的多线程channel.configureBlocking(false);channel.register(selector,SelectionKey.OP_ACCEPT);try{while(true){//与通常的程序不同,这里使用channel.accpet()接受客户端连接请求,而不是在socket对象上调用accept(),如果调用accept()方法时通道配置为非阻塞模式,那么accept()方法立即返回null,不会阻塞this.selector.select();Iteratoriter=this.selector.selectedKeys().iterator();while(iter.hasNext()){SelectionKeykey=(SelectionKey)iter.next();iter.remove();this.handleKey(key);}}}catch(IOExceptionex){ex.printStackTrace();}}publicstaticvoidmain(String[]args)throwsIOException{System.out.println("ServerStart");SelectorServerserver=newSelectorServer(SelectorServer.DEFAULT_SERVERPORT);server.listen();//Server开始监听端口并提供服务}}原文链接:https://img.ydisp.cn/news/20220914/jwqrd3klzll.html【编者推荐】基于JavaNIO即时聊天服务器模型的JavaNIOSocket非阻塞模式解读Socket服务器使用Java.nio.*进行网络编程JavaNIO唤醒分析