[Netty实践] 简单聊天实现(三):client部分

发布时间:2023年12月27日

目录

???????? 一、介绍

二、结构

三、依赖

四、Response消息处理Handler实现

五、ClientChannelInitializer实现

六、ChatClient实现

七、启动器下启动ChatClient

八、编写登录、私聊、群聊接口

九、测试登录、私聊、群聊


一、介绍

本章节主要讲第三部分,涉及客户端的实现,主要包括客户端进行登录、私聊、群聊。

如果你还没有看过第一部分,那么请通过下面这篇文章进行学习:

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
本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。