java基于NIO实现群聊模式
程序员文章站
2022-03-15 20:54:14
本文实例为大家分享了java基于nio实现群聊模式的具体代码,供大家参考,具体内容如下clientpackage com.qst.chat;import java.io.ioexception;imp...
本文实例为大家分享了java基于nio实现群聊模式的具体代码,供大家参考,具体内容如下
client
package com.qst.chat; 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; public class groupchatclient { private final int port = 9999; private final string host = "localhost"; private socketchannel channel; private static selector selector; private string name; public groupchatclient() throws ioexception { selector = selector.open(); // 连接服务器 channel = socketchannel.open(new inetsocketaddress(host, port)); // 设置非阻塞 channel.configureblocking(false); // 将channel 注册到selector channel.register(selector, selectionkey.op_read); name = channel.getlocaladdress().tostring().substring(1); system.out.println(name + "is ok ...."); } // 向服务器发送消息 public void sendto(string msg) { bytebuffer buffer = bytebuffer.wrap((name+":"+msg).getbytes()); try { channel.write(buffer); } catch (ioexception e) { // todo auto-generated catch block e.printstacktrace(); } } // 读取从服务器端回复的消息 public static void getinfo() { try { if(selector.select() >0) { iterator<selectionkey> iterator = selector.selectedkeys().iterator(); while(iterator.hasnext()) { selectionkey key = iterator.next(); if(key.isreadable()) { // 得到通道 socketchannel sc = (socketchannel) key.channel(); bytebuffer buffer = bytebuffer.allocate(1024); int len; // 把读到的缓冲区的数据转成字符串 while((len = sc.read(buffer)) > 0) { system.out.println(new string(buffer.array())); } } } // 删除当前的selectionkey, 防止重复操作 iterator.remove(); } } catch (ioexception e) { // todo auto-generated catch block e.printstacktrace(); } } public static void main(string[] args) { try { groupchatclient client = new groupchatclient(); new thread() { public void run() { while(true) { try { thread.sleep(3000); groupchatclient.getinfo(); } catch (interruptedexception e) { // todo auto-generated catch block e.printstacktrace(); } } }; }.start(); scanner sc = new scanner(system.in); // while(true) { // string name = sc.nextline(); // client.sendto(name); // } while(sc.hasnextline()) { string s = sc.nextline(); client.sendto(s); } } catch (ioexception e) { // todo auto-generated catch block e.printstacktrace(); } } }
server端
package com.qst.chat; import java.io.ioexception; import java.net.inetaddress; import java.net.inetsocketaddress; import java.net.serversocket; import java.net.socket; 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.time.chrono.isochronology; import java.util.iterator; import com.sun.accessibility.internal.resources.accessibility; import sun.print.resources.serviceui; public class groupchatserver { private static serversocketchannel socketchannel; private static socket socket; private static selector selector; private static socketchannel accept; public groupchatserver() throws ioexception { socketchannel = serversocketchannel.open(); selector = selector.open(); // 绑定端口 socketchannel.socket().bind(new inetsocketaddress(9999)); // 设置非阻塞模式 socketchannel.configureblocking(false); // 将该通道 注册到selector socketchannel.register(selector, selectionkey.op_accept); } // 监听 public static void listen() { system.out.println("监听线程: " + thread.currentthread().getname()); try { while (selector.select() > 0) { iterator<selectionkey> iterator = selector.selectedkeys().iterator(); if (iterator.hasnext()) { // 遍历得到selectionkey 集合 selectionkey next = iterator.next(); if (next.isacceptable()) { next.channel(); // socketchannel = (serversocketchannel) next.channel(); socketchannel accept = socketchannel.accept(); accept.configureblocking(false); accept.register(selector, selectionkey.op_read); system.out.println(accept.getremoteaddress()+" 上线 了。。。"); } if (next.isreadable()) { readdate(next); } // 移除当前的next,防止重复处理 iterator.remove(); // system.out.println("未发现"); } } } catch (ioexception e) { // todo auto-generated catch block e.printstacktrace(); } } // 读取客户端消息 public static void readdate(selectionkey key) { try { accept = (socketchannel) key.channel(); bytebuffer buffer = bytebuffer.allocate(1024); int len = accept.read(buffer); if (len > 0) { buffer.flip(); string msg = new string(buffer.array()); system.out.println("user = " + msg); // 向其它的客户端转发消息(去掉自己) sendtoall(msg, accept); buffer.clear(); } } catch (ioexception e) { // todo auto-generated catch block try { string msg = accept.getremoteaddress().tostring(); // 取消注册 key.cancel(); // 关闭通道 accept.close(); system.out.println(msg + "离线了"); } catch (ioexception e1) { // todo auto-generated catch block e1.printstacktrace(); } // e.printstacktrace(); } finally { // todo: handle finally clause } } public static void sendtoall(string msg, socketchannel ssc) { for (selectionkey ss : selector.keys()) { // 通过 key 取出对应的 socketchannel selectablechannel channel = ss.channel(); // 排除自己 if (channel instanceof socketchannel && channel != ssc) { // 转型 socketchannel sh = (socketchannel) channel; // 转存到buffer bytebuffer wrap = bytebuffer.wrap(msg.getbytes()); try { // 写入通道 sh.write(wrap); } catch (ioexception e) { // todo auto-generated catch block e.printstacktrace(); } } } } public static void main(string[] args) throws ioexception { groupchatserver server = new groupchatserver(); groupchatserver.listen(); } }
key.isacceptable()进行接入 操作的时候, 获取通道有两种方式
1、 通过selector获取 (selector key) socketchannel = (serversocketchannel) key.channel();
建立连接 socketchannel .accept();
2、定义一个全局变量
在进行初始化的时候,存储(socketchannel = serversocketchannel.open();)
建立连接 socketchannel .accept();
key.isreadable() 当进行到读入操作的时候( ) selectionkey key accept = (socketchannel) key.channel();
演示
服务器启动,客户端启动
客户端发送消息
启动第二个客户端
两个客户端相互通信
离线信息显示
以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持。