Linux网络-使用Tcp协议进行网络通信并通过网络接口实现远端翻译

文章目录

  • Tcp协议
  • Tcp协议常见API接口
    • 1. int socket(int domain, int type, int protocol);
    • 2. int bind(int socket, const struct sockaddr *address, socklen_t address_len);
      • struct sockaddr
    • 3. int listen(int socket, int backlog);
    • 4. int accept(int socket, struct sockaddr *restrict address,socklen_t *restrict address_len);
    • 5.int connect(int socket, const struct sockaddr *address,socklen_t address_len);
  • telnet通信
  • 服务器代码
    • 1. 单进程版本
    • 2.多进程版本
    • 3.多线程版本
    • 4. 线程池版本(附加字典功能)
      • Main.cc
      • TcpServer.cpp
      • ThreadPool.hpp
      • Task.hpp
      • log.hpp
      • dictionary.hpp
      • dictionary.txt 字典文本(简易)
  • 客户端代码
  • 翻译效果图

Tcp协议

简单了解一下Tcp协议,他与Udp协议都是传输层协议,而他与Udp协议的区别就是Tcp是有连接、可靠传输并且是面向字节流的一种协议。

Tcp协议常见API接口

前两个接口与Udp协议用法一样,只不过将申请套接字的SOCK_DGRAM改为了面向字节流的SOCK_STREAM。

1. int socket(int domain, int type, int protocol);

创建 socket 文件描述符 (TCP/UDP, 客户端 + 服务器)

参数 int domin :指定要在其中创建套接字的通信域。这里我们使用AF_INET采用IPV4通信域。

参数 int type : 指定要创建的套接字类型。 Tcp协议是采用面向字节流,所以是用SOCK_STREAM。

参数 int protocol :指定与套接字一起使用的特定协议。

返回值: 如果成功则返回创建的socket 文件描述符, 失败则返回-1.

代码示例

		int socket_fd = socket(AF_INET, SOCK_STREAM, 0);
        if (socket_fd == -1)
        {
            exit(1);
        }

2. int bind(int socket, const struct sockaddr *address, socklen_t address_len);

绑定端口号 (TCP/UDP, 服务器)
参数 int socket 就是使用socket接口函数所创建的那个socket文件描述符。

struct sockaddr

在这里插入图片描述
由于底层有不同的网络协议,所以它们的地址格式并不相同,所以通常使用struct sockaddr* 作为参数,然后根据前16位地址类型来确定协议内容。

参数 socklen_t address_len, 结构体sockaddr的长度。
typedef unsigned int socklen_t

返回值: 如果绑定成功则返回0, 失败则返回-1.

代码示例

		int socket_fd = socket(AF_INET, SOCK_STREAN, 0);
        if (socket_fd == -1)
        {
            exit(1);
        }
        struct sockaddr_in Server;
        bzero(&Server, 0);
        Server.sin_family = AF_INET;
        Server.sin_addr.s_addr = inet_addr(_ip.c_str()); //?
        Server.sin_port = htons(_port); //?

        int n = bind( socket_fd, (const struct sockaddr *)&Server, sizeof(Server));
        if (n != 0)
        {
            exit(2);
        }

3. int listen(int socket, int backlog);

作用:将参数socket套接字用于监听,使其处于listen状态。
参数 backlog 这里暂时不讲,将其设为10左右即可。
返回值:成功则为0,失败则为-1。

代码示例

		int sock = socket(AF_INET, SOCK_STREAM, 0);
        if (sock == -1)
        {
            logMessage(FATAL, "socket create failed...");
            exit(1);
        }
        logMessage(DEBUG, "socket create succeess...");

        _listensock = sock;

        // bind套接字
        struct sockaddr_in local;
        memset(&local, 0, sizeof local);
        local.sin_family = AF_INET;
        inet_aton(_server_ip.c_str(), &local.sin_addr);
        local.sin_port = htons(_server_port);
        if (bind(_listensock, (const sockaddr *)&local, (socklen_t)sizeof(local)) == -1)
        {
            logMessage(FATAL, "bind failed..., error:%s", strerror(errno));
            exit(2);
        }
        logMessage(DEBUG, "bind succeess...");

        // listen begin
        if (listen(_listensock, backlog) < 0)
        {
            logMessage(FATAL, "listen failed...");
            exit(3);
        }

4. int accept(int socket, struct sockaddr *restrict address,socklen_t *restrict address_len);

作用:处于listen状态的网络套接字将持续监听是否有其他网络套接字对本套接字进行链接,该接口函数会阻塞,直到有套接字进行链接,链接成功后将返回一个文件描述符

参数socket:处于listen状态的网络套接字。

参数struct sockaddr *restrict address: 输出型函数,用于保存远端主机的套接字信息。

参数socklen_t *restrict address_len: 输出型参数,用于保存远端主机的套接字的长度。

返回值:成功链接返回一个文件描述符,可对它进行读写操作,失败则返回-1。

5.int connect(int socket, const struct sockaddr *address,socklen_t address_len);

对目标网络套接字发送连接请求,一般适用于客户端去连接服务器。
参数 socket: 本地申请的套接字。
参数const struct sockaddr *address:目标网络套接字的struct sockaddr。
参数socklen_t address_len: 目标网络套接字的struct sockaddr的长度。


telnet通信

telnet是linux中可安装的程序,它是一种基于Tcp协议通信的程序,我们可以使用它来对我们的服务器进行测试。

终端输入该命令

telnet ip[xxx.xxx.xxx.xxx] port[1024+]

如果出现找不到该命令,则是因为你的linux主机没有安装telnet

输入
sudo yum install telnet
安装telnet


使用示例
telnet 127.0.0.1 8888

服务器代码

1. 单进程版本

// version 1 单进程单线程版
#include <iostream>
#include <sys/socket.h>
#include <sys/types.h>
#include <string>
#include <arpa/inet.h>
#include <stdlib.h>
#include <unistd.h>
#include "log.hpp"
#include <netinet/in.h>
#include <string.h>

const std::string default_ip = "0.0.0.0";
const uint16_t default_port = 8888;
const int backlog = 10;

std::string messageHandle(const std::string &ip, uint16_t port, const std::string &message)
{
    time_t now = time(nullptr);
    struct tm *lt = localtime(&now);
    std::cout << lt->tm_hour << ":" << lt->tm_min << "[" << ip << ":" << port << "]: "
              << message << std::endl;
    return message;
}
class TcpServer
{
public:
    TcpServer(uint16_t port = default_port, std::string ip = default_ip)
        : _listensock(-1), _server_ip(ip), _server_port(port)
    {
    }

    void Init()
    {
        // 申请套接字
        int sock = socket(AF_INET, SOCK_STREAM, 0);
        if (sock == -1)
        {
            logMessage(FATAL, "socket create failed...");
            exit(1);
        }
        logMessage(DEBUG, "socket create succeess...");

        _listensock = sock;

        // bind套接字
        struct sockaddr_in local;
        memset(&local, 0, sizeof local);
        local.sin_family = AF_INET;
        inet_aton(_server_ip.c_str(), &local.sin_addr);
        local.sin_port = htons(_server_port);
        if (bind(_listensock, (const sockaddr *)&local, (socklen_t)sizeof(local)) == -1)
        {
            logMessage(FATAL, "bind failed..., error:%s", strerror(errno));
            exit(2);
        }
        logMessage(DEBUG, "bind succeess...");

        // listen begin
        if (listen(_listensock, backlog) < 0)
        {
            logMessage(FATAL, "listen failed...");
            exit(3);
        }
        logMessage(DEBUG, "listen succeess...");
    }

    void run()
    {
        struct sockaddr_in client;
        socklen_t len;
        while (true)
        {
            memset(&client, 0, sizeof client);
            int socketfd = accept(_listensock, (struct sockaddr *)&client, &len);
            if (socketfd < 0)
            {
                logMessage(WARNING, "accept failed...");
                continue;
            }
            logMessage(DEBUG, "accept success..., and get a link, socketfd: %d", socketfd);
            service(socketfd, client);
        }
    }

    void service(const int socketfd, const struct sockaddr_in client)
    {
        uint16_t client_port = ntohs(client.sin_port);
        char ip_buffer[32];
        inet_ntop(AF_INET, (const void *)&client.sin_addr, ip_buffer, sizeof client);
        std::string cilent_ip = ip_buffer;

        // 开始接收消息

        char buffer[1024];
        while (true)
        {
            memset(buffer, 0, sizeof buffer);
            int n = read(socketfd, buffer, sizeof buffer - 1);
            if (n == 0)
            {
                logMessage(WARNING, "socketfd[%d] closed...", socketfd);
                break;
            }
            else if (n < 0)
            {
                logMessage(WARNING, "read erro, socketfd[%d]...");
                break;
            }
            if (buffer[n - 1] == '\n')
            {
                // 使用telnet通信
                //std::cout << "发现\\n" << std::endl;
                buffer[n - 2] = 0;
            }
            else
            {
                // 使用客户端通信
                buffer[n] = 0;
            }
            std::string info = messageHandle(cilent_ip, client_port, buffer);
            write(socketfd, info.c_str(), info.size());
        }
        close(socketfd);
        logMessage(DEBUG, "socketfd: %d closed...", socketfd);
    }

private:
    int _listensock;
    std::string _server_ip;
    uint16_t _server_port;
};

该版本缺陷很明显,没办法同时处理多个客户端的数据请求。


2.多进程版本

// version 2 多进程版
#include <iostream>
#include <sys/socket.h>
#include <sys/types.h>
#include <string>
#include <arpa/inet.h>
#include <stdlib.h>
#include <unistd.h>
#include "log.hpp"
#include <netinet/in.h>
#include <string.h>
#include <wait.h>
const std::string default_ip = "0.0.0.0";
const uint16_t default_port = 8888;
const int backlog = 10;

std::string messageHandle(const std::string &ip, uint16_t port, const std::string &message)
{
    time_t now = time(nullptr);
    struct tm *lt = localtime(&now);
    std::cout << lt->tm_hour << ":" << lt->tm_min << "[" << ip << ":" << port << "]: "
              << message << std::endl;
    return message;
}
class TcpServer
{
public:
    TcpServer(uint16_t port = default_port, std::string ip = default_ip)
        : _listensock(-1), _server_ip(ip), _server_port(port)
    {
    }

    void Init()
    {
        // 申请套接字
        int sock = socket(AF_INET, SOCK_STREAM, 0);
        if (sock == -1)
        {
            logMessage(FATAL, "socket create failed...");
            exit(1);
        }
        logMessage(DEBUG, "socket create succeess...");

        _listensock = sock;

        // bind套接字
        struct sockaddr_in local;
        memset(&local, 0, sizeof local);
        local.sin_family = AF_INET;
        inet_aton(_server_ip.c_str(), &local.sin_addr);
        local.sin_port = htons(_server_port);
        if (bind(_listensock, (const sockaddr *)&local, (socklen_t)sizeof(local)) == -1)
        {
            logMessage(FATAL, "bind failed..., error:%s", strerror(errno));
            exit(2);
        }
        logMessage(DEBUG, "bind succeess...");

        // listen begin
        if (listen(_listensock, backlog) < 0)
        {
            logMessage(FATAL, "listen failed...");
            exit(3);
        }
        logMessage(DEBUG, "listen succeess...");
    }

    void run()
    {
        struct sockaddr_in client;
        socklen_t len;
        while (true)
        {
            memset(&client, 0, sizeof client);
            int socketfd = accept(_listensock, (struct sockaddr *)&client, &len);
            if (socketfd < 0)
            {
                logMessage(WARNING, "accept failed...");
                continue;
            }
            logMessage(DEBUG, "accept success..., and get a link, socketfd: %d", socketfd);
            int pid = fork();
            if (pid == 0)
            {
                if (fork())
                {
                    // 子进程退出 这样我们的父进程就不需要等service函数执行完才waitpid
                    exit(0);
                }
                // 孙子进程
                close(_listensock);
                service(socketfd, client);
                exit(0);
            }
            // 父进程
            close(socketfd);
            waitpid(pid, nullptr, 0);
        }
    }

    void service(const int socketfd, const struct sockaddr_in client)
    {
        uint16_t client_port = ntohs(client.sin_port);
        char ip_buffer[32];
        inet_ntop(AF_INET, (const void *)&client.sin_addr, ip_buffer, sizeof client);
        std::string cilent_ip = ip_buffer;

        // 开始接收消息

        char buffer[1024];
        while (true)
        {
            memset(buffer, 0, sizeof buffer);
            int n = read(socketfd, buffer, sizeof buffer - 1);
            if (n == 0)
            {
                logMessage(WARNING, "socketfd[%d] closed...", socketfd);
                break;
            }
            else if (n < 0)
            {
                logMessage(WARNING, "read erro, socketfd[%d]...");
                break;
            }
            if (buffer[n - 1] == '\n')
            {
                // 使用telnet通信
                // std::cout << "发现\\n" << std::endl;
                buffer[n - 2] = 0;
            }
            else
            {
                // 使用客户端通信
                buffer[n] = 0;
            }
            std::string info = messageHandle(cilent_ip, client_port, buffer);
            write(socketfd, info.c_str(), info.size());
        }
        close(socketfd);
        logMessage(DEBUG, "socketfd: %d closed...", socketfd);
    }

private:
    int _listensock;
    std::string _server_ip;
    uint16_t _server_port;
};

缺陷是多进程需要维护的系统资源较多,连接的客户端稍微多点就不行了,简而言之就是多进程占用太大。


3.多线程版本

// version 3 多线程版
#include <iostream>
#include <sys/socket.h>
#include <sys/types.h>
#include <string>
#include <arpa/inet.h>
#include <stdlib.h>
#include <unistd.h>
#include "log.hpp"
#include <netinet/in.h>
#include <string.h>
#include <pthread.h>

const std::string default_ip = "0.0.0.0";
const uint16_t default_port = 8888;
const int backlog = 10;

std::string messageHandle(const std::string &ip, uint16_t port, const std::string &message)
{
    time_t now = time(nullptr);
    struct tm *lt = localtime(&now);
    std::cout << lt->tm_hour << ":" << lt->tm_min << "[" << ip << ":" << port << "]: "
              << message << std::endl;
    return message;
}
class TcpServer;

class ThreadData
{
public:
    ThreadData(int fd, struct sockaddr_in client)
        : _socketfd(fd), _client(client)
    {
    }

    int _socketfd;
    struct sockaddr_in _client;
};
class TcpServer
{
public:
    TcpServer(uint16_t port = default_port, std::string ip = default_ip)
        : _listensock(-1), _server_ip(ip), _server_port(port)
    {
    }

    void Init()
    {
        // 申请套接字
        int sock = socket(AF_INET, SOCK_STREAM, 0);
        if (sock == -1)
        {
            logMessage(FATAL, "socket create failed...");
            exit(1);
        }
        logMessage(DEBUG, "socket create succeess...");

        _listensock = sock;

        // bind套接字
        struct sockaddr_in local;
        memset(&local, 0, sizeof local);
        local.sin_family = AF_INET;
        inet_aton(_server_ip.c_str(), &local.sin_addr);
        local.sin_port = htons(_server_port);
        if (bind(_listensock, (const sockaddr *)&local, (socklen_t)sizeof(local)) == -1)
        {
            logMessage(FATAL, "bind failed..., error:%s", strerror(errno));
            exit(2);
        }
        logMessage(DEBUG, "bind succeess...");

        // listen begin
        if (listen(_listensock, backlog) < 0)
        {
            logMessage(FATAL, "listen failed...");
            exit(3);
        }
        logMessage(DEBUG, "listen succeess...");
    }

    void run()
    {
        struct sockaddr_in client;
        socklen_t len;
        while (true)
        {
            memset(&client, 0, sizeof client);
            int socketfd = accept(_listensock, (struct sockaddr *)&client, &len);
            if (socketfd < 0)
            {
                logMessage(WARNING, "accept failed...");
                continue;
            }
            logMessage(DEBUG, "accept success..., and get a link, socketfd: %d", socketfd);
            ThreadData *td = new ThreadData(socketfd, client);
            pthread_t tid;
            pthread_create(&tid, nullptr, service, (void *)td);
        }
    }

    static void *service(void *args)
    {
        pthread_detach(pthread_self());
        ThreadData *td = static_cast<ThreadData *>(args);
        uint16_t client_port = ntohs(td->_client.sin_port);
        char ip_buffer[32];
        inet_ntop(AF_INET, (const void *)&(td->_client.sin_addr), ip_buffer, sizeof(td->_client));
        std::string cilent_ip = ip_buffer;

        // 开始接收消息

        char buffer[1024];
        while (true)
        {
            memset(buffer, 0, sizeof buffer);
            int n = read(td->_socketfd, buffer, sizeof buffer - 1);
            if (n == 0)
            {
                logMessage(WARNING, "socketfd[%d] closed...", td->_socketfd);
                break;
            }
            else if (n < 0)
            {
                logMessage(WARNING, "read erro, socketfd[%d]...");
                break;
            }
            if (buffer[n - 1] == '\n')
            {
                // 使用telnet通信
                // std::cout << "发现\\n" << std::endl;
                buffer[n - 2] = 0;
            }
            else
            {
                // 使用客户端通信
                buffer[n] = 0;
            }
            std::string info = messageHandle(cilent_ip, client_port, buffer);
            write(td->_socketfd, info.c_str(), info.size());
        }
        delete td;
        return nullptr;
    }

private:
    int _listensock;
    std::string _server_ip;
    uint16_t _server_port;
};

相对多进程版本,系统资源维护成本没那么大,也算一种不错的方案。


4. 线程池版本(附加字典功能)

Main.cc

#include <iostream>
#include "TcpServer.hpp"
#include "threadPool.hpp"
#include "Task.hpp"
void Usage(std::string proc)
{
    std::cout << "\n\rUsage: " << proc << " port[8888-9000]\n"
              << std::endl;
}

//多线程版Main
 int main(int argc, char* argv[])
 {
     if(argc != 2)
     {
         Usage("./TcpServer");
         return 1;
     }
     int port = atoi(argv[1]);
     TcpServer ts(port);
     ts.Init();
     ts.run();
     return 0;
 }

TcpServer.cpp

                 //TcpServer.cpp
// version 4 线程池版
#include <iostream>
#include <sys/socket.h>
#include <sys/types.h>
#include <string>
#include <arpa/inet.h>
#include <stdlib.h>
#include <unistd.h>
#include "log.hpp"
#include <netinet/in.h>
#include <string.h>
#include <pthread.h>
#include "threadPool.hpp"
#include "Task.hpp"

const std::string default_ip = "0.0.0.0";
const uint16_t default_port = 8888;
const int backlog = 10;

std::string messageHandle(const std::string &ip, uint16_t port, const std::string &message)
{
    time_t now = time(nullptr);
    struct tm *lt = localtime(&now);
    std::cout << lt->tm_hour << ":" << lt->tm_min << "[" << ip << ":" << port << "]: "
              << message << std::endl;
    return message;
}
class TcpServer;

class TcpServer
{
public:
    TcpServer(uint16_t port = default_port, std::string ip = default_ip)
        : _listensock(-1), _server_ip(ip), _server_port(port)
    {
    }

    void Init()
    {
        // 申请套接字
        int sock = socket(AF_INET, SOCK_STREAM, 0);
        if (sock == -1)
        {
            logMessage(FATAL, "socket create failed...");
            exit(1);
        }
        logMessage(DEBUG, "socket create succeess...");

        _listensock = sock;

        // bind套接字
        struct sockaddr_in local;
        memset(&local, 0, sizeof local);
        local.sin_family = AF_INET;
        inet_aton(_server_ip.c_str(), &local.sin_addr);
        local.sin_port = htons(_server_port);
        if (bind(_listensock, (const sockaddr *)&local, (socklen_t)sizeof(local)) == -1)
        {
            logMessage(FATAL, "bind failed..., error:%s", strerror(errno));
            exit(2);
        }
        logMessage(DEBUG, "bind succeess...");

        // listen begin
        if (listen(_listensock, backlog) < 0)
        {
            logMessage(FATAL, "listen failed...");
            exit(3);
        }
        logMessage(DEBUG, "listen succeess...");
    }

    void run()
    {
        struct sockaddr_in client;
        socklen_t len;
        ThreadPool<Task>::GetInstance()->Start();
        while (true)
        {
            memset(&client, 0, sizeof client);
            int socketfd = accept(_listensock, (struct sockaddr *)&client, &len);
            if (socketfd < 0)
            {
                logMessage(WARNING, "accept failed...");
                continue;
            }
            logMessage(NORMAL, "accept success..., and get a link, socketfd: %d", socketfd);
            ThreadPool<Task> *threadpool = ThreadPool<Task>::GetInstance();
            threadpool->Push(Task(socketfd, client));
        }
    }

private:
    int _listensock;
    std::string _server_ip;
    uint16_t _server_port;
};

ThreadPool.hpp

#pragma once

#include <iostream>
#include <vector>
#include <string>
#include <queue>
#include <pthread.h>
#include <unistd.h>

struct ThreadInfo
{
    pthread_t tid;
    std::string name;
};

static const int defalutnum = 10;

template <class T>
class ThreadPool
{
public:
    void Lock()
    {
        pthread_mutex_lock(&mutex_);
    }
    void Unlock()
    {
        pthread_mutex_unlock(&mutex_);
    }
    void Wakeup()
    {
        pthread_cond_signal(&cond_);
    }
    void ThreadSleep()
    {
        pthread_cond_wait(&cond_, &mutex_);
    }
    bool IsQueueEmpty()
    {
        return tasks_.empty();
    }
    std::string GetThreadName(pthread_t tid)
    {
        for (const auto &ti : threads_)
        {
            if (ti.tid == tid)
                return ti.name;
        }
        return "None";
    }

public:
    static void *HandlerTask(void *args)
    {
        ThreadPool<T> *tp = static_cast<ThreadPool<T> *>(args);
        std::string name = tp->GetThreadName(pthread_self());
        while (true)
        {
            tp->Lock();

            while (tp->IsQueueEmpty())
            {
                tp->ThreadSleep();
            }
            T t = tp->Pop();
            tp->Unlock();

            t();
        }
    }
    void Start()
    {
        int num = threads_.size();
        for (int i = 0; i < num; i++)
        {
            threads_[i].name = "thread-" + std::to_string(i + 1);
            pthread_create(&(threads_[i].tid), nullptr, HandlerTask, this);
        }
    }
    T Pop()
    {
        T t = tasks_.front();
        tasks_.pop();
        return t;
    }
    void Push(const T &t)
    {
        Lock();
        tasks_.push(t);
        Wakeup();
        Unlock();
    }
    static ThreadPool<T> *GetInstance()
    {
        if (nullptr == tp_) // ???
        {
            pthread_mutex_lock(&lock_);
            if (nullptr == tp_)
            {
                // std::cout << "log: singleton create done first!" << std::endl;
                tp_ = new ThreadPool<T>();
            }
            pthread_mutex_unlock(&lock_);
        }

        return tp_;
    }

private:
    ThreadPool(int num = defalutnum) : threads_(num)
    {
        pthread_mutex_init(&mutex_, nullptr);
        pthread_cond_init(&cond_, nullptr);
    }
    ~ThreadPool()
    {
        pthread_mutex_destroy(&mutex_);
        pthread_cond_destroy(&cond_);
    }
    ThreadPool(const ThreadPool<T> &) = delete;
    const ThreadPool<T> &operator=(const ThreadPool<T> &) = delete; // a=b=c
private:
    std::vector<ThreadInfo> threads_;
    std::queue<T> tasks_;

    pthread_mutex_t mutex_;
    pthread_cond_t cond_;

    static ThreadPool<T> *tp_;
    static pthread_mutex_t lock_;
};

template <class T>
ThreadPool<T> *ThreadPool<T>::tp_ = nullptr;

template <class T>
pthread_mutex_t ThreadPool<T>::lock_ = PTHREAD_MUTEX_INITIALIZER;

Task.hpp

#pragma once
#include <functional>
#include <iostream>
#include <sys/socket.h>
#include <sys/types.h>
#include <netinet/in.h>
#include "dictionary.hpp"

Dictionary dictionary;
class Task
{
public:
    Task()
    {
    }

    Task(int socketfd, const struct sockaddr_in client)
        : _socketfd(socketfd), _client(client)
    {
    }
    void operator()()
    {
        char key_word[64];
        while (true)
        {
            memset(key_word, 0, sizeof key_word);
            int n = read(_socketfd, key_word, sizeof key_word - 1);
            if (n == 0)
            {
                logMessage(NORMAL, "Connection closed by foreign host, socketfd[%d] closed...", _socketfd);
                break;
            }
            else if (n < 0)
            {
                logMessage(WARNING, "read erro, socketfd[%d]...");
                break;
            }
            if (key_word[n - 1] == '\n')
            {
                // 使用telnet通信
                logMessage(DEBUG, "find \\n, telnet connection...");
                key_word[n - 2] = 0;
            }
            else
            {
                // 使用客户端通信
                key_word[n] = 0;
            }
            std::string value_word = dictionary.translate(key_word);
            write(_socketfd, value_word.c_str(), value_word.size());
        }
        close(_socketfd);
        logMessage(DEBUG, "socketfd[%d] closed...", _socketfd);
    }

private:
    int _socketfd;
    struct sockaddr_in _client;
};

log.hpp

#pragma once
#include <iostream>
#include <stdarg.h>
#include <string>
#include <time.h>
const char *levels[] = {
    "NORMAL",
    "WARNING",
    "ERROR",
    "FATAL",
    "DEBUG"};

#define NORMAL 0
#define WARNING 1
#define ERROR 2
#define FATAL 3
#define DEBUG 4

void logMessage(int level, const char *format, ...)
{
#ifndef debug
    if (level == DEBUG)
    {
        return;
    }
#endif
    char stdBuffer[1024];
    time_t now = time(nullptr);
    struct tm *lt = localtime(&now);
    snprintf(stdBuffer, sizeof stdBuffer, "[%s][%d:%d]: ", levels[level], lt->tm_hour, lt->tm_min);

    char logBuffer[1024];
    va_list va;
    va_start(va, format);
    vsnprintf(logBuffer, sizeof logBuffer, format, va);

    printf("%s%s\n", stdBuffer, logBuffer);
}

dictionary.hpp

#pragma once
#include <unordered_map>
#include <string>
#include <iostream>
#include <fstream>

const char separator = ':';

class Dictionary
{
public:
    Dictionary()
    {
        Init();
    }
    bool split(const std::string &dword, std::string &part1, std::string &part2)
    {
        int pos = dword.find(separator, 0);
        if (pos == std::string::npos)
        {
            return false;
        }
        part1 = dword.substr(0, pos);
        part2 = dword.substr(pos + 1);
    }
    void Init()
    {
        std::ifstream in("dictionary.txt");
        std::string dword;
        while (std::getline(in, dword))
        {
            std::string part1;
            std::string part2;
            if (split(dword, part1, part2))
                _dic[part1] = part2;
        }
        in.close();
    }

    std::string translate(std::string key)
    {
        auto it = _dic.find(key);
        if (it == _dic.end())
        {
            return "word unknow";
        }
        return it->second;
    }

private:
    std::unordered_map<std::string, std::string> _dic;
};

dictionary.txt 字典文本(简易)

apple:苹果...
banana:香蕉...
red:红色...
yellow:黄色...
the: 这
be: 是
to: 朝向//对
and: 和
I: 我
in:...里
that: 那个
have: 有
will:for: 为了
but: 但是
as:...一样
what: 什么
so: 因此
he: 他
her: 她
his: 他的
they: 他们
we: 我们
their: 他们的
his: 它的
with:...一起
she: 她
he: 他
it:

客户端代码

客户端代码仅此一套 且可适配服务器四个版本

#include <iostream>
#include <sys/socket.h>
#include <sys/types.h>
#include <string>
#include <arpa/inet.h>
#include <stdlib.h>
#include <unistd.h>
#include "log.hpp"
#include <netinet/in.h>
#include <string.h>
// telnet server_ip server_port
void Usage(const std::string &proc)
{
    std::cout << "\n\rUsage: " << proc << " ip[xxx.xxx.xxx.xxx] port[8888-9000]\n"
              << std::endl;
}

int main(int argc, char *argv[])
{
    if (argc != 3)
    {
        Usage("./TcpClient");
        exit(1);
    }
    // 申请socket
    int socketfd = socket(AF_INET, SOCK_STREAM, 0);
    if (socketfd < 0)
    {
        logMessage(FATAL, "socket create failed...");
        exit(2);
    }
    // 初始化结构体sockaddr
    struct sockaddr_in server;
    memset(&server, 0, sizeof server);
    server.sin_family = AF_INET;
    server.sin_port = htons(atoi(argv[2]));
    server.sin_addr.s_addr = inet_addr(argv[1]);

    if (connect(socketfd, (const sockaddr *)&server, sizeof server) < 0)
    {
        // connect失败
        logMessage(FATAL, "connect create failed...");
        exit(3);
    }
    // connect 成功
    logMessage(DEBUG, "connect create seccess...");

    // 开始发送和读取数据
    std::string out_buffer;
    char in_buffer[1024];
    while (true)
    {
        memset(in_buffer, 0, sizeof in_buffer);
        std::cout << "Send a Message@ ";
        std::getline(std::cin, out_buffer);
        write(socketfd, out_buffer.c_str(), out_buffer.size());

        int n = read(socketfd, in_buffer, sizeof in_buffer - 1);
        if (n > 0)
        {
            in_buffer[n] = 0;
            std::cout << "Server echo Message: " << in_buffer << std::endl;
        }
        else if (n == 0)
        {
            logMessage(WARNING, "Connection closed by foreign host, socketfd[%d] closed...", socketfd);
            break;
        }
        else if (n < 0)
        {
            logMessage(WARNING, "read erro, socketfd[%d]...");
            break;
        }
    }
    close(socketfd);
    return 0;
}

翻译效果图

在这里插入图片描述


本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:/a/666982.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

[.NET开发者的福音]一个方便易用的在线.NET代码编辑工具.NET Fiddle

前言 今天给大家分享一个方便易用的.NET在线代码编辑工具&#xff0c;能够帮助.NET开发人员快速完成代码编写、测试和分享的需求&#xff08;.NET开发者的福音&#xff09;&#xff1a;.NET Fiddle。 .NET Fiddle介绍 我们可以不用再担心环境与庞大的IDE安装的问题&#xff0…

python实现——分类类型数据挖掘任务(图形识别分类任务)

分类类型数据挖掘任务 基于卷积神经网络&#xff08;CNN&#xff09;的岩石图像分类。有一岩石图片数据集&#xff0c;共300张岩石图片&#xff0c;图片尺寸224x224。岩石种类有砾岩&#xff08;Conglomerate&#xff09;、安山岩&#xff08;Andesite&#xff09;、花岗岩&am…

github有趣项目:自制“我的世界” project make

videocodehttps://www.youtube.com/watch?v4O0_-1NaWnY,https://www.bilibili.com/video/BV1oj411p7qM/?https://github.com/jdah/minecraft-weekend MAKE git clone --recurse-submodules https://github.com/jdah/minecraft-weekend.git 正克隆到 minecraft-weekend... …

【笔记】关于brew install ffmpeg出现问题解决

Macos系统需要安装ffmpeg使用&#xff0c;通过brew install ffmpeg安装相关依赖时&#xff0c;当安装至flac时出现下列问题 环境&#xff1a;有代理开启 使用国内数据源 brew install ffmpeg --verbose --debug 安装过程中显示日志 curl: (35) error:1400442E:SSL routines:C…

前端3剑客(第1篇)-初识HTML

100编程书屋_孔夫子旧书网 当今主流的技术中&#xff0c;可以分为前端和后端两个门类。 前端&#xff1a;简单的理解就是和用户打交道 后端&#xff1a;主要用于组织数据 而前端就Web开发方向来说&#xff0c; 分为三门语言&#xff0c; HTML、CSS、JavaScript 语言作用HT…

Apache Pulsar 中文社区有奖问卷调查(2024 上半年度)

Apache Pulsar 中文社区有奖问卷调查&#xff08;2024 上半年度&#xff09; &#x1f4e3; &#x1f4e3; &#x1f4e3; Hi&#xff0c;Apache Pulsar 社区的小伙伴们&#xff0c;社区 2024 上半年度的有奖问卷调查来啦&#xff01; &#x1f64c; 本次调查旨在了解用户使用 …

EIS 2019 webshell

请求中可以确定是http POST流量 同时可以判断是 蚁剑的流量 进一步过滤 http.request.method "POST" 直接追踪其tcp流 得到 列举部分 eVAl(cHr(0x40).ChR(0x69).ChR(0x6e).ChR(0x69).ChR(0x5f).ChR(0x73).ChR(0x65).ChR(0x74).ChR(0x28)直接输出一下 内容 <…

数据治理基础知识

文章目录 基本概念相关名词术语数据治理对象 基本概念 1&#xff09;从管理者视角看数据治理 数据治理是企业发展战略的组成部分&#xff0c;是指导整个集团进行数字化变革的基石&#xff0c;要将数据治理纳入企业的顶 层规划&#xff0c;各分/子公司、各业务部门都需要按照企…

智慧园区整理技术方案(ppt,软件全套建设方案)

智慧园区管控平台整体技术方案 1.平台概述 2.公共安全 3.物业管理 4.综合管理 5.企业服务 平台规划&#xff0c;整理技术架构搭建&#xff0c;统一门户&#xff0c;lot物联平台&#xff0c;视频云管理平台&#xff0c;GIS服务平台&#xff0c;服务器架构&#xff0c;统一身份认…

发现一个ai工具网站

网址 https://17yongai.com/ 大概看了下&#xff0c;这个网站收集的数据还挺有用的&#xff0c;有很多实用的ai教程。 懂ai工具的可以在这上面找找灵感。

HTML如何让文字底部线条不紧贴在文字下面(既在内容下方又超出内容区域)

hello&#xff0c;大家好&#xff0c;星途小鹏今天给大家带来的内容是如何让文字底部线条不紧贴在文字下面。 话不多说&#xff0c;先上效果图 简单来说就是padding和margin的区别。 在网页设计中&#xff0c;有时我们想要给某个元素添加一个装饰性的线条&#xff0c;比如底部…

【设计模式】创建型-建造者模式

前言 在面向对象的软件开发中&#xff0c;构建复杂对象时经常会遇到许多挑战。一种常见的解决方案是使用设计模式&#xff0c;其中建造者模式是一个强大而灵活的选择。本文将深入探讨建造者模式的原理、结构、优点以及如何在实际项目中应用它。 一、复杂的对象 public class…

安卓如何书写注册和登录界面

一、如何跳转一个活动 左边的是本活动名称&#xff0c; 右边的是跳转界面活动名称 Intent intent new Intent(LoginActivity.this, RegisterActivity.class); startActivity(intent); finish(); 二、如果在不同的界面传递参数 //发送消息 SharedPreferences sharedPreferen…

【再探】设计模式—中介者模式、观察者模式及模板方法模式

中介者模式让多对多的复杂引用关系变成一对多&#xff0c;同时能通过中间类来封装多个类中的行为&#xff0c;观察者模式在目标状态更新时能自动通知给订阅者&#xff0c;模版方法模式则是控制方法的执行顺序&#xff0c;子类在不改变算法的结构基础上可以扩展功能实现。 1 中…

Python 之SQLAlchemy使用详细说明

目录 1、SQLAlchemy 1.1、ORM概述 1.2、SQLAlchemy概述 1.3、SQLAlchemy的组成部分 1.4、SQLAlchemy的使用 1.4.1、安装 1.4.2、创建数据库连接 1.4.3、执行原生SQL语句 1.4.4、映射已存在的表 1.4.5、创建表 1.4.5.1、创建表的两种方式 1、使用 Table 类直接创建表…

【稳定检索/投稿优惠】2024年商务、信息管理与大数据经济国际会议(BIMBDE 2024)

2024 International Conference on Business, Information Management, and Big Data Economy 2024年商务、信息管理与大数据经济国际会议 【会议信息】 会议简称&#xff1a;BIMBDE 2024 大会地点&#xff1a;中国北京 会议官网&#xff1a;www.bimbde.com 会议邮箱&#xff…

MySql part1 安装和介绍

MySql part1 安装和介绍 数据 介绍 什么是数据库&#xff0c;数据很好理解&#xff0c;一般来说数据通常是我们所认识的 描述事物的符号记录&#xff0c; 可以是数字、 文字、图形、图像、声音、语言等&#xff0c;数据有多种形式&#xff0c;它们都以经过数字化后存入计算机…

CS4344国产替代音频DAC数模转换芯片DP7344采样率192kHz

目录 DAC应用简介DP7344简介结构框图DP7344主要特性微信号&#xff1a;dnsj5343参考原理图 应用领域 DAC应用简介 DAC&#xff08;中文&#xff1a;数字模拟转换器&#xff09;是一种将数字信号转换为模拟信号&#xff08;以电流、电压或电荷的形式&#xff09;的设备。电脑对…

Golang | Leetcode Golang题解之第123题买卖股票的最佳时机III

题目&#xff1a; 题解&#xff1a; func maxProfit(prices []int) int {buy1, sell1 : -prices[0], 0buy2, sell2 : -prices[0], 0for i : 1; i < len(prices); i {buy1 max(buy1, -prices[i])sell1 max(sell1, buy1prices[i])buy2 max(buy2, sell1-prices[i])sell2 m…

Docker 环境下 3D Guassian Splatting 的编译和配置

Title: Docker 环境下 3D Guassian Splatting 的编译和配置 文章目录 前言I. 宿主系统上的安装配置1. 安装 nvidia driver2. 安装 docker3. 安装 nvidia-container-toolkit II. Docker 容器安装配置1. 拉取 ubuntu 22.042. 创建容器3. 进入容器4. 容器中安装 cuda SDK5. 容器中…