答疑解惑

固长数据:就是每次发送消息数据的大小都是固定的

变长数据:发送图片,因每次图片的大小都不一样,所以数据的大小不用,所以在发送时,需要指明消息数据的长度

所以,在步长数据dataLength没有什么用,只有在变长数据,因发送数据的长短是有变化的,所以dataLength是有作用的

粘包:假如,我们每次发送500字节数据,共发送两次,但接收时一下子就接收到了1000字节的数据,这就是粘包。

分包:假如,我们依次发送1000字节的数据,但接收时一下子就收到了500字节的数据,因此,我们需要等待另一500字节的数据,所以在这个过程中我们要有一个数据长度,知道多长,才能最后处理。

接收端:

#include<WinSock2.h>
#include<Windows.h>
#include<stdio.h>
#include<iostream>

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

enum CMD { CMD_Login, CMD_Login_Result, CMD_Logout, CMD_Logout_Result, CMD_ERROR };

//包头
struct DataHeader
{
    short dataLength;
    short cmd;
};
//包体
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;
        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;
        result = 0;
    }
    int result;
};

int main()
{
    WORD ver = MAKEWORD(2, 2);
    WSADATA dat;
    //WinSocket启动
    WSAStartup(ver, &dat);

    //1、建立一个socket
    SOCKET _sock = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP); //AF_INET创建一个IPV4的套接字,SOCK_STREAM面向数据流的,IPPROTO_TCP TCP
    if (INVALID_SOCKET == _sock)
    {
        printf("ERROR:建立失败!\n");
    }
    //2.绑定
    sockaddr_in _sin = {};     //创建网络地址
    _sin.sin_family = AF_INET;
    _sin.sin_port = htons(4567); //Host to Network Short
    _sin.sin_addr.S_un.S_addr = inet_addr("127.0.0.1"); // IP地址 
    if (bind(_sock, (sockaddr *)&_sin, sizeof(_sin)) == SOCKET_ERROR)
    {
        printf("ERROR:绑定失败!\n");
    }
    else
    {
        printf("服务器端绑定成功......\n");
    }
    //3.监听网络端口
    if (listen(_sock, 5) == SOCKET_ERROR)//第二个参数为最大等待多少人可以同时连接
    {
        printf("ERROR:监听失败!\n");
    }
    else
    {
        printf("服务器端监听成功......\n");
    }
    //4.等待接收客户端连接
    sockaddr_in clientAddr = {};
    int nAddrLen = sizeof(sockaddr_in);
    SOCKET _cSOCK = INVALID_SOCKET;
    
    _cSOCK = accept(_sock, (sockaddr *)&clientAddr, &nAddrLen);
    if (_cSOCK == INVALID_SOCKET)
    {
        printf("ERROR:无效客户端SOCKET!\n");
    }
    printf("新客户端加入:Socket=%d,IP = %s\n",(int)_cSOCK, inet_ntoa(clientAddr.sin_addr));//inet_ntoa(clientAddr.sin_addr)将接收到的IP地址转化为字符串

    while (1)
    {
        //增加一个缓冲区
        char szRecv[1024] = {};
        //5.接收客户端新数据
        int nLen = recv(_cSOCK,szRecv, sizeof(DataHeader), 0);
        DataHeader *header = (DataHeader*)szRecv;

        if (nLen <= 0)
        {
            printf("客户端已退出!任务结束!");
            break;
        }

        switch (header->cmd){
            case CMD_Login:
                {
                    recv(_cSOCK, szRecv + sizeof(DataHeader), header->dataLength-sizeof(DataHeader), 0);
                    Login *login = (Login*)szRecv;
                    printf("收到命令:CMD_Login,数据长度:%d\nUserName:%s\nPassWord:%s\n", login->dataLength,login->username,login->password);
                    //忽略判断用户密码是否正确的过程
                    LoginResult ret;
                    send(_cSOCK, (char *)&ret, sizeof(LoginResult), 0); //再发消息体

                }
            case CMD_Logout:
                {
                    
                    recv(_cSOCK, szRecv + sizeof(DataHeader), header->dataLength - sizeof(DataHeader), 0);
                    Logout* logout = (Logout*)szRecv;
                    printf("收到命令:CMD_Logout,数据长度:%d\nUserName:%s\n", logout->dataLength, logout->username);

                    //忽略判断用户密码是否正确的过程
                    LogoutResult let ;
                    send(_cSOCK, (char *)&let, sizeof(let), 0); //再发消息体
                }
                break;
            default:
            {
                    DataHeader header = { 0 };
                    send(_cSOCK, (char *)&header.cmd, sizeof(header), 0);
            }

                break;
        }
    }

    //8.关闭自身的socket
    closesocket(_sock);


    //WinSocket关闭
    WSACleanup();

    system("pause");
    return 0;
}

猜你喜欢

转载自www.cnblogs.com/zhuifeng-mayi/p/10909885.html
今日推荐