基于tcp协议的网络通信应用化(翻译单词版,添加重连功能)

目录

翻译单词版

引入

思路

代码

init.hpp

task.hpp

运行情况

添加重连功能

引入

思路

代码

运行情况


翻译单词版

引入

除了echo消息,也可以让其作为一个翻译软件

  • 翻译不就是在我们搜单词时才会提供服务吗
  • 刚好符合我们的短时服务的要求

思路

我们仍然采用多线程的模式

只需要变动一下task.hpp(也就是处理数据的方式),以及增加一个单词文本文件和读取文件

  • 每次翻译软件启动时,都需要读取文件放入内存中,让客户端在线查询中英文的的切换

代码

init.hpp

cpp 复制代码
#include <fstream>
#include <unordered_map>

#define file_name "./word.txt"
#define delimiter ":"

void segmentation(std::string &info, std::string &part1, std::string &part2)
{
    auto it = info.find(delimiter);
    part1 = info.substr(0, it); // 左闭右开
    part2 = info.substr(it + 1, info.size());
}
struct words_init
{
    words_init()
    {
        std::ifstream in(file_name);
        std::string info;
        while (std::getline(in, info)) //从文件中读取,初始化words_
        {
            std::string part1, part2;
            segmentation(info, part1, part2);
            words_[part1] = part2;
        }
    }

    std::string translation(const std::string &info)
    {
        auto it = words_.find(info);//单词集里查找是否有输入的单词
        std::string res;
        if (it == words_.end())
        {
            return "UnKnown";
        }
        else
        {
            return it->second; //翻译
        }
        return nullptr;
    }

    std::unordered_map<std::string, std::string> words_;
};

task.hpp

cpp 复制代码
#pragma once

#include <iostream>
#include <string>
#include <stdio.h>

#include "helper.hpp"
#include "init.hpp"
// 这里的任务是,服务端在收到客户端的连接后的后续工作

words_init w;

class Task
{
public:
    Task() {} // 方便只是为了接收传参而定义一个对象
    Task(int fd, const char ip[32], const uint16_t port)
        : sockfd_(fd), ip_(ip), port_(port)
    {
    }

    void operator()()
    {
        function();
    }

private:
    void function()
    {
        char buffer[buff_size];
        memset(buffer, 0, sizeof(buffer));

        while (true)
        {
            int n = read(sockfd_, buffer, sizeof(buffer) - 1);
            if (n < 0)
            {
                lg(ERROR, "%s:%d read error, %s", ip_.c_str(), port_, strerror(errno));
                break;
            }
            else if (n == 0)
            {
                lg(INFO, "%s:%d quit", ip_.c_str(), port_);
                break;
            }
            else
            {
                buffer[n] = 0;
                // std::string res = process_info(buffer, ip_, port_);
                std::string res = w.translation(buffer);
                write(sockfd_, res.c_str(), res.size());
            }
        }
    }

private:
    int sockfd_;
    uint16_t port_;
    std::string ip_;
};

运行情况

成功哩:

多个客户端也可以:

添加重连功能

引入

当我们的服务端关闭后,客户端想要向服务端写入时,客户端会被迫退出:

  • 因为套接字在写失败时,会给写入的一端发送sigpipe信号:
  • 但在cs模式中,我们并不希望这样
  • 因为某些问题导致的服务端断开连接/客户端这边出了某些问题,而服务端很可能会快速恢复/客户端重新连接服务端可能就会恢复(比如)
  • 所以我们更希望客户端能在发生错误时,进行一些处理(比如重连),而不是进程直接退出
  • 就像我们玩的各种游戏,在网络波动的时候,都会有转圈圈啦,显示断线重连中啦,都是因为他们有进行错误处理
  • 所以,我们除了设置read错误时的处理,也需要处理sigpipe的信号处理方式(忽略/自定义)

思路

所以我们考虑设置重连措施

  • 设定重连次数(不然客户端会一直重连)
  • 每次重连都需要重新创建套接字
  • 因为一旦断开连接,当前套接字的连接状态无法恢复,不能简单地通过connect重新连接
  • 只能创建新的套接字,然后通过这个新的套接字建立新的连接(客户端和服务端都是这样):
  • 像是下图这样,在服务端是通过accept函数创建用于io的套接字

代码

cpp 复制代码
void short_service()
    {
        signal(SIGPIPE, SIG_IGN); // 忽略这个信号,以便我们进行重连

        struct sockaddr_in *server_addr = new sockaddr_in;
        memset(server_addr, 0, sizeof(*server_addr));
        server_addr->sin_family = AF_INET;
        inet_pton(AF_INET, ip_.c_str(), &(server_addr->sin_addr));
        server_addr->sin_port = htons(port_);

        while (true) // 为了让io失败后,可以进入重连功能
        {
            bool is_reconnect = false;
            int re_num = 5;

            do
            {
                sockfd_ = socket(AF_INET, SOCK_STREAM, 0);
                if (sockfd_ < 0)
                {
                    exit(SOCK_ERROR);
                }
                int ret = connect(sockfd_, reinterpret_cast<struct sockaddr *>(server_addr), sizeof(*server_addr));
                if (ret < 0)
                {
                    is_reconnect = true;
                    --re_num;
                    std::cout << "im reconnect ing..." << std::endl;
                    sleep(2);
                }
                else
                {
                    std::cout << "connect success !" << std::endl;
                    is_reconnect = false;
                }
            } while (is_reconnect && re_num);

            if (re_num == 0)
            {
                break; // 重连次数达到限制,客户端退出
            }

            std::cout << "please enter:" << std::endl;
            std::string buffer;
            std::getline(std::cin, buffer);

            int n = write(sockfd_, buffer.c_str(), buffer.size());
            if (n < 0)
            {
                continue; // 除了处理读失败,写失败也需要(向不存在的文件写入)
            }

            char info[1024];
            memset(info, 0, sizeof(info));

            n = read(sockfd_, info, sizeof(info) - 1);
            if (n > 0)
            {
                info[n] = 0;
                std::cout << info << std::endl;
            }
            else
            {
                continue;
            }
            close(sockfd_);
        }
    }

运行情况

相关推荐
shymoy5 分钟前
Radix Sorts
数据结构·算法·排序算法
风影小子13 分钟前
注册登录学生管理系统小项目
算法
黑龙江亿林等保15 分钟前
深入探索哈尔滨二级等保下的负载均衡SLB及其核心算法
运维·算法·负载均衡
lucy1530275107918 分钟前
【青牛科技】GC5931:工业风扇驱动芯片的卓越替代者
人工智能·科技·单片机·嵌入式硬件·算法·机器学习
杜杜的man34 分钟前
【go从零单排】迭代器(Iterators)
开发语言·算法·golang
小沈熬夜秃头中୧⍤⃝1 小时前
【贪心算法】No.1---贪心算法(1)
算法·贪心算法
木向1 小时前
leetcode92:反转链表||
数据结构·c++·算法·leetcode·链表
阿阿越1 小时前
算法每日练 -- 双指针篇(持续更新中)
数据结构·c++·算法
yfs10242 小时前
压缩Minio桶中的文件为ZIP,并通过 HTTP 响应输出
网络·网络协议·http
hgdlip2 小时前
有什么办法换网络ip动态
网络·tcp/ip·智能路由器