1. 为命令CMD的枚举增加两个成员:
enum CMD {
CMD_LOGIN,
CMD_LOGIN_RESULT,
CMD_LOGOUT,
CMD_LOGOUT_RESULT,
CMD_ERROR
};
2. 使用继承的方式,令Login/Logout/LoginResult/LogoutResult结构体继承于DataHeader,并在Login的构造函数里为cmd和dataLength赋值,这样就不必在定义消息时将DataHeader单独写一遍,也可以避免出错。
//包头
struct DataHeader {
short dataLength; //数据长度
short cmd; //命令
};
//包体 DataPackage
struct Login : public DataHeader
{
Login() {
dataLength = sizeof(Login);
cmd = CMD_LOGIN;
}
char UserName[32];
char PassWord[32];
};
struct LoginResult : public DataHeader
{
LoginResult() {
dataLength = sizeof(LoginResult);
cmd = CMD_LOGIN;
result = 0;
}
int result;
};
struct LogOut : public DataHeader
{
LogOut() {
dataLength = sizeof(LogOut);
cmd = CMD_LOGOUT;
}
char UserName[32];
};
struct LogoutResult: public DataHeader
{
LogoutResult() {
dataLength = sizeof(LogoutResult);
cmd = CMD_LOGOUT;
result = 0;
}
int result;
};
3. 修改服务器端消息的解析方式
switch (header.cmd) {
case CMD_LOGIN:
{
Login login = {};
//接收客户端的登陆信息,这里要注意除去headerd部分,因此要加上数据偏移,并且读取范围要减去header的大小
recv(_cSock, (char*)&login + sizeof(DataHeader), sizeof(Login) - sizeof(DataHeader), 0);
printf("receive message: CMD_LOGIN, data length:%d, username:%s, password: %s\n", login.dataLength, login.UserName, login.PassWord); //提示收到命令
//假设用户输入正确(这里忽略用户名和密码是否正确的验证过程)
LoginResult inret;
//7. 向客户端发送数据send
send(_cSock, (char*)&inret, sizeof(LoginResult), 0); //向客户端发送登陆结果
}
break;
case CMD_LOGOUT:
{
LogOut logout = {};
//接收客户端的登出信息,这里要注意除去headerd部分,因此要加上数据偏移,并且读取范围要减去header的大小
recv(_cSock, (char*)&logout + sizeof(DataHeader), sizeof(LogOut) - sizeof(DataHeader), 0);
printf("receive message: CMD_LOGIN, data length:%d, username:%s\n", logout.dataLength, logout.UserName);
LogoutResult outret;
//7. 向客户端发送数据send
send(_cSock, (char*)&outret, sizeof(LogoutResult), 0);
}
break;
default:
header.cmd = CMD_ERROR;
header.dataLength = 0;
send(_cSock, (char*)&header, sizeof(DataHeader), 0);
break;
}
4. 修改客户端的消息处理方式
while (true) {
//3. 用户输入请求命令
scanf("%s", cmdBuf);
//4. 处理请求命令
if (0 == strcmp(cmdBuf, "exit")) {
printf("receive quit message!");
break;
} else if (0 == strcmp(cmdBuf, "login")){
//5. 向服务器端发送请求
Login login;
strcpy(login.UserName, "liu");
strcpy(login.PassWord, "1234");
send(_sock, (const char*)&login, sizeof(Login), 0);
//6. 接收服务器返回数据
LoginResult loginRet = {};
recv(_sock, (char*)&loginRet, sizeof(LoginResult), 0);
printf("LoginResult: %d\n", loginRet.result);
} else if (0 == strcmp(cmdBuf, "logout")) {
//5. 向服务器端发送请求
LogOut logout;
strcpy(logout.UserName, "liu");
send(_sock, (const char*)&logout, sizeof(LogOut), 0);
//6. 接收服务器返回数据
LogoutResult logoutRet = {};
recv(_sock, (char*)&logoutRet, sizeof(LogoutResult), 0);
printf("LogoutResult: %d\n", logoutRet.result);
} else {
printf("unsupported command!");
}
}
5. 实验结果