C++之最简单的TCP客户端和服务器(Windows版)

这里做个备份,毕竟在对第三方网络库或者自己开发网络库做压测时,需要有比较基准,这个基准必须是最简陋的乞丐版,即只调用系统API实现的最简单的TCP客户端和服务器。例子给出的是最简单的Ping-Pong测试,很形象了,像打乒乓球一样将数据丢来丢去。

一.服务端

//server.cpp
#include<iostream>
#include<winsock.h>   //windows平台的网络库头文件
#pragma comment(lib,"ws2_32.lib")   //库文件

#define PORT 5050
#define BUFSIZ 512

int main()
{
    //初始化套接字库
    //WSA  windows socket async  windows异步套接字
    //WSAStartup启动套接字 参数形式:WORD  WSADATA
    //parm1:请求的socket版本 2.2 2.1 1.0
    //parm2:传出参数
    WORD w_req = MAKEWORD(2, 2);//版本号
    WSADATA wsadata;
    //成功:WSAStartup函数返回零
    if (WSAStartup(w_req, &wsadata) != 0) {
        std::cout << "WSAStartup failed" << std::endl;
        return -1;
    } else {
        std::cout << "WSAStartup succeed" << std::endl;
    }

    //1.创建空的Socket
    //parm1:af 地址协议族 ipv4 ipv6
    //parm2:type 传输协议类型 流式套接字(SOCK_STREAM) 数据报
    //parm3protocl 使用具体的某个传输协议
    SOCKET s_server = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
    if (s_server == INVALID_SOCKET)
    {
        std::cout << "Create socket failed" << std::endl;
        WSACleanup();
        return -1;
    } else {
        std::cout << "Create socket succeed" << std::endl;
    }
    //2.给socket绑定ip地址和端口号
    struct sockaddr_in server_addr;   //sockaddr_in, sockaddr  老版本和新版的区别
    server_addr.sin_family = AF_INET;  //和创建socket时必须一样
    server_addr.sin_port = htons(PORT);  //端口号  大端(高位)存储(本地)和小端(低位)存储(网络),两个存储顺序是反着的  htons 将本地字节序转为网络字节序
    server_addr.sin_addr.s_addr = INADDR_ANY;
    //3.绑定
    if (bind(s_server, (PSOCKADDR)&server_addr, sizeof(sockaddr_in)) == SOCKET_ERROR) {
        std::cout << "Bind failed" << std::endl;
        WSACleanup();
        return -1;
    } else {
        std::cout << "Bind succeed" << std::endl;
    }

    //4.设置套接字为监听状态  SOMAXCONN 监听的端口数
    if (listen(s_server, SOMAXCONN) < 0) {
        std::cout << "Listen failed" << std::endl;
        WSACleanup();
        return -1;
    } else {
        std::cout << "Listen succeed" << std::endl;
    }

    SOCKET s_client;
    std::cout << "Wait client connect..." << std::endl;
    struct sockaddr_in client_addr;
    int addr_len = sizeof (sockaddr_in);
    s_client = accept(s_server, (SOCKADDR*)&client_addr, &addr_len);
    if (s_client == INVALID_SOCKET) {
        std::cout << "Accept failed" << std::endl;
        WSACleanup();
        return -1;
    }

    char buf[BUFSIZ];
    ZeroMemory(buf, BUFSIZ);
    while (true) {
        int ret = recv(s_client, buf, BUFSIZ, 0);
        if (ret > 0){
            std::cout << "Recv from client: " << buf << std::endl;
        } else if (ret == 0) {
            std::cout << "s_client closed" << std::endl;
            closesocket(s_server);
            WSACleanup();
            return -1;
        } else {
            std::cout << "Recv failed: " << GetLastError() << std::endl;
            closesocket(s_server);
            closesocket(s_client);
            WSACleanup();
            return -1;
        }

        ret = send(s_client, buf, BUFSIZ, 0);
        if (SOCKET_ERROR != ret) {
            std::cout << "Send to client: " << buf << std::endl;
        } else {
            std::cout << "Send failed: " << GetLastError() << std::endl;
            closesocket(s_server);
            closesocket(s_client);
            WSACleanup();
            return -1;
        }
    }

    //关闭套接字
    closesocket(s_server);
    closesocket(s_client);
    //释放DLL资源
    WSACleanup();
    return 0;
}

二.客户端

// client.cpp
#include<iostream>
#include<winsock.h>   //windows平台的网络库头文件
#pragma comment(lib,"ws2_32.lib")   //库文件

#define PORT 5050
#define BUFSIZ 512

int main()
{
    //初始化套接字库
    //WSA  windows socket async  windows异步套接字
    //WSAStartup启动套接字 参数形式:WORD  WSADATA
    //parm1:请求的socket版本 2.2 2.1 1.0
    //parm2:传出参数
    WORD w_req = MAKEWORD(2, 2);//版本号
    WSADATA wsadata;
    //成功:WSAStartup函数返回零
    if (WSAStartup(w_req, &wsadata) != 0) {
        std::cout << "WSAStartup failed" << std::endl;
        return -1;
    } else {
        std::cout << "WSAStartup succeed" << std::endl;
    }

    //1.创建空的Socket
    //parm1:af 地址协议族 ipv4 ipv6
    //parm2:type 传输协议类型 流式套接字(SOCK_STREAM) 数据报
    //parm3protocl 使用具体的某个传输协议
    SOCKET c_client = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
    if (c_client == INVALID_SOCKET)
    {
        std::cout << "Create socket failed" << std::endl;
        WSACleanup();
        return -1;
    } else {
        std::cout << "Create socket succeed" << std::endl;
    }
    //2.给socket绑定ip地址和端口号
    struct sockaddr_in client_addr;   // sockaddr_in, sockaddr  老版本和新版的区别
    client_addr.sin_family = AF_INET;  // 和创建socket时必须一样
    client_addr.sin_port = htons(PORT);  // 端口号  大端(高位)存储(本地)和小端(低位)存储(网络),两个存储顺序是反着的  htons 将本地字节序转为网络字节序
    client_addr.sin_addr.S_un.S_addr = inet_addr("127.0.0.1"); //inet_addr将点分十进制的ip地址转为二进制
    //3.连接服务端
    if (connect(c_client, (PSOCKADDR)&client_addr, sizeof(sockaddr_in))== INVALID_SOCKET)
    {
        std::cout << "Connect failed" << std::endl;
        closesocket(c_client);
        WSACleanup();
        return -1;
    }
    else {
        std::cout << "Connect succeed" << std::endl;
    }

    char buf[BUFSIZ] ="Hello World";
    //发送,接收数据
    while (true) {
        int ret = send(c_client, buf, BUFSIZ, 0);
        if (SOCKET_ERROR != ret) {
            std::cout << "Send to server: " << buf << std::endl;
        } else {
            std::cout << "Send failed: " << GetLastError() << std::endl;
            closesocket(c_client);
            WSACleanup();
            return -1;
        }
        ret = recv(c_client, buf, BUFSIZ, 0);
        if (ret > 0){
            std::cout << "Recv from server: " << buf << std::endl;
        } else if (ret == 0) {
            std::cout << "c_client closed" << std::endl;
            closesocket(c_client);
            WSACleanup();
            return -1;
        } else {
            std::cout << "Recv failed: " << GetLastError() << std::endl;
            closesocket(c_client);
            WSACleanup();
            return -1;
        }
    }
    //关闭套接字
    closesocket(c_client);
    //释放DLL资源
    WSACleanup();
    return 0;
}

原文链接:https://blog.csdn.net/caoshangpa/article/details/78611048

  • 5
    点赞
  • 9
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

草上爬

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值