当前位置: 首页 > news >正文

深入了解linux网络—— TCP网络通信(下)

前言

学习了TCP通信相关的接口使用,实现了基本的通信,现在来基于TCP通信实现翻译功能、远程SHELL

翻译功能

对于翻译功能,实现起来还是非常容易的,直接复用之前实现好的Dict类;

TcpServer中新增一个成员变量_func,表示未来信息的处理方法。

这样在server接收到信息时,只需回调_func即可。

//tcpserver.hpp
using func_t = std::function<std::string(std::string)>;
class TcpServer
{void Server(int rwfd, InetAddr &addr){while (true){char english[256];int rn = read(rwfd, english, sizeof(english) - 1);if (rn < 0){// read出错LOG(Level::ERROR) << "read error";break;}else if (rn == 0){// write端退出LOG(Level::INFO) << "writer is exit";break;}// 读取成功english[rn] = '\0';std::string chinese = _func(english);std::cout << addr.ToString() << " : " << english << " -> " << chinese << std::endl;int wn = write(rwfd, chinese.c_str(), chinese.size());if (wn < 0){LOG(Level::ERROR) << "write error";break;}}}
public:TcpServer(uint16_t port, func_t func) : _sockfd(-1), _port(port), _func(func){}~TcpServer() {}void Init(){// 1. socket_sockfd = socket(AF_INET, SOCK_STREAM, 0);if (_sockfd < 0){LOG(Level::FATAL) << "socket error";exit(1);}LOG(Level::DEBUG) << "socket success";// 2. bindInetAddr addr(_port);int b = bind(_sockfd, addr.GetInetAddr(), addr.GetLen());if (b < 0){LOG(Level::FATAL) << "bind error";exit(2);}LOG(Level::DEBUG) << "bind success";int l = listen(_sockfd, 5);if (l < 0){LOG(Level::FATAL) << "listen error";exit(3);}LOG(Level::DEBUG) << "listen success";}class ThreadData{public:ThreadData(int fd, TcpServer *tsvr, InetAddr addr): _fd(fd), _tsvr(tsvr), _addr(addr){}int _fd;TcpServer *_tsvr;InetAddr _addr;};static void *Routinue(void *argv){pthread_detach(pthread_self());ThreadData *td = static_cast<ThreadData *>(argv);td->_tsvr->Server(td->_fd, td->_addr);return nullptr;}void Start(){while (true){struct sockaddr_in peer;socklen_t len = sizeof(peer);bzero(&peer, len);int rwfd = accept(_sockfd, (struct sockaddr *)&peer, &len);if (rwfd < 0){LOG(Level::FATAL) << "accept error";exit(4);}LOG(Level::DEBUG) << "accept success";// 多线程pthread_t tid;ThreadData *td = new ThreadData(rwfd, this, peer);pthread_create(&tid, nullptr, Routinue, td);}private:int _sockfd;uint16_t _port;func_t _func;
};

这样在tcpserver启动时,先加载字典,然后创建TcpServer对象,启动服务端即可。

//tcpserver.cc
int main(int argc, char *argv[])
{if (argc != 2){std::cout << "usage : " << argv[0] << " port" << std::endl;exit(1);}uint16_t port = std::stoi(argv[1]);Dict d;d.Load();TcpServer tsvr(port, [&d](std::string english) -> std::string{ return d.Translate(english); });tsvr.Init();tsvr.Start();return 0;
}

远程shell

这里简单实现远程shell,实现原理很简单:

简单设计一个InetShell类,其中存储着可以远程执行的命令(防止恶意操作)

再由InetShell通过一个方式去执行远端命令;

然后通过回调,在server接受到信息后,回调InetShell中的执行命令的方法;

最后,将执行的结果,通过返回值传给serverserver再将返回值发送给远端。

1. 设计InetShell

首先,在InetShell中要保存可以执行的命令(防止恶意操作),这里就直接使用unordered_set来存储。

class InetShell
{InetShell(){_whitelist.insert("ls");_whitelist.insert("ll");_whitelist.insert("pwd");_whitelist.insert("who");_whitelist.insert("whoami");_whitelist.insert("touch test.txt");_whitelist.insert("mkdir test");}private:std::unordered_set<std::string> _whitelist;
};

2. 执行命令

InetShell中,要实现一个执行命令的方法Execute

在执行该命令之前,就要先判断当前命令是否安全(是否在_whitelist中);

在确认安全后,就要执行命令:

这里执行命令,要命令行解析、进行程序替换等等;

这里就不做这些操作了,可以直接使用popenpopen:将传递进来的字符当中命令行信息,进行命令行解析,执行命令;最后执行结果以文件的形式返回一个FILE*类型的指针)

在这里插入图片描述

所以,这里在确认命令安全之后,就可以直接调用popen,将命令行信息传递进去,以读方式打开(r)。

然后就可以使用C语言文件读取的方法将执行结果读取出来(fgets);

将读取的内容拼接成字符串;读取完毕之后关闭文件即可。

    std::string Execute(const std::string &com){if (IsWhite(com))return "unsafe";FILE *fp = popen(com.c_str(), "r");if (fp == NULL)return std::string();char buff[1024];std::string result;while (fgets(buff, sizeof(buff), fp)){result += buff;}pclose(fp);return result;}

这样,在server中通过回调,执行该方法,获取执行结果,然后再将结果发送给远端。

在这里插入图片描述

这里就通过简单的服务(翻译、远程shell),来熟悉TCP通信。

补充

这里Tcp通信,所实现的TcpServerUDP通信所实现的UdpServer都是不希望被拷贝的;我们可以通过删除拷贝构造和拷贝赋值来保证不被拷贝;

但是这里就实现一个nocopy类,该类删除了拷贝构造和拷贝赋值,TcpServer继承nocopy类,从而TcpServer也就不能被拷贝了。

class nocopy
{
public:nocopy() {}~nocopy() {}nocopy(const nocopy &) = delete;const nocopy &operator=(const nocopy &) = delete;
};

此外,这里当程序出现问题,socket失败、bind失败调用exit退出,退出码都使用的是数字;这里就可以设计一个枚举类型,将退出码一个个列举出来,方便查错。

enum ERR
{OK = 0,SOCKET_ERR,BIND_ERR,LISTEN_ERR,ACCEPT_ERR,CONNECT_ERR,FORK_ERR
};

到这里,本篇文章内容就结束了,感谢支持
我的博客即将同步至腾讯云开发者社区,邀请大家一同入驻:https://cloud.tencent.com/developer/support-plan?invite_code=2oul0hvapjsws

http://www.dtcms.com/a/447205.html

相关文章:

  • 论文速览:从ConvNeXt 到 ConvNeXt V2
  • 《P1544 三倍经验》
  • 之前的知识补充 03
  • 源代码如何做网站网站开发与设计是什么
  • 南京自助建站软件百度seo搜索
  • 接口测试基础01
  • 做淘宝客网站需要多大空间大学生网页设计与制作模板
  • 宁波网站建设用什么软件黄骅招聘网最新招工信息
  • 第四十章 ESP32S3 图片显示实验
  • 网站建设收费分几次汕头网站设计价格
  • 各大网站代下单怎么做延吉市建设厅网站
  • 基于51单片机步数检测计步器无线蓝牙APP上传设计
  • 网站制作邯郸平台网站建设哪家好
  • 微专题:C++中的进制转换
  • 【多线程】多线程的底层实现
  • 台州网站建设公司哪个好互联网销售公司起名
  • 网站可以同时做竞价和优化吗网站建设的优势与不足
  • 做网站怎么去文化局备案phpstudy和wordpress
  • 网站嵌套代码wordpress 文章 指定
  • 什么是速成网站3d建模培训学校哪家好
  • 做律师网站导购网站怎么建设
  • 佛山优化网站排名福建省港航建设发展有限公司网站
  • 上杭网站设计公司安阳市有几个区几个县
  • XGBoost工业级痛点解决:样本不平衡+大数据优化+部署落地
  • CCF-CSP认证考试 202312-4 宝藏 题解
  • 个人网站备案号被注销了网站运营优化推广
  • Python数据清洗实战指南
  • s网站优化西安咪豆网站建设公司
  • 怀柔建设网站公司公司网站后台维护怎么做
  • 网站开发 ssh 菜鸟东阳网络科技有限公司