socket编程实现简单的TCP网络程序(下)

2023-11-20

socket编程实现简单的TCP网络程序(下)

1.封装TCP socket
#include <iostream>
#include <string>
#include <stdio.h>
#include <cassert>
#include <unistd.h>
#include <sys/socket.h>
#include <arpa/inet.h>
#include <netinet/in.h>

#define CHECK_RET(q) if(!(q)) {return false;}

class TcpSocket {
    public:
        TcpSocket() : _fd(-1) {}
        TcpSocket(int fd) :_fd(fd) {}
        ~TcpSocket(){}
        //绑定地址信息-IPV4协议,字节流传输
        bool Socket() {
            _fd = socket(AF_INET, SOCK_STREAM, 0);
            if (_fd < 0) {
                perror("socket error~~\n");
                return false;
            }
            return true;
        }
        //关闭套接字
        bool Close() {
            int ret = close(_fd);
            if (ret < 0) {
                perror("close error~~\n");
                return false;
            }
            return true;
        }
        //为套接字绑定地址信息,地址为一个通用的结构体sockaddr
        //结构体包含了协议类型,ip地址,port端口号
        bool Bind(std::string& ip, uint16_t port) {
            sockaddr_in addr;
            addr.sin_family = AF_INET;
            //inet_addr点分十进制字符串转换为网络ip(本质上是一个32字节数据)
            addr.sin_addr.s_addr = inet_addr(ip.c_str());
            //htons主机字节序转换为网络字节序
            addr.sin_port = htons(port);
            int ret = bind(_fd, (sockaddr*)&addr, sizeof(addr));
            if (ret < 0) {
                perror("bind error~~\n");
                return false;
            }
            return true;
        }
        //开始监听,num=5 最多允许5个客户端处于连接等待状态
        bool Listen(int num = 5) {
            int ret = listen(_fd, num);
            if (ret < 0) {
                perror("listen error~~\n");
                return false;
            }
            return true;
        }
        //监听套接字用于接受连接请求,建立连接后会accept返回一个新的套接字
        //这个套接字就是客户端建立的套接字,是真正用于进行通信的套接字
        //而监听套接字不用于进行通信
        //同时可以接收到对端的地址信息
        bool Accept(TcpSocket& peer, std::string* ip = nullptr, uint16_t* port = nullptr) {
            sockaddr_in addr;
            socklen_t len = sizeof(addr);
            int new_sock = accept(_fd, (sockaddr*)&addr, &len);
            if (new_sock < 0) {
                perror("accept error~~\n");
                return false;
            }
            peer._fd = new_sock;
            if (ip != nullptr) {
                *ip = inet_ntoa(addr.sin_addr);
            }
            if (port != nullptr) {
                *port = ntohs(addr.sin_port);
            }
            return true;
        }
        //请求建立连接,客户端使用
        bool Connect(std::string& ip, uint16_t port) {
            sockaddr_in addr;
            addr.sin_family = AF_INET;
            addr.sin_addr.s_addr = inet_addr(ip.c_str());
            addr.sin_port = htons(port);
            int ret = connect(_fd, (sockaddr*)&addr, sizeof(addr));
            if (ret < 0) {
                perror("connect error~~\n");
                return false;
            }
            return true;
        }
        //发送消息
        bool Send(std::string& buf) {
            int ret = send(_fd, buf.c_str(), buf.size(), 0);
            if (ret < 0) {
                perror("send error~~\n");
                return false;
            }
            return true;
        }
        //接收消息
        bool Recv(std::string& buf) {
            char tmp[1024*4] = {0};
            int len = recv(_fd, tmp, sizeof(tmp)-1, 0);
            if (len < 0) {
                perror("recv error~~\n");
                return false;
            }
            if (len == 0) {
                return false;
            }
            buf.assign(tmp, len);
            return true;
        }
        int GetFd() {
            return _fd;
        }
    private:
        int _fd;
};

2.TCP通用服务器
#include "tcp_socket.hpp"
#include <functional>

typedef std::function<void (const std::string& req, std::string& resp)> Handler;

class TcpServer {
    public:
        TcpServer(std::string& ip, uint16_t port)
            : _ip(ip)
            , _port(port)
        {}
        ~TcpServer() {}

        bool Start(Handler handler) {
            //1.创建套接字
            CHECK_RET(sock.Socket());
            //2.绑定地址信息
            CHECK_RET(sock.Bind(_ip, _port));
            //3.开始监听
            CHECK_RET(sock.Listen());
            //4.进入事件循环
            while (true) {
                //新的套接字,用于接受客户端的套接字
                TcpSocket new_sock;
                std::string ip;
                uint16_t port;
                //5.阻塞建立新连接
                if(!sock.Accept(new_sock, &ip, &port))
                    continue;
                printf("[ip-%s][port-%d] --> connect~~\n", ip.c_str(), port);
                
                //6.对新建立的连接循环读写
                while (true) {
                    //7.接收请求,失败跳出循环并且关闭新的连接
                    std::string req;
                    bool ret = new_sock.Recv(req);
                    if (!ret) {
                        printf("[ip-%s][port-%d] --> disconnect~~\n", ip.c_str(), port);
                        break;
                    }
                    std::cout << "请求:" << req << std::endl;

                    //8.计算响应
                    std::string resp;
                    handler(req, resp);

                    //9.发送响应
                    new_sock.Send(resp);
                }
                new_sock.Close();
            }
            return true;
        }
    private:
        TcpSocket sock;
        std::string _ip;
        uint16_t _port;
};

3.英译汉服务器
#include "tcp_socket.hpp"

class TcpClient {
    public:
        TcpClient(std::string& ip, uint16_t port) 
            : _ip(ip)
            , _port(port) {
            assert(sock.Socket());
        }
        ~TcpClient() {
            assert(sock.Close());
        }
        
        bool Connect() {
            return sock.Connect(_ip, _port);
        } 
        bool Recv(std::string& req) {
            return sock.Recv(req);
        }
        bool Send(std::string& resp) {
            return sock.Send(resp);
        }
    private:
        TcpSocket sock;
        std::string _ip;
        uint16_t _port;
};


4.TCP通用客户端
#include "tcp_server.hpp"
#include <unordered_map>

void Dict(const std::string& req, std::string& resp) {
    std::unordered_map<std::string, std::string> dic;
    dic.insert(std::make_pair("hello", "你好~~"));
    dic.insert(std::make_pair("world", "世界~~"));
    dic.insert(std::make_pair("shen", "珅~~"));
    if (dic.find(req) != dic.end()) {
        auto it = dic.find(req);
        resp = it->second;
    } else {
        resp = "未找到~~";
    }
}

// ./dict_server 127.0.0.1 9000
int main(int argc, char* argv[]) {
    if (argc != 3) {
        std::cout << "./dict_server 127.0.0.1 9000" << std::endl;
        return -1;
    }
    std::string ip = argv[1];
    uint16_t port = atoi(argv[2]);

    TcpServer server(ip, port);
    server.Start(Dict);
    
    return 0;
}

5.英译汉客户端
#include "tcp_client.hpp"

// ./dict_client 127.0.0.1 9000
int main(int argc, char* argv[]) {
    if (argc != 3) {
        std::cout << "./dict_client 127.0.0.1 9000" << std::endl;
        return -1;
    }
    std::string ip = argv[1];
    uint16_t port = atoi(argv[2]);

    TcpClient client(ip, port);
    client.Connect();
    
    while (true) {
        std::string req;
        std::cout << "请求:";
        std::cin >> req;
        client.Send(req);

        std::string resp;
        client.Recv(resp);
        std::cout << "响应:" << resp << std::endl;
    }
    return 0;
}

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

socket编程实现简单的TCP网络程序(下) 的相关文章

  • C++ 维护子类对象的混合集合

    如果我在这里错过了一个相当基本的概念 我很抱歉 但我正在尝试弄清楚如何维护多个类类型的集合 所有类类型都派生自同一个父类 并且在检索它们时仍然可以访问它们的特定于子类的方法从集合中 作为上下文 我有一个基类 BaseClass 和许多类 例
  • CLR 2.0 与 4.0 性能比较?

    如果在 CLR 4 0 下运行 为 CLR 2 0 编译的 NET 程序会运行得更快吗 应用程序配置
  • 计算 XML 中特定 XML 节点的数量

    请参阅此 XML
  • 适合初学者的良好调试器教程[关闭]

    Closed 这个问题不符合堆栈溢出指南 help closed questions 目前不接受答案 有谁知道一个好的初学者教程 在 C 中使用调试器 我感觉自己好像错过了很多 我知道怎么做 单步执行代码并查看局部变量 虽然这常常给我带来问
  • IdentityServer 4 对它的工作原理感到困惑

    我阅读和观看了很多有关 Identity Server 4 的内容 但我仍然对它有点困惑 因为似乎有很多移动部件 我现在明白这是一个单独的项目 它处理用户身份验证 我仍然不明白的是用户如何注册它 谁存储用户名 密码 我打算进行此设置 Rea
  • 如何判断计算机是否已重新启动?

    我曾经使用过一个命令行 SMTP 邮件程序 作为试用版的限制 它允许您在每个 Windows 会话中最多接收 10 封电子邮件 如果您重新启动计算机 您可能还会收到 10 个以上 我认为这种共享软件破坏非常巧妙 我想在我的应用程序中复制它
  • 函数参数的默认参数是否被视为该参数的初始值设定项?

    假设我有这样的函数声明 static const int R 0 static const int I 0 void f const int r R void g int i I 根据 dcl fct default 1 如果在参数声明中指
  • 为什么在 WebApi 上下文中在 using 块中使用 HttpClient 是错误的?

    那么 问题是为什么在 using 块中使用 HttpClient 是错误的 但在 WebApi 上下文中呢 我一直在读这篇文章不要阻止异步代码 https blog stephencleary com 2012 07 dont block
  • 查看 NuGet 包依赖关系层次结构

    有没有一种方法 文本或图形 来查看 NuGet 包之间的依赖关系层次结构 如果您使用的是新的 csproj 您可以在此处获取所有依赖项 在项目构建后 项目目录 obj project assets json
  • Python 属性和 Swig

    我正在尝试使用 swig 为一些 C 代码创建 python 绑定 我似乎遇到了一个问题 试图从我拥有的一些访问器函数创建 python 属性 方法如下 class Player public void entity Entity enti
  • 打破 ReadFile() 阻塞 - 命名管道 (Windows API)

    为了简化 这是一种命名管道服务器正在等待命名管道客户端写入管道的情况 使用 WriteFile 阻塞的 Windows API 是 ReadFile 服务器已创建启用阻塞的同步管道 无重叠 I O 客户端已连接 现在服务器正在等待一些数据
  • 为什么从字典中获取时会得到 Action<> 的克隆?

    我有以下字典 private Dictionary
  • C++ int 前面加 0 会改变整个值

    我有一个非常奇怪的问题 如果我像这样声明一个 int int time 0110 然后将其显示到控制台返回的值为72 但是当我删除前面的 0 时int time 110 然后控制台显示110正如预期的那样 我想知道两件事 首先 为什么它在
  • 等待 IAsyncResult 函数直至完成

    我需要创建等待 IAsyncResult 方法完成的机制 我怎样才能做到这一点 IAsyncResult result contactGroupServices BeginDeleteContact contactToRemove Uri
  • 检测到严重错误 c0000374 - C++ dll 将已分配内存的指针返回到 C#

    我有一个 c dll 它为我的主 c 应用程序提供一些功能 在这里 我尝试读取一个文件 将其加载到内存 然后返回一些信息 例如加载数据的指针和内存块的计数到 c Dll 成功将文件读取到内存 但在返回主应用程序时 程序由于堆损坏而崩溃 检测
  • 使 Guid 属性成为线程安全的

    我的一个类有一个 Guid 类型的属性 该属性可以由多个线程同时读写 我的印象是对 Guid 的读取和写入不是原子的 因此我应该锁定它们 我选择这样做 public Guid TestKey get lock testKeyLock ret
  • C++ new * char 不为空

    我有一个问题 我在 ASIO 中开发服务器 数据包采用尖头字符 当我创建新字符时 例如char buffer new char 128 我必须手动将其清理为空 By for int i 0 i lt 128 i buffer i 0x00
  • 将数组作为参数传递

    如果我们修改作为方法内参数传递的数组的内容 则修改是在参数的副本而不是原始参数上完成的 因此结果不可见 当我们调用具有引用类型参数的方法时 会发生什么过程 这是我想问的代码示例 using System namespace Value Re
  • 实体框架中的“it”是什么

    如果以前有人问过这个问题 请原谅我 但我的任何搜索中都没有出现 它 我有两个数据库表 Person 和 Employee 对每个类型的表进行建模 例如 Employee is a Person 在我的 edmx 设计器中 我定义了一个实体
  • Objective-C / C 给出枚举默认值

    我在某处读到过关于给枚举默认值的内容 如下所示 typedef enum MarketNavigationTypeNone 0 MarketNavigationTypeHeirachy 1 MarketNavigationTypeMarke

随机推荐