Skip to content

Commit

Permalink
netty聊天服务器
Browse files Browse the repository at this point in the history
  • Loading branch information
liming committed Mar 30, 2023
1 parent cfc7614 commit 8c1915d
Show file tree
Hide file tree
Showing 37 changed files with 10,321 additions and 0 deletions.
57 changes: 57 additions & 0 deletions Netty-客户端和服务端聊天功能.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,57 @@
serer
配置类
1.设置parent,children EventLoop
2.ServerBootstrap 绑定parent,children
3.设置端口,设置参数,设置channel类型
4.设置children 初始化内容
4.1 protobuf 解密类 继承channelinbound
标记一下读的位置(当未完整读取时,可以重复读)
读取魔数
读取版本
读取字节中的长度(后续要读取多少个字节的数据),
没有长度或者长度为0时 -> 主动关闭连接
长度不够等待下次读取 -> resetMark标记
判断是否是堆内存还是直接内存
使用byte数组读取 buff.readBytes()...
读取成功 把protobuf 解析成对象。
super.channel... 继续调用下一个channelInBound
4.2 loginRequestHandle 登录请求处理类 ,继承channelinbound
channelActive方法,
写入日志获取到连接,但是没有登录
channelRead方法
如果不是protobuf Message对象。那么继续调用super.channelRead方法
此时,字节流已经被转换成了Message对象
判断处理类型,如果不是登录类型,那么继续调用super.channelRead方法
获取Mesage里面的用户信息。
进行登录(使用future 线程),创建一个Session对象 与channel绑定
1.获取protobuf 对象里面的seqId(方便客户端在多线程处理时,可以通过seqId做某些事情)
2.把请求对象信息转换成User对象
3.检查用户
判断用户是否已经登录(判断标准是用户id是否与"数据库"的用户id一致等),不一致就给客户端返回失败结果
登录成功
session与用户信息做绑定
构建回复报文
登录失败
future->结果 。
成功
绑定一个聊天channelHandle
绑定一个心跳channelHandle
移除这个登录类解码处理器(后续不在需要级)
失败或者异常
关闭channel
如果SessionMap集合中包含这个用户信息。将他下线!
4.2 protobufEncode 编码类
1.获取到要返回的butff
2.构建返回字段 魔术,版本号,bytebuff 长度
3.填充返回的butff
4.写入channel
4.3 一个异常处理类,专门处理channelInBound异常 重写 exceptionCaught方法
仅仅记录一下日志
5.开始同步绑定,并获取到channelFuture对象
6.获取到channelFuture的channel. closeFuture事件, 同步
final
parent,children优雅关闭
1 change: 1 addition & 0 deletions Netty-概念.md
Original file line number Diff line number Diff line change
Expand Up @@ -76,3 +76,4 @@ Netty 还有`slice`切片实现类似零拷贝的功能。



[透过现象看 Java AIO 的本质](https://xie.infoq.cn/article/3740980e285510995cd206143)
33 changes: 33 additions & 0 deletions netty-model/netty-chat/nett-chat-server/.gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
HELP.md
target/
!.mvn/wrapper/maven-wrapper.jar
!**/src/main/**/target/
!**/src/test/**/target/

### STS ###
.apt_generated
.classpath
.factorypath
.project
.settings
.springBeans
.sts4-cache

### IntelliJ IDEA ###
.idea
*.iws
*.iml
*.ipr

### NetBeans ###
/nbproject/private/
/nbbuild/
/dist/
/nbdist/
/.nb-gradle/
build/
!**/src/main/**/build/
!**/src/test/**/build/

### VS Code ###
.vscode/
90 changes: 90 additions & 0 deletions netty-model/netty-chat/nett-chat-server/pom.xml
Original file line number Diff line number Diff line change
@@ -0,0 +1,90 @@
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>3.0.5</version>
<relativePath/> <!-- lookup parent from repository -->
</parent>
<groupId>com.example</groupId>
<artifactId>nett-chat-server</artifactId>
<version>0.0.1-SNAPSHOT</version>
<name>nett-chat-server</name>
<description>nett-chat-server</description>
<properties>
<java.version>17</java.version>
</properties>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter</artifactId>
</dependency>

<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-configuration-processor</artifactId>
<optional>true</optional>
</dependency>

<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>

<!-- https://mvnrepository.com/artifact/org.slf4j/slf4j-api -->
<dependency>
<groupId>org.slf4j</groupId>
<artifactId>slf4j-api</artifactId>
<version>1.7.30</version>
</dependency>
<!-- https://mvnrepository.com/artifact/org.slf4j/slf4j-log4j12 -->
<dependency>
<groupId>org.slf4j</groupId>
<artifactId>slf4j-log4j12</artifactId>
<version>1.7.30</version>
<!-- <scope>test</scope>-->
</dependency>
<!--引入fastjson -->
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>fastjson</artifactId>
<version>1.2.83</version>
</dependency>
<dependency>
<groupId>io.netty</groupId>
<artifactId>netty-all</artifactId>
<version>4.1.6.Final</version>
</dependency>

<dependency>
<groupId>com.example</groupId>
<artifactId>netty-chat-common</artifactId>
<version>1.0-SNAPSHOT</version>
</dependency>
</dependencies>

<build>
<plugins>
<plugin>
<groupId>org.graalvm.buildtools</groupId>
<artifactId>native-maven-plugin</artifactId>
</plugin>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
<configuration>
<excludes>
<exclude>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
</exclude>
</excludes>
</configuration>
</plugin>
</plugins>
</build>

</project>
Original file line number Diff line number Diff line change
@@ -0,0 +1,61 @@
/**
* @Project:
* @Author: leegoo
* @Date: 2023年03月25日
*/
package com.example.nettychatserver;

import com.example.nettychatserver.inbound.ProtobuffChannelHandler;
import com.example.nettychatserver.inbound.RequestChannelHandler;
import io.netty.bootstrap.ServerBootstrap;
import io.netty.buffer.PooledByteBufAllocator;
import io.netty.channel.ChannelFuture;
import io.netty.channel.ChannelInitializer;
import io.netty.channel.ChannelOption;
import io.netty.channel.ChannelPipeline;
import io.netty.channel.nio.NioEventLoop;
import io.netty.channel.nio.NioEventLoopGroup;
import io.netty.channel.socket.SocketChannel;
import io.netty.channel.socket.nio.NioServerSocketChannel;
import org.springframework.beans.factory.config.ConfigurableBeanFactory;
import org.springframework.context.annotation.Scope;
import org.springframework.stereotype.Service;

/**
* ClassName: ChatServer
* @Description:
* @author leegoo
* @date 2023年03月25日
*/
@Service
@Scope(ConfigurableBeanFactory.SCOPE_PROTOTYPE)
public class ChatServer {
private ServerBootstrap serverBootstrap = new ServerBootstrap();

public void runServe() {
NioEventLoopGroup parent = new NioEventLoopGroup();
NioEventLoopGroup children = new NioEventLoopGroup();
serverBootstrap.group(parent,children);
try {
serverBootstrap.option(ChannelOption.ALLOCATOR, PooledByteBufAllocator.DEFAULT);
serverBootstrap.childOption(ChannelOption.ALLOCATOR, PooledByteBufAllocator.DEFAULT);
serverBootstrap.localAddress(18899);
serverBootstrap.channel(NioServerSocketChannel.class);
serverBootstrap.childHandler(new ChannelInitializer<SocketChannel>() {
@Override
protected void initChannel(SocketChannel ch) throws Exception {
ChannelPipeline pipeline = ch.pipeline();
pipeline.addLast(new ProtobuffChannelHandler());
pipeline.addLast(new RequestChannelHandler());
}
});
ChannelFuture channelFuture = serverBootstrap.bind().sync();
ChannelFuture future = channelFuture.channel().closeFuture().sync();
} catch (InterruptedException e) {
throw new RuntimeException(e);
} finally {
parent.shutdownGracefully();
children.shutdownGracefully();
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
package com.example.nettychatserver;

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;

@SpringBootApplication(scanBasePackages = "com.example.nettychatserver")
public class NettChatServerApplication {

public static void main(String[] args) {
SpringApplication.run(NettChatServerApplication.class, args);
}

}
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
/**
* @Project:
* @Author: leegoo
* @Date: 2023年03月29日
*/
package com.example.nettychatserver.async;

import lombok.SneakyThrows;

import java.util.concurrent.ArrayBlockingQueue;
import java.util.concurrent.Future;
import java.util.concurrent.ThreadPoolExecutor;
import java.util.concurrent.TimeUnit;

/**
* ClassName: AsyncCallBack
*
* @author leegoo
* @Description:
* @date 2023年03月29日
*/
public class AsyncCallBack {

private static final ThreadPoolExecutor THREAD_POOL_EXECUTOR = new ThreadPoolExecutor(
1, 1, 0L, TimeUnit.MILLISECONDS, new ArrayBlockingQueue<>(1000)
);


@SneakyThrows
public static void run (CallBack callBack){
Future<?> future = THREAD_POOL_EXECUTOR.submit(new Runnable() {
@Override
public void run() {
callBack.execute();
}
});
Boolean result = (Boolean) future.get(10, TimeUnit.SECONDS);
if (result){
callBack.onSuccess();
}else {
callBack.onFail();
}
}

}
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
/**
* @Project:
* @Author: leegoo
* @Date: 2023年03月29日
*/
package com.example.nettychatserver.async;


/**
* ClassName: CallBack
* @Description:
* @author leegoo
* @date 2023年03月29日
*/
public interface CallBack {
boolean execute();
boolean onSuccess();
boolean onFail();
}
Loading

0 comments on commit 8c1915d

Please sign in to comment.