尬聊聊天室
代码如下
服务端代码
/**
* 聊天室服务端
* @author:PZ
* @Date: 2020/12/1 16 27
*/
public class ChatRoomServer {
/**
* 服务端通道
*/
private ServerSocketChannel channel;
/**
* 多路复用选择器
*/
private Selector selector;
public ChatRoomServer(){
try {
channel = ServerSocketChannel.open();
selector = Selector.open();
//设置端口为7777
SocketAddress address = new InetSocketAddress(7777);
channel.socket().bind(address);
//设置为非阻塞
channel.configureBlocking(false);
// 注册通道的可接收事件
channel.register(selector, SelectionKey.OP_ACCEPT);
}catch (IOException e){
e.printStackTrace();
}
}
/**
* 监听客户端的变化
*
* @throws Exception
*/
public void listenClient() throws Exception{
System.out.println("聊天室服务端启动监听");
while (true){
//选择器查找是否有事件处理
int num = selector.select();
if (num==0) {
continue;
}
//获取要处理事件的集合
Set<SelectionKey>set = selector.selectedKeys();
Iterator<SelectionKey>iterator = set.iterator();
while (iterator.hasNext()){
SelectionKey key = iterator.next();
//避免重复处理
iterator.remove();
//如果key是可连接事件
if (key.isAcceptable()){
SocketChannel clientChannel = channel.accept();
//设置为非阻塞
clientChannel.configureBlocking(false);
//聊天室客户端注册可读事件
clientChannel.register(selector,SelectionKey.OP_READ);
System.out.println("欢迎"+clientChannel.socket().getRemoteSocketAddress()+"上线啦");
continue;
}
//如果key是可读的 执行读取数据方法
if (key.isReadable()){
readData(key);
}
}
}
}
/**
* 监听到读取事件执行方法
*
* @param key
*/
private void readData(SelectionKey key){
SocketChannel channel = null;
try {
channel = (SocketChannel) key.channel();
//指定大小
ByteBuffer buffer = ByteBuffer.allocate(1024);
//num代表写入数组长度
int num = channel.read(buffer);
if (num > 0) {
String msg = new String(buffer.array());
msg = msg + "from " + channel.socket().getRemoteSocketAddress();
System.out.println("msg:" + msg);
//再将数据广播给其他的客户端,不包括发送数据的客户端自身
sendToOther(msg, channel);
}
} catch (Exception e) {
// 没有获取到通道,即为用户下线了
System.out.println("用户" + channel.socket().getRemoteSocketAddress() + "退出啦");
// 取消注册关系
key.cancel();
// 关闭通道
try {
channel.close();
} catch (IOException e1) {
e1.printStackTrace();
}
}
}
/**
* 将数据广播给其他用户
*
* @param msg
* @param selfChannel
* @throws Exception
*/
private void sendToOther(String msg, SocketChannel selfChannel) throws Exception {
// 找到所有的通道,相当于找到所有在线用户
Set<SelectionKey> set = selector.keys();
for (SelectionKey selectionKey : set) {
Channel channel = selectionKey.channel();
/**
* 判断这是一个用户,并且不是发送消息的那个人
* 代码即为
* 这是一个SocketChannel,并且不等价于selfChannel
*/
if (channel instanceof SocketChannel && channel != selfChannel) {
SocketChannel socketChannel = (SocketChannel) channel;
// wrap方法,直接将array数据存放到缓冲区
ByteBuffer buffer = ByteBuffer.wrap(msg.getBytes());
socketChannel.write(buffer);
}
}
}
public static void main(String[] args) throws Exception {
ChatRoomServer server = new ChatRoomServer();
server.listenClient();
}
}
客户端代码
/**
* @author:PZ
* @Date: 2020/12/1 16 28
*/
public class ChatRoomClient {
/**
* 客户端通道
*/
private SocketChannel channel;
/**
* 多路复用选择器
*/
private Selector selector;
public ChatRoomClient(){
try {
selector = Selector.open();
//连接的ip与端口号
SocketAddress address = new InetSocketAddress("127.0.0.1",7777);
channel = SocketChannel.open(address);
//设置为非阻塞
channel.configureBlocking(false);
//注册可读事件
channel.register(selector, SelectionKey.OP_READ);
System.out.println("欢迎"+channel.getLocalAddress()+"登录");
}catch (IOException e){
e.printStackTrace();
}
}
/**
* 发数据
* @param msg
*/
public void sendData(String msg){
ByteBuffer byteBuffer = ByteBuffer.wrap(msg.getBytes());
try {
channel.write(byteBuffer);
}catch (IOException e){
e.printStackTrace();
}
}
/**
* 监听到channel有读事件发生
*/
public void readData(){
try {
//选择器查找是否有事件处理
int num = selector.select();
if (num>0){
//获取要处理事件的集合
Set<SelectionKey>set = selector.selectedKeys();
Iterator<SelectionKey>iterator = set.iterator();
while (iterator.hasNext()){
SelectionKey key = iterator.next();
//避免重复处理
iterator.remove();
//如果key是可连接事件
if (key.isReadable()){
SocketChannel socketChannel = (SocketChannel)key.channel();
//指定大小
ByteBuffer byteBuffer = ByteBuffer.allocate(1024);
socketChannel.read(byteBuffer);
String msg = new String(byteBuffer.array());
System.out.println(msg);
}
}
}
}catch (IOException e){
e.printStackTrace();
}
}
public static void main(String[] args) {
final ChatRoomClient client = new ChatRoomClient();
new Thread(){
@Override
public void run(){
while (true){
client.readData();
try {
sleep(2000);
}catch (Exception e){
e.printStackTrace();
}
}
}
}.start();
Scanner scanner = new Scanner(System.in);
while (scanner.hasNextLine()){
String str = scanner.nextLine();
client.sendData(str);
}
}
}
执行结果
1)服务端启动监听
2)客户端登录
3)服务端接收到客户端信息
4)客户端退出