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

news2024/11/19 0:21:44

文章目录

  • 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;
}

翻译效果图

在这里插入图片描述


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

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

【设计模式】结构型-门面模式

前言 在软件开发中&#xff0c;设计模式是解决特定问题的经验总结&#xff0c;为开发者提供了一种可复用的解决方案。其中&#xff0c;门面模式&#xff08;Facade Pattern&#xff09;是一种结构型模式&#xff0c;旨在为复杂系统提供简化的接口&#xff0c;使客户端与系统之…

Java(十一)---String类型

文章目录 前言1.String类的重要性2.常用方法2.1.字符串的创建2.2.字符串的比较2.2.1.比较是否引用同一个对象2.2.2.boolean equals(Object anObject) 方法&#xff1a;2.2.3.int CompareTo(String s)2.2.4.int compareToIgnoreCase(String str) 方法&#xff1a; 2.3.字符串的查…

算法(十四)动态规划

算法概念 动态规划&#xff08;Dynamic Programming&#xff09;是一种分阶段求解的算法思想&#xff0c;通过拆分问题&#xff0c;定义问题状态和状态之间的关系&#xff0c;使得问题能够以递推&#xff08;分治&#xff09;的方式去解决。动态规划中有三个重点概念&#xff…

C 基础 - 预处理命令和基本语法详解

#include <stdio.h> //预处理指令int main() //函数 {printf("Hello, World!"); //输出语句return 0; //返回语句 } 目录 一.预处理指令 1.#define #ifdef #ifndef #if #else #elif #endif 2.#inlcude a.新增一个文件 b.#include c.运行结果 d.扩…

AI炒股-批量爬取网易财经的要闻板块

工作任务和目标&#xff1a;批量爬取网易财经的要闻板块 在class"tab_body current"的div标签中&#xff1b; 标题和链接在&#xff1a;<a href"https://www.163.com/dy/article/J2UIO5DD051188EA.html">华为急需找到“松弛感”</a> 第一步&…

【原创教程】MES服务器与成品打标机控制说明

1 实现的功能及应用的场合 MES即制造执行系统(manufacturing execution system,简称MES),即在加强MRP计划的执行功能,把MRP计划同车间作业现场控制,通过执行系统联系起来。 MES是一个生产管理智能化的一个系统,是用于生产时记录数据、产量等信息的智能管理系统。 该项…

WebGL画粗线

目录 前言 基本思路 求左右端点 实现 组织数据 顶点着色器计算端点坐标 效果 前言 WebGL绘制模式有点、线、面三种&#xff1b;通过点的绘制可以实现粒子系统等&#xff0c;通过线可以绘制一些连线关系&#xff1b;面就强大了&#xff0c;通过面&#xff0c;我们可以…

材质技术在AI去衣中的作用

随着人工智能技术的飞速发展&#xff0c;越来越多的应用场景开始涌现。其中&#xff0c;AI去衣技术作为一种新兴的图像处理技术&#xff0c;已经在很多领域得到了广泛的应用。而在AI去衣技术中&#xff0c;材质技术起到了至关重要的作用。本文将详细介绍材质技术在AI去衣中的作…

【前缀和 记忆化搜索】LeetCode1444. 切披萨的方案数

本文涉及的基础知识点 C算法&#xff1a;前缀和、前缀乘积、前缀异或的原理、源码及测试用例 包括课程视频 动态规划 记忆化搜索 LeetCode1444. 切披萨的方案数 给你一个 rows x cols 大小的矩形披萨和一个整数 k &#xff0c;矩形包含两种字符&#xff1a; ‘A’ &#xff…

生成式AI,在云端的绽放与盛开

编辑&#xff1a;阿冒 设计&#xff1a;沐由 毫无疑问&#xff0c;生成式AI已然成为当今技术发展和应用创新的重要引擎之一。 过去的一年多时间里&#xff0c;我们每个人都在目睹和见证着生成式AI是如何以移山倒海的力量&#xff0c;为诸多行业带来革命性乃至颠覆性的变革&…

Python3位运算符

前言 本文介绍的是位运算符&#xff0c;位运算可以理解成对二进制数字上的每一个位进行操作的运算&#xff0c;位运算分为 布尔位运算符 和 移位位运算符。 文章目录 前言一、位运算概览1、布尔位运算符1&#xff09;按位与运算符 ( & )2&#xff09;按位或运算符 ( | )3…

输入输出安全防护指南

输入输出安全防护指南 在现代网络应用程序中&#xff0c;输入输出的安全性是至关重要的。未经验证的输入和未编码的输出可能导致严重的安全漏洞&#xff0c;如SQL注入、跨站脚本攻击&#xff08;XSS&#xff09;等。本文将详细讨论如何通过输入验证和输出编码来确保应用程序的…

9. C++通过epoll+fork的方式实现高性能网络服务器

epollfork 实现高性能网络服务器 一般在服务器上&#xff0c;CPU是多核的&#xff0c;上述epoll实现方式只使用了其中的一个核&#xff0c;造成了资源的大量浪费。因此我们可以将epoll和fork结合来实现更高性能的网络服务器。 创建子进程函数–fork( ) 要了解线程我们先来了解…

零配件相关销售业务

测试场景CRM订单类型描述SAP订单类型描述发货开票备注零部件销售&退货服务商零配件订单标准订单&#xff08;服务商零配件&#xff09;参考DN开票YY 服务商零配件退货单退货订单(服务商零配件&#xff09;不开票退返账号金额YN服务商收到的零配件&#xff08;不能使用&…

Charles-ios无法抓包原因之一证书

VPN证书安装完成后依然无法抓包存在无网络问题 VPN安装证书后直接抓包这时候抓包接口返回无网络&#xff0c;原因是IOS通用-关于本机-证书信任设计未开启信任

最佳实践:REST API 的 HTTP 请求参数

HTTP 请求中的请求参数解释 当客户端发起 HTTP 请求 时&#xff0c;它们可以在 URL 末尾添加请求参数&#xff08;也叫查询参数或 URL 参数&#xff09;来传递数据。这些参数以键值对的形式出现在 URL 中&#xff0c;方便浏览和操作。 请求参数示例 以下是一些带有请求参数的…

c基础 - 输入输出

目录 一.scanf() 和 printf() 函数 1.printf 2.scanf 二 . getchar() & putchar() 函数 1.int getchar(void) 2.int putchar(int c) 三. gets() & puts() 函数 一.scanf() 和 printf() 函数 #include <stdio.h> 需要引入头文件,stdio.h 1.printf print…

【Linux】权限的概念

1.Linux权限的概念 Linux下有两种用户&#xff1a;超级用户&#xff08;root&#xff09;、普通用户。 超级用户&#xff1a;可以再linux系统下做任何事情&#xff0c;不受权限限制 普通用户&#xff1a;在linux下做有限的事情&#xff0c;受权限设置。 windows下也有超级用户…

ADC数模转换器

一、ADC&#xff08;Analog-Digital Converter&#xff09;模拟-数字转换器 1、ADC可以将引脚上连续变化的模拟电压转换为内存中存储的数字变量&#xff0c;建立模拟电路到数字电路的桥梁 2、12位逐次逼近型ADC&#xff0c;1us转换时间 3、输入电压范围&#xff1a;0~3.3V&a…

掌握 JavaScript 基本输出方法

掌握 JavaScript 基本输出方法 前言 这是我在这个网站整理的笔记,有错误的地方请指出&#xff0c;关注我&#xff0c;接下来还会持续更新。 作者&#xff1a;神的孩子都在歌唱 JavaScript 是一种强大且灵活的编程语言&#xff0c;广泛用于 Web 开发。通过 JavaScript&#xff…