尚硅谷2019年Netty教程 netty 群聊系统 ----目标netty—step5.02
*https://blog.csdn.net/wei198621/article/details/108764920需要与 下面的进行对比学习,就可以知道 netty的好了
尚硅谷2019年Netty教程 NIO 群聊系统 ----目标netty—step4.01
https://blog.csdn.net/wei198621/article/details/108700129
https://www.bilibili.com/video/BV1jK4y1s7GV?p=29
https://www.bilibili.com/video/BV1jK4y1s7GV?p=30
https://www.bilibili.com/video/BV1jK4y1s7GV?p=31
https://www.bilibili.com/video/BV1jK4y1s7GV?p=32
尚硅谷2019年Netty教程 NIO 群聊系统 一共分为4讲
29,30 ----server端编码
31,32 ----client编码
32 的后半部分是对 之前代码的修改,主要有两点
part1 服务端 GroupChartServer
// 别忘将客户端 置为 非阻塞
public void listen(){
if(key.isAcceptable()){
sc.configureBlocking(false) ; //设置客户端非阻塞
}
part2 客户端 GroupChatClient
//读取从服务器 回复的消息 别忘删除 SelectionKey
public void readInfo(){
iterator.remove(); //读取后,别忘了删除当前 selectionKey
}
服务端 代码
package com.atguigu.groupChat;
import java.io.IOException;
import java.net.InetSocketAddress;
import java.nio.ByteBuffer;
import java.nio.channels.Channel;
import java.nio.channels.SelectionKey;
import java.nio.channels.Selector;
import java.nio.channels.ServerSocketChannel;
import java.nio.channels.SocketChannel;
import java.util.Iterator;
/**
* Author: tz_wl
* Date: 2020/9/20 21:41
* Content:
*
* 1.1 服务器启动并监听 * 端口
1.2 打印上线信息
1.2 打印数据信息
1.3 打印转发消息
1.4 打印离线消息
*
*
*/
public class GroupChartServer {
//01 定义 需要都用到的变量
private Selector selector ;
private ServerSocketChannel listenChannel;
private static final int PORT = 8095;
//02 构造函数 初始化 注册 serverSocketChannel 到 Selector
public GroupChartServer() throws Exception{
try {
selector = Selector.open();
listenChannel = ServerSocketChannel.open();
listenChannel.socket().bind(new InetSocketAddress(PORT));
listenChannel.configureBlocking(false);
listenChannel.register(selector , SelectionKey.OP_ACCEPT);
} catch (IOException e) {
e.printStackTrace();
}
}
// 03 服务端 监听函数
// isAcceptable 有客户端连接上来 打印 ***客户端连接到服务器了
// isReadable 客户端发送的数据 放到单独方法 readData 中处理
public void listen(){
try{
System.out.println("服务端已经启动 ... ");
while(true){
int count= selector.select(2000);
if(count>0){
Iterator<SelectionKey> iterator = selector.selectedKeys().iterator();
while(iterator.hasNext()){
SelectionKey key= iterator.next();
if(key.isAcceptable()){
SocketChannel sc = listenChannel.accept();
sc.configureBlocking(false) ; //设置客户端非阻塞
sc.register(selector,SelectionKey.OP_READ);
//提示 某某客户端 上线了
System.out.println(sc.getRemoteAddress()+"上线");
}
if(key.isReadable()){
// 专门方法处理读事件
readData(key);
}
iterator.remove();// 注意要删除 别忘记
}
}else{
//System.out.println("waiting ...");
}
}
}catch(IOException e){
e.printStackTrace();
}finally{
}
}
//读取客户端消息
// 读到数据了 提示 有客户端发来消息
// 其他客户端转发 消息
// 有客户端离线了,提示 离线了
private void readData(SelectionKey key){
SocketChannel channel = null;
try{
channel= (SocketChannel) key.channel();
ByteBuffer buffer=ByteBuffer.allocate(1024);
int count = channel.read(buffer);
if(count>0){
String msg = new String(buffer.array());
System.out.println("from 客户端 msg is:" + msg );
// 向 其他客户端转发消息 专用方法
sendInfoToOtherClients(msg,channel);
}
} catch (Exception e){
try{
System.out.println(channel.getRemoteAddress()+"离线了");
key.cancel(); //取消注册
channel.close(); //关闭通道
}catch(IOException e2){
}
}
}
//转发消息给其他客户
private void sendInfoToOtherClients(String msg, SocketChannel self) throws IOException {
System.out.println("服务器转发消息中... ");
//遍历 所有 注册到 selector 上面的socketChannel - self
for(SelectionKey key: selector.keys()){
Channel targetChannel = key.channel();
//如果就一个服务器 只要 targetChannel != self 就可以
//考虑到多台服务器 if(targetChannel instanceof SocketChannel )
if(targetChannel instanceof SocketChannel && targetChannel != self)
{
SocketChannel dest = (SocketChannel) targetChannel;
ByteBuffer buffer = ByteBuffer.wrap(msg.getBytes());
dest.write(buffer);
}
}
}
public static void main(String[] args) throws Exception {
GroupChartServer groupChatServer = new GroupChartServer();
groupChatServer.listen();
}
}
客户端代码
package com.atguigu.groupChat;
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;
/**
* Author: tz_wl
* Date: 2020/9/20 21:41
* Content:
*
* //客户端
//链接服务器
//接收消息
//发送消息
*/
public class GroupChatClient {
//定义 用到的变量
private final String HOST = "127.0.0.1";
private final int PORT = 8095;
private Selector selector;
private SocketChannel socketChannel;
private String userName;
//构造函数
public GroupChatClient() throws IOException {
selector =Selector.open();
socketChannel = SocketChannel.open(new InetSocketAddress("127.0.0.1", PORT));
socketChannel.configureBlocking(false);
socketChannel.register(selector, SelectionKey.OP_READ);
userName = socketChannel.getLocalAddress().toString().substring(1);
System.out.println(userName+ " is Starting ...");
}
//向服务器发送消息
public void sendInfo(String info) {
info = userName + "说:" + info;
try {
socketChannel.write(ByteBuffer.wrap(info.getBytes()));
} catch (IOException e) {
e.printStackTrace();
}
}
//读取从服务器 回复的消息
public void readInfo(){
try{
int readChannels = selector.select();
if(readChannels > 0){
Iterator<SelectionKey> iterator =selector.selectedKeys().iterator();
while(iterator.hasNext()){
SelectionKey key = iterator.next();
//此处client只有 readable 没有 acceptable
if(key.isReadable()){
SocketChannel sc = (SocketChannel)key.channel();
ByteBuffer buffer =ByteBuffer.allocate(1034);
sc.read(buffer);
//
String msg = new String (buffer.array());
System.out.println(msg);
}
iterator.remove(); //读取后,别忘了删除当前 selectionKey
}
}else{
System.out.println("没有可用通道");
}
}catch(Exception e){
}
}
// 本线程 监听 System.in nextLine 发送数据给服务端
// // //启动一个线程 每隔 3 秒 ,读取从服务器发送的数据
public static void main(String[] args) throws Exception {
GroupChatClient chatClient = new GroupChatClient();
//启动一个线程 每隔 3 秒 ,读取从服务器发送的数据
new Thread() {
public void run() {
while (true) {
chatClient.readInfo();
try {
Thread.currentThread().sleep(3000);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}.start();
// 发送数据给服务端
Scanner scanner = new Scanner(System.in);
while (scanner.hasNextLine()) {
String s = scanner.nextLine();
chatClient.sendInfo(s);
}
}
}
版权声明:本文为wei198621原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接和本声明。