(C++ server study notes): Send structured network message data

table of Contents

Send structured network message data

Demo case

Send structured network message data

[Pure string network message]

  • Advantages :
    • Handling simple commands is convenient and quick.
  • Disadvantages :
    • Passing large amounts of data is expensive for string parsing.
  • Application method in the enterprise:
    • Character data in JSON, XML, and custom formats.

[Use a structured binary data stream to transmit network messages]

  • advantage:
    • Simple, convenient, fast analysis and low consumption.
  • Disadvantages:
    • Strict network byte order consistency is required.

  • About recv function to receive network messages
struct DataHeader
{
    short dataLength;
    short cmd;
};
  • Fixed length data, variable length data, sticking/unpacking, less packing/grouping.

Demo case

  • Server:
    • Define the data:
struct DataPackage 
{
    int  age;
    char name[32];  
};
  • Sending data requires forced type conversion
if (0 == strcmp(cmdBuff, "GetInfo"))
{          
    DataPackage datapg = {6,"喜羊羊"};
    send(sockAccpt, (const char *) &datapg, sizeof(DataPackage), 0);
}
  • Client:
    • Define the data:
struct DataPackage 
{
    int  age;
    char name[32];  
};
  • To receive data, a forced type conversion is required
char recvBuff[128] = {};
int nlen = recv(sockCli, recvBuff, 128, 0);
if (nlen > 0)
{
    DataPackage* dpRecv =(DataPackage*) recvBuff;
    printf("接收到数据:年龄 = %d, 姓名 = %s \n", dpRecv->age, dpRecv->name);
}

[Complete code]

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

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

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

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)
    {
        char cmdBuff[128] = {};
        //5.接收客户端数据
        int nLen = recv(sockAccpt, cmdBuff, 128, 0);
        if (nLen < 0)
        {
            printf("客户端已退出,任务结束\n");
            break;
        }
        printf("收到命令:%s\n", cmdBuff);

        //6.处理请求
        if (0 == strcmp(cmdBuff, "GetInfo"))
        {
            //7.向客户端发送数据
            DataPackage datapg = {6,"喜羊羊"};
            send(sockAccpt, (const char *) &datapg, sizeof(DataPackage), 0);
        }
        else
        {
            //7.向客户端发送数据
            char msgBuff[] = "???.";
            send(sockAccpt, msgBuff, strlen(msgBuff) + 1, 0);
        }
    }

    //closesocket 关闭套接字
    closesocket(sock);
    closesocket(sockAccpt);

    WSACleanup();

    printf("结束任务\n");
    getchar();
    return 0;
}
  • Client:
#define WIN32_LEAN_AND_MEAN
#define _WINSOCK_DEPRECATED_NO_WARNINGS
#include <windows.h>
#include <WinSock2.h>
#include <cstdio>
#pragma comment(lib,"ws2_32.lib")

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
        {
            //5.向服务器发送请求
            send(sockCli, cmdBuff, strlen(cmdBuff) + 1, 0);
        }

        //6.接收服务器信息 recv
        char recvBuff[128] = {};
        int nlen = recv(sockCli, recvBuff, 128, 0);
        if (nlen > 0)
        {
            DataPackage* dpRecv =(DataPackage*) recvBuff;
            printf("接收到数据:年龄 = %d, 姓名 = %s \n", dpRecv->age, dpRecv->name);
        }
    }

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

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

  • It can be seen from the above that when the command is entered correctly, the result is correct. When the command is wrong, the server sends "???." to the client. However, the output will be wrong through the coercive type conversion to the DataPackage type. Good solution.

Guess you like

Origin blog.csdn.net/baidu_41388533/article/details/111818420