com.iohao.game.external.client.join.TcpClientStartup Maven / Gradle / Ivy
/*
* ioGame
* Copyright (C) 2021 - present 渔民小镇 ([email protected]、[email protected]) . All Rights Reserved.
* # iohao.com . 渔民小镇
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as
* published by the Free Software Foundation, either version 3 of the
* License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see .
*/
package com.iohao.game.external.client.join;
import com.iohao.game.common.consts.IoGameLogName;
import com.iohao.game.external.client.ClientConnectOption;
import com.iohao.game.external.client.join.handler.ClientMessageHandler;
import com.iohao.game.external.client.user.ClientUser;
import com.iohao.game.external.client.user.ClientUserChannel;
import io.netty.bootstrap.Bootstrap;
import io.netty.channel.*;
import io.netty.channel.nio.NioEventLoopGroup;
import io.netty.channel.socket.SocketChannel;
import io.netty.channel.socket.nio.NioSocketChannel;
import io.netty.handler.codec.LengthFieldBasedFrameDecoder;
import lombok.extern.slf4j.Slf4j;
import java.net.InetSocketAddress;
/**
* @author 渔民小镇
* @date 2023-07-05
*/
@Slf4j(topic = IoGameLogName.CommonStdout)
class TcpClientStartup implements ClientConnect {
static int PACKAGE_MAX_SIZE = 1024 * 1024;
@Override
public void connect(ClientConnectOption option) {
ClientUser clientUser = option.getClientUser();
ClientMessageHandler clientMessageHandler = new ClientMessageHandler(clientUser);
EventLoopGroup group = new NioEventLoopGroup();
var bootstrap = new Bootstrap();
bootstrap.group(group)
.channel(NioSocketChannel.class)
.option(ChannelOption.TCP_NODELAY, true)
.handler(new ChannelInitializer() {
@Override
protected void initChannel(SocketChannel ch) {
// 编排网关业务
ChannelPipeline pipeline = ch.pipeline();
// 数据包长度 = 长度域的值 + lengthFieldOffset + lengthFieldLength + lengthAdjustment。
pipeline.addLast(new LengthFieldBasedFrameDecoder(PACKAGE_MAX_SIZE,
// 长度字段的偏移量, 从 0 开始
0,
// 字段的长度, 如果使用的是 short ,占用2位;(消息头用的 byteBuf.writeShort 来记录长度的)
// 字段的长度, 如果使用的是 int ,占用4位;(消息头用的 byteBuf.writeInt 来记录长度的)
4,
// 要添加到长度字段值的补偿值:长度调整值 = 内容字段偏移量 - 长度字段偏移量 - 长度字段的字节数
0,
// 跳过的初始字节数: 跳过0位; (跳过消息头的 0 位长度)
0));
// 编解码
pipeline.addLast("codec", new ClientTcpExternalCodec());
pipeline.addLast(clientMessageHandler);
}
});
InetSocketAddress address = option.getSocketAddress();
String hostName = address.getHostName();
int port = address.getPort();
final ChannelFuture channelFuture = bootstrap.connect(hostName, port);
try {
Channel channel = channelFuture.sync().channel();
ClientUserChannel userChannel = clientUser.getClientUserChannel();
userChannel.setClientChannel(channel::writeAndFlush);
userChannel.setCloseChannel(channel::close);
clientUser.getClientUserInputCommands().start();
channel.closeFuture().await();
} catch (InterruptedException e) {
log.error(e.getMessage(), e);
} finally {
group.shutdownGracefully();
}
}
}