43. TCP -2实现英文查中文功能

🔥个人主页: Milestone-里程碑

❄️个人专栏: <<力扣hot100>> <<C++>><<Linux>>

🌟心向往之行必能至

上一篇文章,我们实现了基础的TCP的封装实现,本篇文章,我们将与前面的UDP一样,实现英文查中文的操作

一.引入Dict.hpp

bash 复制代码
#pragma once

#include <iostream>
#include <fstream>
#include <string>
#include <unordered_map>
#include "Log.hpp"
#include"InetAddr.hpp"
using namespace LogModule;
const std::string gap = ":";
const std::string defaultdictpath = "./word.txt";
class Dict
{
public:
    Dict() : _dict_path(defaultdictpath)
    {
    }
    bool LoadDict()
    {
        std::ifstream in(_dict_path);
        if (!in.is_open())
        {
            LOG(LogLevel::DEBUG) << "打开字典: " << _dict_path << " 错误";
            return false;
        }
        std::string line;
        while (std::getline(in, line))
        {
            auto pos = line.find(gap);
            if (pos == std::string ::npos)
            {
                LOG(LogLevel::WARNING) << "解析: " << line << " 失败";
                continue;
            }
            // 左闭右开
            std::string word = line.substr(0, pos);
            std::string chinaese = line.substr(pos + gap.size());
            if (word.empty() || chinaese.empty())
            {
                LOG(LogLevel::WARNING) << "没有有效数据 " << line;
                continue;
            }
            _dict.insert(std::make_pair(word, chinaese));
            LOG(LogLevel::DEBUG) << "加载: " << line;
        }
        in.close();
        return true;
    }
    std::string Translate(const std::string &word, InetAddr & client)
    {
        auto iter = _dict.find(word);
        if (iter == _dict.end())
        {
            // LOG(LogLevel::DEBUG) << "word ";
             LOG(LogLevel::DEBUG) << "进入到了翻译模块, [" << client.IP() << " : " << client.PORT() << "]# " << word << "->None";
            return "None";
        }
        return iter->second;
    }
    ~Dict() {}

private:
    std::string _dict_path; // 默认路径
    std::unordered_map<std::string, std::string> _dict;
};

TcpClient.cc

bash 复制代码
#include <iostream>
#include "Common.hpp"
#include "Log.hpp"
#include "InetAddr.hpp"
using namespace LogModule;
int main(int args, char *argv[])
{
    if (args != 3)
    {
        LOG(LogLevel::ERROR) << "USAG" << argv[0] << " ip port";
        exit(usgv_err);
    }
    std::string ip = argv[1];
    uint16_t port = std::stoi(argv[2]);
    // 1.创建套接字
    int sockfd = socket(AF_INET, SOCK_STREAM, 0);
    if (sockfd < 0)
    {
        LOG(LogLevel::ERROR) << "sockfd error";
        exit(socket_err);
    }
    LOG(LogLevel::DEBUG) << "sockfd success";
    // 无需显示绑定,系统随随机绑定端口号
    //  2. 我应该做什么呢?listen?accept?都不需要!!
    //  2. 直接向目标服务器发起建立连接的请求
    InetAddr serveraddr(ip, port);
    int n = connect(sockfd, serveraddr.NetAddrPtr(), serveraddr.NetAddrLen());
    if (n < 0)
    {
        LOG(LogLevel::ERROR) << "connect fail";
        exit(connect_err);
    }
    LOG(LogLevel::DEBUG) << "connect success";

    while (true)
    {
        // 1.写P
        LOG(LogLevel::DEBUG) << "Please input#";
        std::string line;
        std::getline(std::cin, line);
        ssize_t n = write(sockfd, line.c_str(), line.size());

        // 2.读
        char buf[1024];
        n = read(sockfd, buf, sizeof(buf) - 1);
        if (n > 0)
        {
            buf[n] = 0;
            LOG(LogLevel::INFO) << "server echo#" << buf;
        }
    }
    return 0;
}

三.TcpServer.cc

bash 复制代码
#include"TcpServer.hpp"
#include<iostream>
int main(int args,char*argv[])
{
    if(args!=2)
    {
        std::cout<<"USGR: "<<argv[0]<<"port";
        exit(usgv_err);
    }
    uint16_t port=std::stoi(argv[1]);
    std::unique_ptr<TcpServer> tcp=std::make_unique<TcpServer>(port);
    tcp->Init();
    tcp->Start();
     return 0;
}   

四.TcpServer.hpp

bash 复制代码
#pragma once
#include <sys/types.h>
#include <unistd.h>
#include <wait.h>
#include <signal.h>
#include <pthread.h>
#include<functional>
#include "InetAddr.hpp"
#include "Common.hpp"
#include "Log.hpp"
#include"ThreadPool.hpp"
using namespace LogModule;
using namespace ThreadPoolModule;
const int defaultsocket = -1;
using task_t=std::function<void()>;
class TcpServer : public NoCopy // 服务器不可拷贝
{
public:
    TcpServer(uint16_t &port)
        : _listensocket(defaultsocket), _port(port), _isrunning(false)
    {
    }
    void Init()
    {
        // signal(SIGCHLD, SIG_IGN); // 忽略SIG_IGN信号
        // 1.创建套接字
        _listensocket = socket(AF_INET, SOCK_STREAM, 0);
        if (_listensocket < 0)
        {
            LOG(LogLevel::ERROR) << "socket fail";
            exit(socket_err);
        }
        LOG(LogLevel::INFO) << "socket success" << _listensocket;
        // 2. bind
        InetAddr local(_port);
        int n = bind(_listensocket, local.NetAddrPtr(), local.NetAddrLen());
        if (n < 0)
        {
            LOG(LogLevel::ERROR) << "bind fail" << _listensocket;
            exit(bind_err);
        }
        LOG(LogLevel::INFO) << "bind success" << _listensocket;
        // 进行监听
        int backlog = 5;
        n = listen(_listensocket, backlog);
        if (n < 0)
        {
            LOG(LogLevel::ERROR) << "listen fail" << _listensocket;
            exit(listen_err);
        }
        LOG(LogLevel::INFO) << "listen success" << _listensocket;
    }
    class ThreadData
    {
    public:
        ThreadData(int fd, InetAddr &ar, TcpServer *s) : sockfd(fd), addr(ar), tsvr(s) {}

    public:
        int sockfd;
        InetAddr addr;
        TcpServer *tsvr;
    };
    static void *Rotinue(void *argv)
    {
        ThreadData *td = static_cast<ThreadData *>(argv);
        // 脱离主线程
        pthread_detach(pthread_self());
        td->tsvr->Service(td->sockfd, td->addr);
        delete td;
        return nullptr;
    }
    // 短服务
    // 长服务: 多进程多线程比较合适
    void Service(int sockfd, InetAddr &peer)
    {
        // 1. 先读取数据
        // a. n>0: 读取成功
        // b. n<0: 读取失败
        // c. n==0: 对端把链接关闭了,读到了文件的结尾 --- pipe
        char buf[1024];

        while (true)
        {
            ssize_t n = read(sockfd, buf, sizeof(buf) - 1);
            if (n < 0)
            {
                LOG(LogLevel::ERROR) << "read fail";
                close(sockfd);
                exit(read_err);
            }
            else if (n == 0)
            {
                LOG(LogLevel::DEBUG) << peer.StringAddr() << "exit ";
                close(sockfd);
                break;
            }
            else
            {
                buf[n] = 0;
                LOG(LogLevel::INFO) << peer.StringAddr() << " #" << buf;
                std::string echo_string = "echo# ";
                write(sockfd, echo_string.c_str(), echo_string.size());
            }
        }
    }
    void Start()
    {
        _isrunning = true;
        while (_isrunning)
        {
            // a. 获取链接
            struct sockaddr_in peer;
            socklen_t len = sizeof(sockaddr_in);
            // 如果没有连接,accept就会阻塞
            int sockfd = accept(_listensocket, CONV(peer), &len);
            if (sockfd < 0)
            {
                LOG(LogLevel::WARNING) << "accept error";
                continue;
            }
            InetAddr addr(peer);
            LOG(LogLevel::INFO) << "accept success, peer addr : " << addr.StringAddr();
            // version0 -- text version 单线程版本
            //  Service(sockfd, addr);
            // version1 -- 多线程版本
            // pid_t id = fork();
            // if (id < 0)
            // {
            //     LOG(LogLevel::ERROR) << "fork fail";
            //     exit(fork_err);
            // }
            // // 父与子都关闭不需要的端口
            // else if (id == 0)
            // {
            //     close(_listensocket);
            //     if(fork()>0)
            //         exit(OK);
            //         //孙子进程
            //     Service(sockfd, addr);
            //     exit(OK);
            // }
            // else
            // {
            //     close(sockfd);
            //     pid_t rid = waitpid(id, nullptr, 0);
            //     (void)rid;
            //     //父进程要等待子进程,要不然僵尸,但等待与之前的一样,等于没处理
            //     //解决方法:
            //     //1. 设置为非阻塞状态,不推荐
            //     //2. 自定义信号(不够优雅)
            //     //3.  利用子进程创建一个孙进程,让子进程退出,孙进程就成了孤儿进程,由系统领养
            // }
            // version 2 ---多线程版本
            // ThreadData *td = new ThreadData(sockfd, addr, this);
            // pthread_t tid;
            // pthread_create(&tid, nullptr, Rotinue, td);
            //version 3 --线程池版本,一般适合处理短服务
            // 将新链接和客户端构建一个新任务,push线程池中  
            ThreadPool<task_t>::GetInstance()->Enqueue([this,sockfd,&addr]
            (){
                this->Service(sockfd,addr);
            });
        }
        _isrunning = false;
    }
    ~TcpServer() {}

private:
    int _listensocket; // 监听socket
    uint16_t _port;
    bool _isrunning;
};

五.总结

有前面造的轮子,此处增加这一个功能,基本上都是CV

CV的快乐

相关推荐
千里马-horse2 小时前
ubuntu 电脑安装protoc-gen-grpc-kotlin
linux·运维·ubuntu
柯儿的天空2 小时前
【OpenClaw 全面解析:从零到精通】第 004 篇:OpenClaw 在 Linux/Ubuntu 上的安装与部署实战
linux·人工智能·ubuntu·elasticsearch·知识图谱
从零点2 小时前
ubuntu网络没有WiFi怎么办?网络配置解决步骤
linux·服务器·网络
计算机与认知2 小时前
Linux Device Link机制
java·linux·服务器
代码探秘者2 小时前
【算法篇】1.双指针
java·数据结构·人工智能·后端·python·算法
bugu___2 小时前
Linux系统易错点
linux
你这个代码我看不懂2 小时前
Java软引用对象的创建以及对象回收
java·开发语言
qq_417695052 小时前
C++中的中介者模式
开发语言·c++·算法
xiangpanf2 小时前
PHP爬虫框架:Goutte vs Panther
开发语言·c++·vue.js·php