Java NIO实现聊天室功能
程序员文章站
2022-06-24 23:39:44
本文实例为大家分享了java nio实现聊天室功能的具体代码,供大家参考,具体内容如下代码里面已经包含了必要的注释,这里不详述了。实现了基本的聊天室功能。常量类:public class consta...
本文实例为大家分享了java nio实现聊天室功能的具体代码,供大家参考,具体内容如下
代码里面已经包含了必要的注释,这里不详述了。实现了基本的聊天室功能。
常量类:
public class constant { public static final int serverport = 44444; }
服务端:
package server; import java.io.ioexception; import java.net.inetsocketaddress; import java.net.socketaddress; import java.nio.bytebuffer; import java.nio.channels.closedchannelexception; import java.nio.channels.selectionkey; import java.nio.channels.selector; import java.nio.channels.serversocketchannel; import java.nio.channels.socketchannel; import java.nio.charset.charset; import java.util.iterator; import java.util.set; import constant.constant; public class socketserver { private charset charset = charset.forname("utf-8"); private serversocketchannel serversocketchannel; private selector serversocketselector; private selectionkey serverregisterkey; private bytebuffer buffer = bytebuffer.allocate(1024); public static void main(string[] args) throws ioexception { new socketserver().openserver(new inetsocketaddress(constant.serverport)); } public void openserver(socketaddress address) throws ioexception { init(address); handle(); } private void init(socketaddress address) throws ioexception { serversocketselector = selector.open(); serversocketchannel = serversocketchannel.open(); serversocketchannel.configureblocking(false); serverregisterkey = serversocketchannel.register(serversocketselector, selectionkey.op_accept); serversocketchannel.socket().bind(address); } private void handle() throws ioexception { system.out.println("服务端open"); while (serversocketselector.select() > 0) { iterator<selectionkey> iterator = serversocketselector.selectedkeys().iterator(); // 为什么这里要用迭代器,而不用增强for循环之类的呢?是因为这里获得一个key之后,要对其进行移除,避免二次处理,造成影响 while (iterator.hasnext()) { dispatch(iterator.next()); iterator.remove(); } } } private void dispatch(selectionkey key) throws ioexception { if (key.isacceptable()) { accept(key); } else if (key.isreadable()) { readmessage(key); } else if (key.isvalid() && key.iswritable()) { writemessage(key); } } private void accept(selectionkey key) throws ioexception, closedchannelexception { // 主要的是,接收事件是发生在服务器这边的,所以这边的通道要强转为serversocketchannel serversocketchannel server = (serversocketchannel) key.channel(); socketchannel client = server.accept(); client.configureblocking(false); // 同时再给该通道注册选择器,监听的内容的读取 client.register(serversocketselector, selectionkey.op_read); } private void readmessage(selectionkey key) throws ioexception { socketchannel client = (socketchannel) key.channel(); client.read(buffer); // 调整为读取模式 buffer.flip(); string content = charset.decode(buffer).tostring(); // 压缩空间,即抛弃已经读取的内容(实际上还在里面,只是处于等待被覆盖状态) buffer.compact(); // 这里可以根据业务逻辑,设置不设置都可以,但是这里想接受到消息后立马回复一条消息,所以设置下一次感兴趣的(监听)事件为写 key.interestops(selectionkey.op_write); // 设置系统回复信息 key.attach("系统已经收到你的消息\n"); // 开始广播这个客户端的内容到其他客户端 broadcast(key, content); } private void broadcast(selectionkey self, string content) throws ioexception { set<selectionkey> selectedkeys = self.selector().keys(); for (selectionkey key : selectedkeys) { // 不能发送给自己,也不要服务器自己本身对这个有反应 if (key != self && key != serverregisterkey) { string oldmessage = (string) key.attach(null); // 如果有旧消息的话,在下一次发送时,连同旧消息一起发送 key.attach(oldmessage != null ? oldmessage + content : content); key.interestops(key.interestops() | selectionkey.op_write); } } } private void writemessage(selectionkey key) throws ioexception { socketchannel client = (socketchannel) key.channel(); // 获取发给这个客户端的消息,并清空消息 client.write(charset.encode((string) key.attach(null))); key.interestops(selectionkey.op_read); } }
客户端(包含了socket版本和socketchannel版本):
package client; import java.io.ioexception; import java.net.inetsocketaddress; import java.net.socket; import java.net.unknownhostexception; import java.nio.bytebuffer; import java.nio.channels.socketchannel; import java.nio.charset.charset; import java.util.scanner; import constant.constant; public class socketclient { public static void main(string[] args) throws ioexception { nioversion(); // ioversion(); } private static void ioversion() throws unknownhostexception, ioexception { system.out.println("客户端"); final socket socket = new socket(); socket.connect(new inetsocketaddress(constant.serverport)); new thread() { @override public void run() { scanner scanner = new scanner(system.in); while (scanner.hasnext()) { string line = scanner.nextline(); try { socket.getoutputstream().write((line + "\n").getbytes("utf-8")); } catch (ioexception e) { e.printstacktrace(); } } scanner.close(); try { socket.close(); } catch (ioexception e) { // todo auto-generated catch block e.printstacktrace(); } }; }.start(); new thread() { @override public void run() { try { scanner scanner = new scanner(socket.getinputstream(), "utf-8"); while (scanner.hasnext()) { string line = scanner.nextline(); system.out.println("收到消息:" + line); } scanner.close(); } catch (ioexception e) { e.printstacktrace(); } } }.start(); } private static void nioversion() throws ioexception { charset charset = charset.forname("utf-8"); system.out.println("客户端"); socketchannel socketchannel = socketchannel.open(); // 设置为非阻塞模式 socketchannel.configureblocking(false); socketchannel.connect(new inetsocketaddress(constant.serverport)); while (true) { if (socketchannel.finishconnect()) { new thread() { @override public void run() { scanner scanner = new scanner(system.in); while (scanner.hasnext()) { string input = scanner.nextline(); try { socketchannel.write(charset.encode(input)); } catch (ioexception e) { e.printstacktrace(); } } scanner.close(); } }.start(); new thread() { bytebuffer dst = bytebuffer.allocate(1024); @override public void run() { while (true) { try { int len = socketchannel.read(dst); if (len > 0) { dst.flip(); system.out.println("收到消息:" + charset.decode(dst)); dst.compact(); } } catch (ioexception e) { // todo auto-generated catch block e.printstacktrace(); } } } }.start(); return; } } } }
以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持。
上一篇: 两个很实用的Python装饰器详解
下一篇: 深入解读python字符串函数