CLConnect 是客户端进入登录服后的第一条连接握手包。当前 Game.exe 与现役 /home/ubuntu/Game2 登录服 Lua 都能确认:它是一条固定 110 字节请求,包体由 net_provider、account、version、ip 四段组成。现役服务端收到后不会直接做账号认证或版本拦截,而是先缓存 version,再立即回 LCRetConnect,等待后续 CLAskLogin 继续登录链路。
包信息
| 项目 |
内容 |
| 封包 ID |
355 |
| 包名 |
CLConnect |
| 方向 |
CL 客户端 -> 登录服 |
| 包长 |
固定 110 字节 |
| 专用回包 |
LCRetConnect(ID 311) |
| 当前 Lua 协议定义 |
/home/ubuntu/Game2/services/login/packet.lua |
| 当前 Lua 处理入口 |
/home/ubuntu/Game2/services/login/logind.lua |
| 当前用途 |
建立登录服握手上下文,缓存客户端上报的版本串,并返回后续登录入口 |
当前 Game.exe 可直接确认:
GetPacketID() = 355;
GetPacketSize() = 110;
Read() = read_u32_net_provider + read_bytes_50_account + read_bytes_32_version + read_bytes_24_ip;
Write() = write_u32_net_provider + write_bytes_50_account + write_bytes_32_version + write_bytes_24_ip;
Execute() = 2;
包体结构
按当前 Game.exe 与现役登录服 packet.lua,包体结构如下:
| 偏移 |
长度 |
字段 |
类型 |
含义 |
0x00 |
0x04 |
net_provider |
uint32 |
网络线路/运营商线路标识;现役登录服未按此字段分流 |
0x04 |
0x32 |
account |
char[50] |
连接阶段账号串;当前登录认证主链不使用该字段 |
0x36 |
0x20 |
version |
char[32] |
客户端上报的版本串;现役登录服会先缓存到连接上下文 |
0x56 |
0x18 |
ip |
char[24] |
客户端自报 IP;现役登录服不把它当成真实来源地址 |
总长度为:
0x6E = 110 字节
account、version、ip 当前都是按定长原始字节串读取;现役 Lua 不会自动裁掉末尾补零。
当前实际行为
/home/ubuntu/Game2/services/login/logind.lua 的 server.message(fd, idx, packet) 收到 CLConnect 后,当前处理顺序非常直接:
- 把
packet.version 缓存到 connect_versions[fd]
- 构造
LCRetConnect
- 把
login_ip、wan_ip 都写成 server_conf.server_ip
- 把
login_port 写成当前登录服监听端口 port
- 从
handshake[fd] 解析出对端字符串地址里的端口,写入 wan_port
- 立即回包
LCRetConnect
这条包当前并不会直接触发账号认证,也不会在这里执行登录版本强校验。现役版本校验发生在下一条 CLAskLogin 阶段,登录服会拿 packet.uVersion 调用 is_login_version_valid(...),而 CLConnect.version 主要作为连接阶段缓存值,后续用于登录日志记录与排查辅助。
从现役 Lua 可确认的实际使用情况如下:
version:当前实际使用,会先缓存到 connect_versions[fd]
account:当前未进入现役认证主链,真正账号口令解析发生在 CLAskLogin
ip:包里虽然自报了地址,但登录服后续真正使用的是 server.connect(fd, addr) 阶段记录到 handshake[fd] 的 socket 对端地址
net_provider:当前未看到现役登录链路按它分流或做策略判断
这条握手缓存也是一次性的。现役登录服会在两种时机清理 connect_versions[fd]:
- 收到
CLAskLogin 并进入登录处理后
- 连接断开
server.disconnect(fd) 时
服务端落点
- 协议定义:
/home/ubuntu/Game2/services/login/packet.lua
- 登录包处理:
/home/ubuntu/Game2/services/login/logind.lua
- 连接建立与地址缓存:
/home/ubuntu/Game2/services/login/logind.lua
当前直接相关的现役状态变量包括:
handshake[fd]:记录 server.connect(fd, addr) 阶段捕获的真实对端地址字符串
connect_versions[fd]:记录 CLConnect.version
关键代码
Game.exe 的当前包体读写顺序可概括为:
read net_provider(u32);
read account[50];
read version[32];
read ip[24];
现役 Lua 的协议读取与握手处理可概括为:
self.net_provider = stream:readuint()
self.account = stream:read(0x32)
self.version = stream:read(0x20)
self.ip = stream:read(0x18)
if packet.xy_id == packet_def.XYID_CLCONNECT then
connect_versions[fd] = packet.version
ret = packet_def.LCRetConnect.new()
ret.login_ip = server_conf.server_ip
ret.login_port = port
ret.wan_ip = server_conf.server_ip
local _, client_port = string.match(handshake[fd], "(.+):(.+)")
ret.wan_port = client_port
loginservice.send(fd, idx, ret)
end
登录服后续真正使用连接层地址和版本缓存的位置是:
local ip = string.match(handshake[fd], "(.+):(.+)")
local connect_version = connect_versions[fd]
handshake[fd] = nil
connect_versions[fd] = nil
结论
CLConnect 在当前版本中是活跃的登录握手包,但职责比较单纯:它负责把客户端的线路标识、账号串、版本串和自报 IP 送到登录服,并换回 LCRetConnect。从现役实现看,真正进入当前业务主链的只有 version,而且它也只是先缓存,供后续 CLAskLogin 阶段记录日志和辅助排查。
更关键的现役实现特征有两点:一是登录版本强校验并不发生在 CLConnect,而是在下一条 CLAskLogin;二是包体中的 ip 不是最终依据,登录服实际信任的是 socket 层握手时记录的 handshake[fd]。因此,把 CLConnect 理解为“登录服连接握手与上下文预热包”会比把它理解成“正式登录认证包”更准确。