(C++服务器学习笔记):网络数据报文的格式定义

网络数据报文的格式定义

  • 报文有两个部分,包头和包体,是网络消息的基本单元。
  • 包头:描述本次消息包的大小,描述数据的的作用。
  • 包体:数据
  • 下面数据定义,服务端与客户端共用。
enum CMD             //命令枚举
{
    CMD_LOGIN,
    CMD_LOGOUT,
    CMD_ERROR
};

//DataHeader
struct DataHeader      //数据包头
{
    short dataLength;
    short cmd;
};

//DataPackage
struct Login          //登录
{
    char UserName[32];
    char PassWord[32];
};
 
struct LoginResult    //登录结果
{
    int lgResult;
};

struct LogOut      //退出登录
{
    char UserName[32];
};


struct LogOutResult  //退出结果
{
    int lgOutResult;
};
  • 服务端数据处理
while (true)
{
    DataHeader dbHeader = {};
    //接收客户端数据
    int nLen = recv(sockAccpt, (char*)&dbHeader, sizeof(DataHeader), 0);
    if (nLen < 0)
    {
        printf("客户端已退出,任务结束\n");
        break;
    }
    printf("收到命令:%d ,数据长度: %d\n", dbHeader.cmd, dbHeader.dataLength);

    switch (dbHeader.cmd)
    {
    case CMD_LOGIN:
    {
        Login login = {};
        recv(sockAccpt, (char*)&login, sizeof(Login), 0);
        //忽略对用户密码进行判断
        LoginResult lgRet = { 0 };
        send(sockAccpt, (char*)&dbHeader, sizeof(DataHeader), 0);
        send(sockAccpt, (char*)&lgRet, sizeof(LoginResult), 0);
    }
    break;
    case CMD_LOGOUT:
    {
        LogOut logout = {};
        recv(sockAccpt, (char*)&logout, sizeof(LogOut), 0);
        //忽略对用户密码进行判断
        LogOutResult lgOutRet = { 1 };
        send(sockAccpt, (char*)&dbHeader, sizeof(DataHeader), 0);
        send(sockAccpt, (char*)&lgOutRet, sizeof(LogOutResult), 0);
    }
    break;
    default:
        dbHeader.cmd = CMD_ERROR;
        dbHeader.dataLength = 0;
        send(sockAccpt, (char*)&dbHeader, sizeof(DataHeader), 0);
        break;
    }
}
  • 客户端数据处理:
while (true)
{
	//3.输入请求命令
	char cmdBuff[128] = {};
	scanf("%s", cmdBuff);

	//4.处理请求
	if (0 == strcmp(cmdBuff, "exit"))
	{
		printf("接收到命令exit,退出 \n");
		break;
	}
	else if (0 == strcmp(cmdBuff, "login"))
	{
		Login login = { "喜羊羊","123456" };
		DataHeader header = { sizeof(login), CMD_LOGIN};

		//5.向服务器发送请求
		send(sockCli, (const char*)&header, sizeof(header), 0);
		send(sockCli, (const char *)&login, sizeof(login), 0);			

		//接收服务器返回的数据
		DataHeader retHeader = {};
		LoginResult loginRet = {};
		recv(sockCli, ( char*)&retHeader, sizeof(retHeader), 0);
		recv(sockCli, ( char*)&loginRet, sizeof(loginRet), 0);
		printf("LoginResult: %d\n", loginRet.lgResult);
	}
	else if (0 == strcmp(cmdBuff, "logout"))
	{
		LogOut logout = { "喜羊羊" };
		DataHeader headerOut = {sizeof(logout), CMD_LOGIN};

		//5.向服务器发送请求
		send(sockCli, (const char*)&headerOut, sizeof(headerOut), 0);
		send(sockCli, (const char*)&logout, sizeof(logout), 0);

		//接收服务器返回的数据
		DataHeader retHeaderOut = {};
		LogOutResult logOutRet = {};
		recv(sockCli, (char*)&retHeaderOut, sizeof(retHeaderOut), 0);
		recv(sockCli, (char*)&logOutRet, sizeof(logOutRet), 0);
		printf("LogOutResult: %d\n", logOutRet.lgOutResult);
	}
	else
	{
		printf("不支持该命令,请从新输入 \n");
	}
}

【服务端源码】

#define WIN32_LEAN_AND_MEAN
#define _WINSOCK_DEPRECATED_NO_WARNINGS
#include <windows.h>
#include <WinSock2.h>
#include <cstdio>

#pragma comment(lib,"ws2_32.lib")

enum CMD             //命令枚举
{
    CMD_LOGIN,
    CMD_LOGOUT,
    CMD_ERROR
};

//DataHeader
struct DataHeader      //数据包头
{
    short dataLength;
    short cmd;
};

//DataPackage
struct Login          //登录
{
    char UserName[32];
    char PassWord[32];
};
 
struct LoginResult    //登录结果
{
    int lgResult;
};

struct LogOut      //退出登录
{
    char UserName[32];
};


struct LogOutResult  //退出结果
{
    int lgOutResult;
};


int main()
{
    WORD ver = MAKEWORD(2, 2);
    WSAData dat;
    WSAStartup(ver, &dat);

    //1.创建socket套接字
    SOCKET sock = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);

    //2,bind 绑定用于接收客户端连接的端口
    sockaddr_in sinAddr = {};
    sinAddr.sin_family = AF_INET;
    sinAddr.sin_port = htons(5678); //host to net unsigned short
    sinAddr.sin_addr.S_un.S_addr = INADDR_ANY;  //inet_addr("127.0.0.1")
    if (SOCKET_ERROR == bind(sock, (sockaddr*)&sinAddr, sizeof(sockaddr_in)))
    {
        printf("Bind Error\n");
    }
    else
    {
        printf("Bind Success\n");
    }

    //3. listen 监听网络端口
    if (SOCKET_ERROR == listen(sock, 5))
    {
        printf("Listen Error\n");
    }
    else
    {
        printf("Listen Success\n");
    }

    //4.accept 接收客户端连接
    sockaddr_in clientAddr = {};
    int clAddrLen = sizeof(sockaddr_in);

    SOCKET sockAccpt = INVALID_SOCKET;
    sockAccpt = accept(sock, (sockaddr*)&clientAddr, &clAddrLen);

    if (INVALID_SOCKET == sockAccpt)
    {
        printf("Accept Error\n");
    }
    else
    {
        printf("Accept Success\n");
    }
    printf("新客户端加入:Socket = %d,IP = %s \n", (int)sockAccpt, inet_ntoa(clientAddr.sin_addr));


    while (true)
    {
        DataHeader dbHeader = {};
        //接收客户端数据
        int nLen = recv(sockAccpt, (char*)&dbHeader, sizeof(DataHeader), 0);
        if (nLen < 0)
        {
            printf("客户端已退出,任务结束\n");
            break;
        }
        printf("收到命令:%d ,数据长度: %d\n", dbHeader.cmd, dbHeader.dataLength);

        switch (dbHeader.cmd)
        {
        case CMD_LOGIN:
        {
            Login login = {};
            recv(sockAccpt, (char*)&login, sizeof(Login), 0);
            //忽略对用户密码进行判断
            LoginResult lgRet = { 0 };
            send(sockAccpt, (char*)&dbHeader, sizeof(DataHeader), 0);
            send(sockAccpt, (char*)&lgRet, sizeof(LoginResult), 0);
        }
        break;
        case CMD_LOGOUT:
        {
            LogOut logout = {};
            recv(sockAccpt, (char*)&logout, sizeof(LogOut), 0);
            //忽略对用户密码进行判断
            LogOutResult lgOutRet = { 1 };
            send(sockAccpt, (char*)&dbHeader, sizeof(DataHeader), 0);
            send(sockAccpt, (char*)&lgOutRet, sizeof(LogOutResult), 0);
        }
        break;
        default:
            dbHeader.cmd = CMD_ERROR;
            dbHeader.dataLength = 0;
            send(sockAccpt, (char*)&dbHeader, sizeof(DataHeader), 0);
            break;
        }
    }
        //closesocket 关闭套接字
        closesocket(sock);
        closesocket(sockAccpt);

        WSACleanup();

        printf("结束任务\n");
        getchar();
        return 0;
 }

【客户端源码】

#define WIN32_LEAN_AND_MEAN
#define _WINSOCK_DEPRECATED_NO_WARNINGS
#include <windows.h>
#include <WinSock2.h>
#include <cstdio>
#pragma comment(lib,"ws2_32.lib")

enum CMD             //命令枚举
{
	CMD_LOGIN,
	CMD_LOGOUT,
	CMD_ERROR
};

//DataHeader
struct DataHeader      //数据包头
{
	short dataLength;
	short cmd;
};

//DataPackage
struct Login          //登录
{
	char UserName[32];
	char PassWord[32];
};

struct LoginResult    //登录结果
{
	int lgResult;
};

struct LogOut      //退出登录
{
	char UserName[32];
};


struct LogOutResult  //退出结果
{
	int lgOutResult;
};

struct DataPackage
{
	int  age;
	char name[32];
};

int main()
{
	WORD ver = MAKEWORD(2, 2);
	WSAData dat;
	WSAStartup(ver, &dat);

	//1.建立一个socket
	SOCKET sockCli = socket(AF_INET, SOCK_STREAM, 0);
	if (INVALID_SOCKET == sockCli)
	{
		printf("Socket Error\n");
	}
	else
	{
		printf("Socket Success\n");
	}

	//2. connect连接服务器
	sockaddr_in servAddr = {};
	servAddr.sin_family = AF_INET;
	servAddr.sin_port = htons(5678);
	servAddr.sin_addr.S_un.S_addr = inet_addr("127.0.0.1");

	int ret = connect(sockCli, (sockaddr*)&servAddr, sizeof(sockaddr_in));

	if (SOCKET_ERROR == ret)
	{
		printf("Connect Error\n");
	}
	else
	{
		printf("Connect Success\n");
	}

	while (true)
	{
		//3.输入请求命令
		char cmdBuff[128] = {};
		scanf("%s", cmdBuff);

		//4.处理请求
		if (0 == strcmp(cmdBuff, "exit"))
		{
			printf("接收到命令exit,退出 \n");
			break;
		}
		else if (0 == strcmp(cmdBuff, "login"))
		{
			Login login = { "喜羊羊","123456" };
			DataHeader header = { sizeof(login) ,CMD_LOGIN};

			//5.向服务器发送请求
			send(sockCli, (const char*)&header, sizeof(header), 0);
			send(sockCli, (const char *)&login, sizeof(login), 0);			

			//接收服务器返回的数据
			DataHeader retHeader = {};
			LoginResult loginRet = {};
			recv(sockCli, ( char*)&retHeader, sizeof(retHeader), 0);
			recv(sockCli, ( char*)&loginRet, sizeof(loginRet), 0);
			printf("LoginResult: %d\n", loginRet.lgResult);
		}
		else if (0 == strcmp(cmdBuff, "logout"))
		{
			LogOut logout = { "喜羊羊" };
			DataHeader headerOut = { sizeof(logout), CMD_LOGIN };

			//5.向服务器发送请求
			send(sockCli, (const char*)&headerOut, sizeof(headerOut), 0);
			send(sockCli, (const char*)&logout, sizeof(logout), 0);

			//接收服务器返回的数据
			DataHeader retHeaderOut = {};
			LogOutResult logOutRet = {};
			recv(sockCli, (char*)&retHeaderOut, sizeof(retHeaderOut), 0);
			recv(sockCli, (char*)&logOutRet, sizeof(logOutRet), 0);
			printf("LogOutResult: %d\n", logOutRet.lgOutResult);
		}
		else
		{
			printf("不支持该命令,请从新输入 \n");
		}
	}

	//7.关闭套接字 closesocket
	closesocket(sockCli);

	WSACleanup();
	printf("结束任务\n");
	getchar();
	return 0;
}

【测试结果】

猜你喜欢

转载自blog.csdn.net/baidu_41388533/article/details/111823399
今日推荐