1.客户端
start() {
// init logic
this.label.string = this.text;
let socket = new WebSocket("ws://localhost:6080/ws"); // H5标准,底层做好了;
socket.binaryType = "arraybuffer";
socket.onopen = function () {
cc.log("connect succ!!!");
let content = "";
for (let i = 0; i < 1; i++) {
content += "你好啊,朋友";
}
this.sendMessage(socket, OPCodeConfig.OP_CHAT_BROADCAST, {
content: content,
})
}.bind(this);
socket.onmessage = function (event) {
let obj = JSON.parse(event.data);
cc.log(obj);
}.bind(this);
}
sendMessage(socket, msgCode, params) {
let obj = {
msgCode: msgCode,
params: params,
};
let msg = JSON.stringify(obj);
socket.send(msg);
}
2.服务器
package gamebase;
import io.netty.bootstrap.ServerBootstrap;
import io.netty.channel.ChannelFuture;
import io.netty.channel.ChannelInitializer;
import io.netty.channel.EventLoopGroup;
import io.netty.channel.nio.NioEventLoopGroup;
import io.netty.channel.socket.SocketChannel;
import io.netty.channel.socket.nio.NioServerSocketChannel;
import io.netty.handler.codec.http.HttpObjectAggregator;
import io.netty.handler.codec.http.HttpServerCodec;
import io.netty.handler.codec.http.websocketx.WebSocketServerProtocolHandler;
import io.netty.handler.stream.ChunkedWriteHandler;
import vega.gameserver.GSIOHandler;
import vega.gameserver.GSServer;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
public class WsManager {
private static Logger logger = LoggerFactory.getLogger(GSServer.class);
private static EventLoopGroup bossGroup;
private static EventLoopGroup workerGroup;
public static void start() {
bossGroup = new NioEventLoopGroup(1);
workerGroup = new NioEventLoopGroup();
ServerBootstrap b = new ServerBootstrap();
b.group(bossGroup, workerGroup);
b.channel(NioServerSocketChannel.class);
b.childHandler(new ChannelInitializer<SocketChannel>() {
@Override
protected void initChannel(SocketChannel ch) throws Exception {
ch.pipeline().addLast(
new HttpServerCodec(),
new ChunkedWriteHandler(),
new HttpObjectAggregator(65536),
new WebSocketServerProtocolHandler("/ws"),
new GSIOHandler()
);
}
});
try {
int port = 6080;
ChannelFuture f = b.bind(port).sync();
if (f.isSuccess()) {
logger.info("ws server start, listen port:{}", port);
}
// f.channel().closeFuture().sync();
} catch (Exception e) {
logger.error("", e);
}
}
public static void stop() {
bossGroup.shutdownGracefully();
workerGroup.shutdownGracefully();
logger.info("game server shutdown!!!");
}
}
package vega.gameserver;
import com.alibaba.fastjson.JSONObject;
import gamebase.BusinessThreadManager;
import gamebase.processor.CmdExecutor;
import gamebase.processor.ProcessorManager;
import io.netty.channel.ChannelHandlerContext;
import io.netty.channel.SimpleChannelInboundHandler;
import io.netty.handler.codec.http.websocketx.TextWebSocketFrame;
import io.netty.util.internal.StringUtil;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.lang.reflect.Method;
public class GSIOHandler extends SimpleChannelInboundHandler<TextWebSocketFrame> {
private static Logger logger = LoggerFactory.getLogger(GSIOHandler.class);
@Override
protected void channelRead0(ChannelHandlerContext ctx, TextWebSocketFrame textWebSocketFrame) throws Exception {
try {
JSONObject jo = JSONObject.parseObject(textWebSocketFrame.text());
// 命令号(找那个method)
int msgCode = jo.getInteger("msgCode");
// 消息体
JSONObject params = jo.getJSONObject("params");
CmdExecutor cmdExecutor = ProcessorManager.getCmdExecutor(msgCode);
if (cmdExecutor == null) {
throw new RuntimeException("请求参数找不到msgCode:" + msgCode);
}
Object handler = cmdExecutor.getHandler();
Method method = cmdExecutor.getMethod();
boolean isLoginInterface = cmdExecutor.isLoginInterface();
// Object[] paramArr = new Object[]{role, params};
// if (!cmdExecutor.isLoginInterface()) {
// if (StringUtil.isNullOrEmpty(role.getRid())) {
// throw new RuntimeException("不是登陆接口必须含有rid:" + msgCode);
// }
// }
//
// Object ret = method.invoke(handler, paramArr);
// if (ret != null) {
// return (JSONObject) ret;
// }
//
// return null;
BusinessThreadManager.runTask(1, () -> {
try {
JSONObject retMsg = ProcessorManager.processMessage(null, msgCode, params);
// 将处理结果发给客户端
if (retMsg != null) {
ctx.writeAndFlush(new TextWebSocketFrame(retMsg.toJSONString()));
}
} catch (Exception e) {
logger.error("", e);
}
});
} catch (Exception e) {
logger.error("", e);
}
}
@Override
public void channelActive(ChannelHandlerContext ctx) throws Exception {
}
@Override
public void channelInactive(ChannelHandlerContext ctx) throws Exception {
}
@Override
public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) throws Exception {
System.out.println("客户端异常:" + ctx.channel().remoteAddress());
cause.printStackTrace();
ctx.close();
}
}
package gamebase.processor;
import com.alibaba.fastjson.JSONObject;
import io.netty.util.internal.ObjectUtil;
import io.netty.util.internal.StringUtil;
import org.reflections.Reflections;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import vega.gameserver.model.Role;
import java.lang.reflect.Method;
import java.util.HashMap;
import java.util.Map;
import java.util.Set;
public class ProcessorManager {
private static Logger logger = LoggerFactory.getLogger(ProcessorManager.class);
private static Map<Integer, CmdExecutor> interfaceMap = new HashMap<>();
public static void init(String packageName) {
Reflections reflections = new Reflections(packageName);
Set<Class<?>> httpHandlerSet = reflections.getTypesAnnotatedWith(Processor.class);
try {
for (Class<?> clazz : httpHandlerSet) {
Object handler = clazz.newInstance();
Processor processor = clazz.getAnnotation(Processor.class);
Method[] methods = clazz.getDeclaredMethods();
for (Method method : methods) {
Interface interfaceMethod = method.getAnnotation(Interface.class);
if (interfaceMethod != null) {
int msgCode = interfaceMethod.msgCode();
interfaceMap.put(msgCode, CmdExecutor.valueOf(method, method.getParameterTypes(), handler, interfaceMethod.loginInterface()));
}
}
}
} catch (Exception e) {
logger.error("", e);
}
}
public static CmdExecutor getCmdExecutor(int msgCode) {
return interfaceMap.get(msgCode);
}
public static JSONObject processMessage(Role role, int msgCode, JSONObject params) throws Exception {
CmdExecutor cmdExecutor = interfaceMap.get(msgCode);
if (cmdExecutor == null) {
throw new RuntimeException("请求参数找不到msgCode:" + msgCode);
}
Object handler = cmdExecutor.getHandler();
Object[] paramArr = new Object[]{role, params};
Method method = cmdExecutor.getMethod();
if (!cmdExecutor.isLoginInterface()) {
if (StringUtil.isNullOrEmpty(role.getRid())) {
throw new RuntimeException("不是登陆接口必须含有rid:" + msgCode);
}
}
Object ret = method.invoke(handler, paramArr);
if (ret != null) {
return (JSONObject) ret;
}
return null;
}
}