5_client和server进行交互

创建server端

该server端可以连接多个客户端,但不可以和单个客户端进行多次交互

#define WIN32_LEAN_AND_MEAN   //windows.h和WinSock2.h有宏定义冲突,导致WinSock2.h必须要在windows.h前引用,定义该宏后可不用强制位置
#define _WINSOCK_DEPRECATED_NO_WARNINGS 

#include<windows.h>
#include<WinSock2.h>
#include<iostream>
#pragma comment(lib, "ws2_32.lib")  //method_1

int main02()
{
    WORD ver = MAKEWORD(2, 2);
    WSADATA dat;
    WSAStartup(ver, &dat);     //Windows socket网络环境的启动函数,需要引入ws2_32库文件,可以使用method_1,也可以在属性界面链接器的输入选项添加依赖项
    //1.创建socket
    SOCKET sock = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);    //地址系列规范,套接字规范,使用的协议
    //2.绑定地址
    sockaddr_in server_addr = {};
    server_addr.sin_family = AF_INET;
    server_addr.sin_port = htons(6666);
    server_addr.sin_addr.S_un.S_addr = INADDR_ANY;          //代表本机所有地址
    int ret = bind(sock, (sockaddr*)&server_addr, sizeof(sockaddr_in));  //若成功返回0
    if (SOCKET_ERROR == ret)    
    {
        std::cout << "绑定错误" << std::endl;
    }
    //3.监听端口
    ret = listen(sock, 5);    //第二个参数为挂起的连接队列的最大长度,若成功返回0
    if (SOCKET_ERROR == ret)
    {
        std::cout << "监听错误" << std::endl;
    }
    //4.接收客户端连接
    sockaddr_in client_addr = {};
    int len = sizeof(sockaddr_in);
    char buf[] = "hello, i'm server";
    while (true)
    {
        SOCKET client_sock = accept(sock, (sockaddr*)&client_addr, &len);    //accept函数返回一个新的套接字来和客户端通信,sockaddr和sockaddr_in所代表的意义一样,字节大小也一样,只不过sockaddr_in是后面创建的,之前的接口没有更改
        if (INVALID_SOCKET == client_sock)
        {
            std::cout << "连接客户端错误" << std::endl;
        }
        std::cout << "客户端:" << inet_ntoa(client_addr.sin_addr) << "连接成功" << std::endl;
        //5.发送数据
        int buf_len = send(client_sock, buf, sizeof(buf), 0);  //如果未发生错误, send 将返回发送的总字节数,该字节数可能小于 len 参数中请求发送的数量
        if (SOCKET_ERROR == buf_len)
        {
            std::cout << "发送错误" << std::endl;
        }
    }
    //6.关闭套接字
    closesocket(sock);
    WSACleanup();
    return 0;
}

该server端可以和单个客户端进行多次交互,但不可以连接多个客户端并和多个客户端进行交互

#define WIN32_LEAN_AND_MEAN   //windows.h和WinSock2.h有宏定义冲突,导致WinSock2.h必须要在windows.h前引用,定义该宏后可不用强制位置
#define _WINSOCK_DEPRECATED_NO_WARNINGS 
#define _CRT_SECURE_NO_WARNINGS

#include<windows.h>
#include<WinSock2.h>
#include<iostream>
#pragma comment(lib, "ws2_32.lib")  //method_1
struct DataPackage
{
    int age;
    char name[32];
};

int main()
{
    WORD ver = MAKEWORD(2, 2);
    WSADATA dat;
    WSAStartup(ver, &dat);     //Windows socket网络环境的启动函数,需要引入ws2_32库文件,可以使用method_1,也可以在属性界面链接器的输入选项添加依赖项
                               //1.创建socket
    SOCKET sock = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);    //地址系列规范,套接字规范,使用的协议
                                                                //2.绑定地址
    sockaddr_in server_addr = {};
    server_addr.sin_family = AF_INET;
    server_addr.sin_port = htons(6666);
    server_addr.sin_addr.S_un.S_addr = INADDR_ANY;          //代表本机所有地址
    int ret = bind(sock, (sockaddr*)&server_addr, sizeof(sockaddr_in));  //若成功返回0
    if (SOCKET_ERROR == ret)
    {
        std::cout << "绑定错误" << std::endl;
    }
    //3.监听端口
    ret = listen(sock, 5);    //第二个参数为挂起的连接队列的最大长度,若成功返回0
    if (SOCKET_ERROR == ret)
    {
        std::cout << "监听错误" << std::endl;
    }
    //4.接收客户端连接,
    sockaddr_in client_addr = {};
    int len = sizeof(sockaddr_in);
    char buf[] = "hello, i'm server";
    char recv_buf[128] = {};
    char send_buf[128] = {};
    std::cout << typeid(recv_buf).name() << std::endl;
    //accept函数放在循坏外面,证明只能处理一个客户端的请求
    SOCKET client_sock = accept(sock, (sockaddr*)&client_addr, &len);    //accept函数返回一个新的套接字来和客户端通信,sockaddr和sockaddr_in所代表的意义一样,字节大小也一样,只不过sockaddr_in是后面创建的,之前的接口没有更改
    if (INVALID_SOCKET == client_sock)
    {
        std::cout << "连接客户端错误" << std::endl;
    }
    std::cout << "客户端:" << inet_ntoa(client_addr.sin_addr) << "连接成功" << std::endl;
    //5.发送数据
    int buf_len = send(client_sock, buf, sizeof(buf), 0);  //如果未发生错误, send 将返回发送的总字节数,该字节数可能小于 len 参数中请求发送的数量
    if (SOCKET_ERROR == buf_len)
    {
        std::cout << "发送错误" << std::endl;
    }
    while (true)
    {
        //6.接收数据
        buf_len = recv(client_sock, recv_buf, 128, 0);
        //7.处理数据
        if (SOCKET_ERROR == buf_len)
        {
            std::cout << "接收错误" << std::endl;
            break;
        }
        else
        {
            std::cout << "接收请求:" << recv_buf << std::endl;
            if (strncmp(recv_buf, "exit", 4) == 0)
            {
                std::cout << "客户端连接退出" << std::endl;
                break;
            }
            else if (strncmp(recv_buf, "get_info_struct", sizeof("get_info_struct")) == 0)
            {
                DataPackage data = {18, "aaron"};
                buf_len = send(client_sock, (char *)&data, sizeof(send_buf), 0);  //如果未发生错误, send 将返回发送的总字节数,该字节数可能小于 len 参数中请求发送的数量
                if (SOCKET_ERROR == buf_len)
                {
                    std::cout << "发送错误" << std::endl;
                }
            }
            else if (strncmp(recv_buf, "get_name", sizeof("get_name")) == 0)
            {
                strcpy(send_buf, "aaron");
                buf_len = send(client_sock, send_buf, sizeof(send_buf), 0); 
                if (SOCKET_ERROR == buf_len)
                {
                    std::cout << "发送错误" << std::endl;
                }
            }
            else if (strncmp(recv_buf, "get_age", sizeof("get_age")) == 0)
            {
                strcpy(send_buf, "18");
                buf_len = send(client_sock, send_buf, sizeof(send_buf), 0); 
                if (SOCKET_ERROR == buf_len)
                {
                    std::cout << "发送错误" << std::endl;
                }
            }
            else
            {
                strcpy(send_buf, "不合理的请求,请重新发送");
                buf_len = send(client_sock, send_buf, sizeof(send_buf), 0); 
                if (SOCKET_ERROR == buf_len)
                {
                    std::cout << "发送错误" << std::endl;
                }
            }
        }
    }
    std::cout << "服务器退出" << std::endl;
    //8.关闭套接字
    closesocket(sock);
    WSACleanup();
    return 0;
}

服务器模拟网络报文分别发送报文头和报文体和客户端进行交互

#define WIN32_LEAN_AND_MEAN   //windows.h和WinSock2.h有宏定义冲突,导致WinSock2.h必须要在windows.h前引用,定义该宏后可不用强制位置
#define _WINSOCK_DEPRECATED_NO_WARNINGS 
#define _CRT_SECURE_NO_WARNINGS

#include<windows.h>
#include<WinSock2.h>
#include<iostream>
#pragma comment(lib, "ws2_32.lib")  //method_1

enum CMD
{
    CMD_LOGIN,
    CMD_LOGOUT,
    CMD_EXIT
};
struct DataHeader
{
    short data_length;
    short cmd;
};
struct Login
{
    char username[32];
    char password[32];
};
struct LoginResult
{
    int result;
};
struct Logout
{
    char username[32];
};
struct LogoutResult
{
    int result;
};


bool judge_return_value(char* function_name, int ret)
{
    if (SOCKET_ERROR == ret)
    {
        std::cout << function_name <<  "错误"<< std::endl;
        return TRUE;
    }
    return FALSE;
}
int main()
{
    WORD ver = MAKEWORD(2, 2);
    WSADATA dat;
    WSAStartup(ver, &dat);     //Windows socket网络环境的启动函数,需要引入ws2_32库文件,可以使用method_1,也可以在属性界面链接器的输入选项添加依赖项
                               //1.创建socket
    SOCKET sock = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);    //地址系列规范,套接字规范,使用的协议
                                                                //2.绑定地址
    sockaddr_in server_addr = {};
    server_addr.sin_family = AF_INET;
    server_addr.sin_port = htons(6666);
    server_addr.sin_addr.S_un.S_addr = INADDR_ANY;          //代表本机所有地址
    int ret = bind(sock, (sockaddr*)&server_addr, sizeof(sockaddr_in));  //若成功返回0
    judge_return_value("bind", ret);
    //3.监听端口
    ret = listen(sock, 5);    //第二个参数为挂起的连接队列的最大长度,若成功返回0
    judge_return_value("listen", ret);
    //4.接收客户端连接,
    sockaddr_in client_addr = {};
    int len = sizeof(sockaddr_in);
    char buf[] = "hello, i'm server";
    char recv_buf[128] = {};
    char send_buf[128] = {};
    //std::cout << typeid(recv_buf).name() << std::endl;
    //accept函数放在循坏外面,证明只能处理一个客户端的请求
    SOCKET client_sock = accept(sock, (sockaddr*)&client_addr, &len);    //accept函数返回一个新的套接字来和客户端通信,sockaddr和sockaddr_in所代表的意义一样,字节大小也一样,只不过sockaddr_in是后面创建的,之前的接口没有更改
    if (INVALID_SOCKET == client_sock)
    {
        std::cout << "连接客户端错误" << std::endl;
    }
    std::cout << "客户端:" << inet_ntoa(client_addr.sin_addr) << "连接成功" << std::endl;
    //5.发送数据
    int buf_len = send(client_sock, buf, sizeof(buf), 0);  //如果未发生错误, send 将返回发送的总字节数,该字节数可能小于 len 参数中请求发送的数量
    judge_return_value("send", buf_len);
    while (true)
    {
        //6.接收数据
        DataHeader header = {};
        buf_len = recv(client_sock, (char*)&header, sizeof(DataHeader), 0);
        //7.处理数据
        if (judge_return_value("recv", buf_len))
        {
            break;
        }
        else
        {
            std::cout << "接收请求:" << header.cmd << "报文长度:" << header.data_length <<std::endl;
            if (header.cmd == CMD_EXIT)
            {
                std::cout << "客户端连接退出" << std::endl;
                break;
            }
            else if (header.cmd == CMD_LOGIN)
            {
                Login data = {};
                buf_len = recv(client_sock, (char *)&data, sizeof(Login), 0);  //如果未发生错误, send 将返回发送的总字节数,该字节数可能小于 len 参数中请求发送的数量
                judge_return_value("recv", buf_len);
                LoginResult res = {};
                if (!strncmp(data.username, "aaron", sizeof("aaron") && !strncmp(data.password, "123456", sizeof("123456"))))
                {
                    res.result = 1;
                }
                else
                {
                    res.result = 0;
                }
                buf_len = send(client_sock, (char *)&res, sizeof(LoginResult), 0);  
                judge_return_value("send", buf_len);
            }
            else if (header.cmd == CMD_LOGOUT)
            {
                Logout data = {};
                buf_len = recv(client_sock, (char *)&data, sizeof(Logout), 0); 
                judge_return_value("recv", buf_len);
                LoginResult res = {2};
                buf_len = send(client_sock, (char *)&res, sizeof(LoginResult), 0);  
                judge_return_value("send", buf_len);
            }
        }
    }
    std::cout << "服务器退出" << std::endl;
    getchar();
    //8.关闭套接字
    closesocket(sock);
    WSACleanup();
    return 0;
}

服务器模拟网络报文同时发送报文头和报文体和客户端进行交互

#define WIN32_LEAN_AND_MEAN   //windows.h和WinSock2.h有宏定义冲突,导致WinSock2.h必须要在windows.h前引用,定义该宏后可不用强制位置
#define _WINSOCK_DEPRECATED_NO_WARNINGS 
#define _CRT_SECURE_NO_WARNINGS

#include<windows.h>
#include<WinSock2.h>
#include<iostream>
#pragma comment(lib, "ws2_32.lib")  //method_1

enum CMD
{
    CMD_LOGIN,
    CMD_LOGIN_RESULT,
    CMD_LOGOUT,
    CMD_LOGOUT_RESULT,
    CMD_EXIT
};
struct DataHeader
{
    short data_length;
    short cmd;
};
struct Login : public DataHeader
{
    Login()
    {
        data_length = sizeof(Login);
        cmd = CMD_LOGIN;
    }
    char username[32];
    char password[32];
};
struct LoginResult : public DataHeader
{
    LoginResult()
    {
        data_length = sizeof(LoginResult);
        cmd = CMD_LOGIN_RESULT;
    }
    int result;
};
struct Logout : public DataHeader
{
    Logout()
    {
        data_length = sizeof(Logout);
        cmd = CMD_LOGOUT;
    }
    char username[32];
};
struct LogoutResult : public DataHeader
{
    LogoutResult()
    {
        data_length = sizeof(LogoutResult);
        cmd = CMD_LOGOUT_RESULT;
    }
    int result;
};


bool judge_return_value(char* function_name, int ret)
{
    if (SOCKET_ERROR == ret)
    {
        std::cout << function_name <<  "错误" << std::endl;
        return TRUE;
    }
    return FALSE;
}
int main()
{
    WORD ver = MAKEWORD(2, 2);
    WSADATA dat;
    WSAStartup(ver, &dat);     //Windows socket网络环境的启动函数,需要引入ws2_32库文件,可以使用method_1,也可以在属性界面链接器的输入选项添加依赖项
                               //1.创建socket
    SOCKET sock = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);    //地址系列规范,套接字规范,使用的协议
                                                                //2.绑定地址
    sockaddr_in server_addr = {};
    server_addr.sin_family = AF_INET;
    server_addr.sin_port = htons(6666);
    server_addr.sin_addr.S_un.S_addr = INADDR_ANY;          //代表本机所有地址
    int ret = bind(sock, (sockaddr*)&server_addr, sizeof(sockaddr_in));  //若成功返回0
    judge_return_value("bind", ret);
    //3.监听端口
    ret = listen(sock, 5);    //第二个参数为挂起的连接队列的最大长度,若成功返回0
    judge_return_value("listen", ret);
    //4.接收客户端连接,
    sockaddr_in client_addr = {};
    int len = sizeof(sockaddr_in);
    char buf[] = "hello, i'm server";
    char recv_buf[128] = {};
    char send_buf[128] = {};
    //std::cout << typeid(recv_buf).name() << std::endl;
    //accept函数放在循坏外面,证明只能处理一个客户端的请求
    SOCKET client_sock = accept(sock, (sockaddr*)&client_addr, &len);    //accept函数返回一个新的套接字来和客户端通信,sockaddr和sockaddr_in所代表的意义一样,字节大小也一样,只不过sockaddr_in是后面创建的,之前的接口没有更改
    if (INVALID_SOCKET == client_sock)
    {
        std::cout << "连接客户端错误" << std::endl;
    }
    std::cout << "客户端:" << inet_ntoa(client_addr.sin_addr) << "连接成功" << std::endl;
    //5.发送数据
    int buf_len = send(client_sock, buf, sizeof(buf), 0);  //如果未发生错误, send 将返回发送的总字节数,该字节数可能小于 len 参数中请求发送的数量
    judge_return_value("send", buf_len);
    while (true)
    {
        //6.接收数据
        DataHeader header = {};
        buf_len = recv(client_sock, (char*)&header, sizeof(DataHeader), 0);
        //7.处理数据
        if (judge_return_value("recv", buf_len))
        {
            break;
        }
        else
        {
            if (header.cmd == CMD_EXIT)
            {
                std::cout << "客户端连接退出" << std::endl;
                break;
            }
            else if (header.cmd == CMD_LOGIN)
            {
                Login data = {};
                buf_len = recv(client_sock, (char *)&data + sizeof(DataHeader), sizeof(Login) - sizeof(DataHeader), 0);  //如果未发生错误, send 将返回发送的总字节数,该字节数可能小于 len 参数中请求发送的数量
                judge_return_value("recv", buf_len);
                std::cout << "接收请求:LOGIN"  << ",数据长度:" << data.data_length << ",用户名:" << data.username << std::endl;
                LoginResult res = {};
                if (!strncmp(data.username, "aaron", sizeof("aaron") && !strncmp(data.password, "123456", sizeof("123456"))))
                {
                    res.result = 0;      //网络通信一般返回0为正常
                }
                else
                {
                    res.result = 1;
                }
                buf_len = send(client_sock, (char *)&res, sizeof(LoginResult), 0);  
                judge_return_value("send", buf_len);
            }
            else if (header.cmd == CMD_LOGOUT)
            {
                Logout data = {};
                buf_len = recv(client_sock, (char *)&data + sizeof(DataHeader), sizeof(Logout) - sizeof(DataHeader), 0);
                judge_return_value("recv", buf_len);
                std::cout << "接收请求:LOGOUT"  << ",数据长度:" << data.data_length << ",用户名:" << data.username << std::endl;
                LogoutResult res = {};
                res.result = 0;
                buf_len = send(client_sock, (char *)&res, sizeof(LogoutResult), 0);  
                judge_return_value("send", buf_len);
            }
        }
    }
    std::cout << "服务器退出" << std::endl;
    getchar();
    //8.关闭套接字
    closesocket(sock);
    WSACleanup();
    return 0;
}

创建客户端

只进行服务器的连接测试

#define WIN32_LEAN_AND_MEAN   //windows.h和WinSock2.h有宏定义冲突,导致WinSock2.h必须要在windows.h前引用,定义该宏后可不用强制位置
#define _WINSOCK_DEPRECATED_NO_WARNINGS 

#include<windows.h>
#include<WinSock2.h>
#include<iostream>
#pragma comment(lib, "ws2_32.lib")  //method_1
struct DataPackage
{
    int age;
    char name[32];
};

int main()
{
    WORD ver = MAKEWORD(2, 2);
    WSADATA dat;
    WSAStartup(ver, &dat);     //Windows socket网络环境的启动函数,需要引入ws2_32库文件,可以使用method_1,也可以在属性界面链接器的输入选项添加依赖项
    //创建socket
    SOCKET sock = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);    //客户端的地址由系统自动分配,不需要绑定
    //连接服务器
    sockaddr_in server_addr = {};
    server_addr.sin_family = AF_INET;
    server_addr.sin_port = htons(6666);
    server_addr.sin_addr.S_un.S_addr = inet_addr("127.0.0.1");
    int ret = connect(sock, (sockaddr*)&server_addr, sizeof(sockaddr_in));       //如果未发生错误,则返回零
    if (SOCKET_ERROR == ret)
    {
        std::cout << "连接建立出错" << std::endl;
    }
    //接受消息
    char buf[128] = {};
    int buf_len = recv(sock, buf, 128, 0);
    if (SOCKET_ERROR == buf_len)
    {
        std::cout << "接收错误" << std::endl;
    }
    std::cout << buf << std::endl;
    getchar();
    //关闭套接字
    closesocket(sock);
    WSACleanup();
    return 0;
}

可以和服务器进行结构化数据的交互

#define WIN32_LEAN_AND_MEAN   //windows.h和WinSock2.h有宏定义冲突,导致WinSock2.h必须要在windows.h前引用,定义该宏后可不用强制位置
#define _WINSOCK_DEPRECATED_NO_WARNINGS 

#include<windows.h>
#include<WinSock2.h>
#include<iostream>
#pragma comment(lib, "ws2_32.lib")  //method_1
struct DataPackage
{
    int age;
    char name[32];
};

int main()
{
    WORD ver = MAKEWORD(2, 2);
    WSADATA dat;
    WSAStartup(ver, &dat);     //Windows socket网络环境的启动函数,需要引入ws2_32库文件,可以使用method_1,也可以在属性界面链接器的输入选项添加依赖项
    //创建socket
    SOCKET sock = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);    //客户端的地址由系统自动分配,不需要绑定
    //连接服务器
    sockaddr_in server_addr = {};
    server_addr.sin_family = AF_INET;
    server_addr.sin_port = htons(6666);
    server_addr.sin_addr.S_un.S_addr = inet_addr("127.0.0.1");
    int ret = connect(sock, (sockaddr*)&server_addr, sizeof(sockaddr_in));       //如果未发生错误,则返回零
    if (SOCKET_ERROR == ret)
    {
        std::cout << "连接建立出错" << std::endl;
    }
    //接受消息
    char buf[128] = {};
    int buf_len = recv(sock, buf, 128, 0);
    if (SOCKET_ERROR == buf_len)
    {
        std::cout << "接收错误" << std::endl;
    }
    std::cout << buf << std::endl;
    char recv_buf[128] = {};
    char send_buf[128] = {};
    while (true)
    {
        //输入数据
        std::cin >> send_buf;
        if (strncmp(send_buf, "exit", 4) == 0)
        {
            buf_len = send(sock, send_buf, sizeof(send_buf), 0);  //如果未发生错误, send 将返回发送的总字节数,该字节数可能小于 len 参数中请求发送的数量
            if (SOCKET_ERROR == buf_len)
            {
                std::cout << "发送错误" << std::endl;
            }
            break;
        }
        buf_len = send(sock, send_buf, sizeof(send_buf), 0);
        if (SOCKET_ERROR == buf_len)
        {
            std::cout << "发送错误" << std::endl;
        }
        buf_len = recv(sock, recv_buf, 128, 0);
        DataPackage* data = (DataPackage* )recv_buf;
        if (SOCKET_ERROR == buf_len)
        {
            std::cout << "接收错误" << std::endl;
        }
        std::cout << data->age << data->name << std::endl;
    }
    std::cout << "连接退出" << std::endl;
    getchar();
    //关闭套接字
    closesocket(sock);
    WSACleanup();
    return 0;
}

可以和服务器进行报文模式的结构化数据的交互

#define WIN32_LEAN_AND_MEAN   //windows.h和WinSock2.h有宏定义冲突,导致WinSock2.h必须要在windows.h前引用,定义该宏后可不用强制位置
#define _WINSOCK_DEPRECATED_NO_WARNINGS 

#include<windows.h>
#include<WinSock2.h>
#include<iostream>
#pragma comment(lib, "ws2_32.lib")  //method_1

bool judge_return_value(char* function_name, int ret)
{
    if (SOCKET_ERROR == ret)
    {
        std::cout << function_name << "错误" << std::endl;
        return FALSE;
    }
    return TRUE;
}

enum CMD
{
    CMD_LOGIN,
    CMD_LOGOUT,
    CMD_EXIT
};
struct DataHeader
{
    short data_length;
    short cmd;
};
struct Login
{
    char username[32];
    char password[32];
};
struct LoginResult
{
    int result;
};
struct Logout
{
    char username[32];
};
struct LogoutResult
{
    int result;
};

int main()
{
    WORD ver = MAKEWORD(2, 2);
    WSADATA dat;
    WSAStartup(ver, &dat);     //Windows socket网络环境的启动函数,需要引入ws2_32库文件,可以使用method_1,也可以在属性界面链接器的输入选项添加依赖项
    //创建socket
    SOCKET sock = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);    //客户端的地址由系统自动分配,不需要绑定
    //连接服务器
    sockaddr_in server_addr = {};
    server_addr.sin_family = AF_INET;
    server_addr.sin_port = htons(6666);
    server_addr.sin_addr.S_un.S_addr = inet_addr("127.0.0.1");
    int ret = connect(sock, (sockaddr*)&server_addr, sizeof(sockaddr_in));       //如果未发生错误,则返回零
    judge_return_value("connect", ret);
    //接受消息
    char buf[128] = {};
    int buf_len = recv(sock, buf, 128, 0);
    judge_return_value("recv", buf_len);
    std::cout << buf << std::endl;
    char recv_buf[128] = {};
    char send_buf[128] = {};
    while (true)
    {
        //输入数据
        std::cin >> send_buf;
        if (strncmp(send_buf, "exit", sizeof("exit")) == 0)
        {
            DataHeader header = { 0, CMD_EXIT };
            buf_len = send(sock, (char*)&header, sizeof(DataHeader), 0);
            judge_return_value("send", buf_len);
            break;
        }
        else if (strncmp(send_buf, "login", sizeof("login")) == 0)
        {
            Login info = {"aaron", "123456"};
            DataHeader header = { sizeof(Login), CMD_LOGIN };
            buf_len = send(sock, (char*)&header, sizeof(DataHeader), 0);  
            judge_return_value("send", buf_len);
            buf_len = send(sock, (char*)&info, sizeof(Login), 0);
            judge_return_value("send", buf_len);
            LoginResult res = {};
            buf_len = recv(sock, (char*)&res, sizeof(LoginResult), 0);
            judge_return_value("recv", buf_len);
            std::cout << res.result << std::endl;
        }
        else if (strncmp(send_buf, "logout", sizeof("logout")) == 0)
        {
            Logout info = { "aaron"};
            DataHeader header = { sizeof(Logout), CMD_LOGOUT };
            buf_len = send(sock, (char*)&header, sizeof(DataHeader), 0);
            judge_return_value("send", buf_len);
            buf_len = send(sock, (char*)&info, sizeof(Logout), 0);
            judge_return_value("send", buf_len);
            LogoutResult res = {};
            buf_len = recv(sock, (char*)&res, sizeof(LoginResult), 0);
            judge_return_value("recv", buf_len);
            std::cout << res.result << std::endl;
        }
    }
    std::cout << "连接退出" << std::endl;
    getchar();
    //关闭套接字
    closesocket(sock);
    WSACleanup();
    return 0;
}

可以和服务器进行整体报文模式的结构化数据的交互

#define WIN32_LEAN_AND_MEAN   //windows.h和WinSock2.h有宏定义冲突,导致WinSock2.h必须要在windows.h前引用,定义该宏后可不用强制位置
#define _WINSOCK_DEPRECATED_NO_WARNINGS 
#define _CRT_SECURE_NO_WARNINGS

#include<windows.h>
#include<WinSock2.h>
#include<iostream>
#pragma comment(lib, "ws2_32.lib")  //method_1

bool judge_return_value(char* function_name, int ret)
{
    if (SOCKET_ERROR == ret)
    {
        std::cout << function_name << "错误" << std::endl;
        return FALSE;
    }
    return TRUE;
}

enum CMD
{
    CMD_LOGIN,
    CMD_LOGIN_RESULT,
    CMD_LOGOUT,
    CMD_LOGOUT_RESULT,
    CMD_EXIT
};
struct DataHeader
{
    short data_length;
    short cmd;
};
struct Login : public DataHeader
{
    Login()
    {
        data_length = sizeof(Login);
        cmd = CMD_LOGIN;
    }
    char username[32];
    char password[32];
};
struct LoginResult : public DataHeader
{
    LoginResult()
    {
        data_length = sizeof(LoginResult);
        cmd = CMD_LOGIN_RESULT;
    }
    int result;
};
struct Logout : public DataHeader
{
    Logout()
    {
        data_length = sizeof(Logout);
        cmd = CMD_LOGOUT;
    }
    char username[32];
};
struct LogoutResult : public DataHeader
{
    LogoutResult()
    {
        data_length = sizeof(LogoutResult);
        cmd = CMD_LOGOUT_RESULT;
    }
    int result;
};


int main()
{
    WORD ver = MAKEWORD(2, 2);
    WSADATA dat;
    WSAStartup(ver, &dat);     //Windows socket网络环境的启动函数,需要引入ws2_32库文件,可以使用method_1,也可以在属性界面链接器的输入选项添加依赖项
    //创建socket
    SOCKET sock = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);    //客户端的地址由系统自动分配,不需要绑定
    //连接服务器
    sockaddr_in server_addr = {};
    server_addr.sin_family = AF_INET;
    server_addr.sin_port = htons(6666);
    server_addr.sin_addr.S_un.S_addr = inet_addr("127.0.0.1");
    int ret = connect(sock, (sockaddr*)&server_addr, sizeof(sockaddr_in));       //如果未发生错误,则返回零
    judge_return_value("connect", ret);
    //接受消息
    char buf[128] = {};
    int buf_len = recv(sock, buf, 128, 0);
    judge_return_value("recv", buf_len);
    std::cout << buf << std::endl;
    char recv_buf[128] = {};
    char send_buf[128] = {};
    while (true)
    {
        //输入数据
        std::cin >> send_buf;
        if (strncmp(send_buf, "exit", sizeof("exit")) == 0)
        {
            DataHeader header = { 0, CMD_EXIT };
            buf_len = send(sock, (char*)&header, sizeof(DataHeader), 0);
            judge_return_value("send", buf_len);
            break;
        }
        else if (strncmp(send_buf, "login", sizeof("login")) == 0)
        {
            Login info = {};
            strcpy(info.username, "aaron");
            strcpy(info.password, "123456");
            buf_len = send(sock, (char*)&info, sizeof(Login), 0);
            judge_return_value("send", buf_len);
            LoginResult res = {};
            buf_len = recv(sock, (char*)&res, sizeof(LoginResult), 0);
            judge_return_value("recv", buf_len);
            std::cout << "数据指令:" << res.cmd << ",数据长度:" << res.data_length << ",返回:"<<res.result << std::endl;
        }
        else if (strncmp(send_buf, "logout", sizeof("logout")) == 0)
        {
            Logout info = { };
            strcpy(info.username, "aaron");
            buf_len = send(sock, (char*)&info, sizeof(Logout), 0);
            judge_return_value("send", buf_len);
            LogoutResult res = {};
            buf_len = recv(sock, (char*)&res, sizeof(LoginResult), 0);
            judge_return_value("recv", buf_len);
            std::cout << "数据指令:" << res.cmd << ",数据长度:" << res.data_length << ",返回:" << res.result << std::endl;
        }
    }
    std::cout << "连接退出" << std::endl;
    getchar();
    //关闭套接字
    closesocket(sock);
    WSACleanup();
    return 0;
}

Leave a Comment

Your email address will not be published. Required fields are marked *

Scroll to Top