[Netty实践] 简单聊天实现(三):client部分
2023-12-27 10:29:31
    		目录
???????? 一、介绍
一、介绍
本章节主要讲第三部分,涉及客户端的实现,主要包括客户端进行登录、私聊、群聊。
如果你还没有看过第一部分,那么请通过下面这篇文章进行学习:
https://blog.csdn.net/Staba/article/details/135057482
如果你还没有看过第二部分,那么请通过下面这篇文章进行学习:
https://blog.csdn.net/Staba/article/details/135061442
二、结构

三、依赖
此处为了节省麻烦,通过http接口调用去进行登录、发送私聊消息、发送群聊消息,所以引入了spring-boot-web-starter
<dependencies>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
            <version>2.3.10.RELEASE</version>
        </dependency>
        
        <dependency>
            <groupId>io.netty</groupId>
            <artifactId>netty-all</artifactId>
            <version>4.1.101.Final</version>
        </dependency>
        <dependency>
            <groupId>org.example</groupId>
            <artifactId>chat-common</artifactId>
            <version>1.0-SNAPSHOT</version>
        </dependency>
    </dependencies>四、Response消息处理Handler实现
?1、BaseHandler,所有Handler的父类
public abstract class BaseHandler<T> extends SimpleChannelInboundHandler<T> {
    @Override
    public void channelActive(ChannelHandlerContext ctx) throws Exception {
        System.out.println("客户端进行连接, channel: " + ctx.channel());
    }
    @Override
    public void channelInactive(ChannelHandlerContext ctx) throws Exception {
        System.out.println("客户端断开连接, channel: " + ctx.channel());
        super.channelInactive(ctx);
    }
    @Override
    public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) throws Exception {
        System.out.println("出现异常断开, channel: " + ctx.channel());
        cause.printStackTrace();
        // todo, 清除相关数据
    }
}2、LoginResponseHandler,用于接收登录返回消息
public class LoginResponseHandler extends BaseHandler<LoginResponse> {
    @Override
    protected void channelRead0(ChannelHandlerContext ctx, LoginResponse msg) throws Exception {
        System.out.println("[LoginResponseHandler]读取到服务端消息, channel: " + ctx.channel());
        System.out.println("消息是: " + msg);
    }
}3、SingleMessageResponseHandler,用于接收单聊消息
public class SingleMessageResponseHandler extends BaseHandler<SingleMessageResponse> {
    @Override
    protected void channelRead0(ChannelHandlerContext ctx, SingleMessageResponse msg) throws Exception {
        System.out.println("[SingleMessageResponseHandler]读取到服务端消息, channel: " + ctx.channel());
        System.out.println("消息是: " + msg);
    }
}
4、GroupMessageResponseHandler,用于接收群聊消息
public class GroupMessageResponseHandler extends BaseHandler<GroupMessageResponse> {
    @Override
    protected void channelRead0(ChannelHandlerContext ctx, GroupMessageResponse msg) throws Exception {
        System.out.println("[GroupMessageResponseHandler]读取到服务端消息, channel: " + ctx.channel());
        System.out.println("消息是: " + msg);
    }
}五、ClientChannelInitializer实现
该类用于初始化Server与Client通信的Channel,需要将我们前面写的编解码器以及ResponseHandler添加进pipeline
public class ClientChannelInitializer extends ChannelInitializer<SocketChannel> {
    @Override
    protected void initChannel(SocketChannel socketChannel) throws Exception {
        ChannelPipeline pipeline = socketChannel.pipeline();
        pipeline.addLast(new MessageEncode());
        pipeline.addLast(new MessageDecode());
        pipeline.addLast(new LoginResponseHandler());
        pipeline.addLast(new SingleMessageResponseHandler());
        pipeline.addLast(new GroupMessageResponseHandler());
    }
}六、ChatClient实现
public class ChatClient {
    public Channel connect(String ip, Integer port) {
        EventLoopGroup workGroup = new NioEventLoopGroup();
        Channel channel = null;
        try{
            Bootstrap bootstrap = new Bootstrap();
            bootstrap.group(workGroup)
                    .channel(NioSocketChannel.class)
                    .option(ChannelOption.AUTO_READ, true)
                    .handler(new ClientChannelInitializer());
            // 阻塞,等待连接建立
            channel = bootstrap.connect(ip, port).sync().channel();
            System.out.println("chatClient 启动...");
        } catch (Exception e) {
            e.printStackTrace();
        }
        return channel;
    }
}七、启动器下启动ChatClient
@SpringBootApplication
public class ClientApplication {
    public static void main(String[] args) {
        SpringApplication.run(ClientApplication.class, args);
    }
    @Bean
    public Channel init(){
        return new ChatClient().connect("127.0.0.1", 8888);
    }
}八、编写登录、私聊、群聊接口
@RestController
public class ChatController {
    @Resource
    private Channel channel;
    private String username;
    @GetMapping("/login")
    public void login(String username) {
        this.username = username;
        LoginRequest loginRequest = new LoginRequest(username);
        channel.writeAndFlush(loginRequest);
    }
    @GetMapping("/send/single")
    public void sendSingleMessage(String sendTo, String content) {
        SingleMessageRequest singleMessageRequest = new SingleMessageRequest(this.username, sendTo, content);
        channel.writeAndFlush(singleMessageRequest);
    }
    @GetMapping("/send/group")
    public void sendGroupMessage(String group, String content) {
        GroupMessageRequest groupMessageRequest = new GroupMessageRequest(this.username, group, content);
        channel.writeAndFlush(groupMessageRequest);
    }
}九、测试登录、私聊、群聊
1、启动客户端
分别启动三个客户端,端口分别为8081、8082、8083
2、登录
分别调用一下http接口进行模拟登录
http://localhost:8081/login?username=001
http://localhost:8082/login?username=002
http://localhost:8083/login?username=003在各自客户端控制台看到以下输出即可:
[LoginResponseHandler]读取到服务端消息, channel: [id: 0xb7a9fb1b, L:/127.0.0.1:58376 - R:/127.0.0.1:8888]
消息是: LoginResponse(result=true, message=登录成功!)3、私聊
调用以下接口,模拟username为001的用户向002用户发送消息
http://localhost:8081/send/single?sendTo=002&content=nihao可以在端口为8082服务的控制台上看到如下信息,其他服务看不到即可:
[SingleMessageResponseHandler]读取到服务端消息, channel: [id: 0xfc720170, L:/127.0.0.1:58340 - R:/127.0.0.1:8888]
消息是: SingleMessageResponse(sendFrom=001, content=nihao)4、群聊
调用以下接口,模拟username为001的用户想group2的群组发送消息
http://localhost:8081/send/group?group=group2&content=nihao可以在端口为8082和8083服务的控制台上看到如下信息:
[GroupMessageResponseHandler]读取到服务端消息, channel: [id: 0xfc720170, L:/127.0.0.1:58340 - R:/127.0.0.1:8888]
消息是: GroupMessageResponse(sendFrom=001, group=group2, content=nihao)至此,一个简单的私聊,群聊实现完毕
    			文章来源:https://blog.csdn.net/Staba/article/details/135061661
本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。 如若内容造成侵权/违法违规/事实不符,请联系我的编程经验分享网邮箱:veading@qq.com进行投诉反馈,一经查实,立即删除!
    	本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。 如若内容造成侵权/违法违规/事实不符,请联系我的编程经验分享网邮箱:veading@qq.com进行投诉反馈,一经查实,立即删除!