Flask接口签名sign原理与实例代码浅析
308
2022-09-13
Java NIO实现聊天室功能
本文实例为大家分享了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
// 为什么这里要用迭代器,而不用增强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
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
publiNyisfVkgMsc vohttp://id 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;
}
}
}
}
版权声明:本文内容由网络用户投稿,版权归原作者所有,本站不拥有其著作权,亦不承担相应法律责任。如果您发现本站中有涉嫌抄袭或描述失实的内容,请联系我们jiasou666@gmail.com 处理,核实后本网站将在24小时内删除侵权内容。
发表评论
暂时没有评论,来抢沙发吧~