Socket编程TCP

【Linux】TCP编程

实验:通过TCP通信—在客户端输入要执行的指令,接收执行结果,另服务端接收指令并执行,向客户端发送执行结果

//主函数
#include<iostream>
#include<string>
#include"log.hpp"
#include"command_excute.hpp"
#include"tcp_serve.hpp"void Usage(std::string name)
{std::cout<<"usage:\n\t"<<name <<" local_port\n"<<std::endl;
}int main(int argc,char* argv[]){if(argc !=2){Usage(argv[0]);return 1;}EnableScrean();//开启屏幕日志uint16_t port =std::stoi(argv[1]);//端口号Command cmd("./safe.txt");//创建Command对象func_t excute_t = bind(&Command::excute,&cmd,std::placeholders::_1);//将excute函数绑定到cmd对象,并指定一个占位符std::unique_ptr<tcp_serve> t_ptr = std::make_unique<tcp_serve>(port,excute_t);//创建智能指针指向tcp_serve类,并构造类对象t_ptr->init_serve();t_ptr->loop();return 0;}
//客户端
#include <functional>
#include <iostream>
#include <string.h>
#include <memory>
#include <cstdint>
#include <string>
#include <unistd.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include "InetAddr.hpp"void Usage(std::string name)
{std::cout << "usage:\n\t" << name << " serveip serveport\n"<< std::endl;
}int main(int argc, char *argv[])
{if (argc != 3){Usage(argv[0]);exit(1);}std::string server_ip = argv[1];uint16_t server_prot = std::stoi(argv[2]);// 创建套接字int sockfd = ::socket(AF_INET, SOCK_STREAM, 0);if (sockfd < 0){std::cerr << "socket error" << std::endl;exit(2);}// 设置本地信息struct sockaddr_in server;memset(&server, 0, sizeof(server));server.sin_family = AF_INET;server.sin_port = htons(server_prot);server.sin_addr.s_addr = inet_addr(server_ip.c_str());// 连接套接字sockfdint n = connect(sockfd, (struct sockaddr *)&server, sizeof(server));if (n < 0){std::cerr << "connect error" << std::endl;exit(3);}while (true){std::cout << "please enter#:" << std::endl;std::string outstring;std::getline(std::cin, outstring);ssize_t s = send(sockfd, outstring.c_str(), outstring.size(), 0); // 发送信息if (s > 0){// 发送成功char buffer[1024];ssize_t n = recv(sockfd, buffer, sizeof(buffer) - 1, 0); // 接受信息if (n > 0){buffer[n] = 0;std::cout << buffer << std::endl;}else{break;}}else{break;}}close(sockfd);return 0;
}
//服务端
#pragma once
#include <functional>
#include <iostream>
#include <string.h>
#include <memory>
#include <cstdint>
#include <string>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include "InetAddr.hpp"
// 错误码
enum
{SOCKET_ERROR = 1,BIND_ERROR,LISTEN_ERROR,USAGE_ERROR
};static const int gbacklog = 16;
static const int defaultsock = -1;
using func_t = std::function<std::string(const std::string &)>; // 回调函数处理server接收的信息class tcp_serve;class thread_data
{
public:thread_data(int fd, InetAddr clientaddr, tcp_serve *s): _sockfd(fd), _clientaddr(clientaddr), _self(s){}public:InetAddr _clientaddr;int _sockfd;tcp_serve *_self;
};
class tcp_serve
{
public:tcp_serve(uint16_t port, func_t func): _port(port), _func(func), _isruning(false), _listensock(defaultsock){}void init_serve(){// 1. 创建流式套接字_listensock = ::socket(AF_INET, SOCK_STREAM, 0);if (_listensock < 0){LOG(FATAL, "socket error\n");exit(SOCKET_ERROR);}LOG(DEBUG, "socket create seccess ,sockfd is : %d\n", _listensock);// 2. bind绑定本地协议地址,套接字将用于通信的本地 IP 地址和端口号struct sockaddr_in local;memset(&local, 0, sizeof(local));local.sin_family = AF_INET;local.sin_port = htons(_port);local.sin_addr.s_addr = INADDR_ANY;int n = ::bind(_listensock, (struct sockaddr *)&local, sizeof(local));if (n < 0){LOG(FATAL, "bind error\n");exit(BIND_ERROR);}LOG(DEBUG, "bind success, sockfd is :%d\n", _listensock);n = ::listen(_listensock, gbacklog); // 将一个未连接的套接字转换为一个被动套接字,即监听套接字,它可以接受其他套接字的连接请求if (n < 0){LOG(FATAL, "listen error\n");exit(LISTEN_ERROR);}LOG(DEBUG, "listen success, sockfd is : %d\n", _listensock);}void service(int sockfd, InetAddr client){LOG(DEBUG, "get new link,info : %s: %d:%d\n", client.Ip(), client.Port(), sockfd);std::string clientaddr = "[" + client.Ip() + " : " + std::to_string(client.Port()) + "]#";while (true) // 死循环一直接收信息,处理信息,发送信息{char buffer[1024];ssize_t n = recv(sockfd, buffer, sizeof(buffer) - 1, 0); // 接收来自套接字sockfd中的信息if (n > 0){buffer[n] == 0;std::cout << clientaddr << buffer << std::endl;std::string ret = _func(buffer); // 通过回调函数处理接收的信息send(sockfd, ret.c_str(), ret.size(), 0); // 发送处理接受信息的结果给sockfd}else if (n == 0){LOG(INFO, "%s quit\n", clientaddr.c_str());break;}else{LOG(ERROR, "read error \n", clientaddr.c_str());break;}}::close(sockfd);}static void *handler_sock(void *args){std::cout << "2" << std::endl;// pthread_detach(pthread_self());// thread_data *ptr = static_cast<thread_data *>(args);// pthread_detach(pthread_self());thread_data *td = static_cast<thread_data *>(args);td->_self->service(td->_sockfd, td->_clientaddr);delete td;return nullptr;}void loop(){_isruning = true;while (_isruning){struct sockaddr_in peer;socklen_t len = sizeof(peer);int sockfd = ::accept(_listensock, (struct sockaddr *)&peer, &len);// 用于从监听套接字接受一个连接请求// 阻塞等待直到有一个连接请求到达监听套接_listensock// 当连接请求到达时,accept会创建一个新的套接字处理这个连接,并返回新套接字的文件描述符。// 新套接字用于后续与客户端的通信if (sockfd < 0){LOG(WARNING, "accept error\n");continue;}pthread_t t;std::cout << "1" << std::endl;thread_data *td = new thread_data(sockfd, InetAddr(peer), this); // 创建指针td指向thread_data对象pthread_create(&t, nullptr, handler_sock, td);                   // 创建一个线程执行handler_sock,并将td'作为参数传递}_isruning = false;}private:uint16_t _port;int _listensock;bool _isruning;func_t _func;
};
//执行指令封装
#include <iostream>
#include <set>
#include <cstdio>
#include <fstream>
#include "log.hpp"
const static std::string sign = " ";
class Command
{
private:void load_safe_command(const std::string &set) // 将安全指令集从磁盘中装入内存中{std::ifstream in(set); // 打开我文件setif (!in.is_open()){LOG(FATAL, "open file error");return;}std::string line;while (std::getline(in, line)){LOG(FATAL, "load command [%s] success!\n", line.c_str());_safe_cmd.insert(line);}in.close(); // 关闭文件}public:Command(const std::string cond_path): _cond_path(cond_path){load_safe_command(_cond_path);}std::string get_head(const std::string &cmd) // ls -a -l 获取指令头部{if (cmd.empty())return std::string();auto index = cmd.find(sign);if (index == std::string::npos)return cmd;elsereturn cmd.substr(0, index);}bool check_safe(const std::string &cmd) // 检查指令是否安全{std::string head = get_head(cmd); // 获取指令头部,如:ls -l -a 指令中 lsif (head.empty())return false;auto iter = _safe_cmd.find(head); // 在安全指令集中查找指令头部if (iter != _safe_cmd.end()){return true;}return false;}std::string excute(const std::string &cmd) // 回调函数,cmd :server端接收的指令,{std::string result;if (check_safe(cmd)) // 检查指令是否安全,即是否在安全指令集中{FILE *fp = popen(cmd.c_str(), "r"); // popen()函数执行cmd指令,创建一个管道,通过这个管道可以读取命令的输出,// 执行完后,可以使用fread,fgets从fp指定的管道中读取数据,最后不用这个管道了,用pclose(fp)关闭if (fp == nullptr){return "failed";}char buffer[1024];while (fgets(buffer, sizeof(buffer), fp) != NULL) // 读取执行结果,写入result中{result += buffer;}pclose(fp);}else{result = "坏人!\n";}return result;}private:std::set<std::string> _safe_cmd; // 安全指令集std::string _cond_path;          // 安全指令存放的路径
};
//ip port 信息封装
#pragma once
#include <iostream>
#include<sys/types.h>
#include<sys/socket.h>
#include<arpa/inet.h>
#include<netinet/in.h>
class InetAddr
{
public:InetAddr(const sockaddr_in& addr):_addr(addr){get_address(&_ip,&_port);}std::string Ip(){return _ip;}uint16_t Port(){return _port;}bool operator==(const InetAddr& addr){if(_ip == addr._ip&&_port == addr._port){return true;}elsereturn false;}struct sockaddr_in addr(){return _addr;}~InetAddr(){}
private:void get_address(std::string* ip,uint16_t* port){*ip = inet_ntoa(_addr.sin_addr);*port = ntohs(_addr.sin_port);}struct sockaddr_in _addr;std::string _ip;uint16_t _port;
};
//日志封装
#pragma once
#include <iostream>
#include <stdarg.h>
#include <fstream>
#include<sys/types.h>
#include<unistd.h>
#include "LockGuard.hpp"
const static char *logname = "log.txt";//日志文件
bool g_save = false; 
pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER;
enum level//日志的等级
{DEBUG = 0,INFO,WARNING,ERROR,FATAL
};
void save_file(const std::string &logname, std::string &massage)//保存日志到文件中
{std::ofstream infile("logname", std::ios::app);if (!infile.is_open()){return;}infile << massage << std::endl;infile.close();
}
// 获取日志等级
std::string get_level_string(int level)
{switch (level){case DEBUG:return "DEBUG";case INFO:return "INFO";case WARNING:return "WARNING";case ERROR:return "ERROR";case FATAL:return "FATAL";default:return "None";}
}
// 获取时间字符串
std::string get_time_string()
{time_t cur_time = time(nullptr);if (cur_time == (time_t)-1){printf("Failed to get the current time.\n");return "None";}struct tm *formate_time = localtime(&cur_time);if (formate_time == nullptr){return "None";}char buffer[1024];snprintf(buffer, sizeof(buffer), "%d-%d-%d %d:%d:%d",formate_time->tm_year + 1900,formate_time->tm_mon + 1,formate_time->tm_mday,formate_time->tm_hour,formate_time->tm_min,formate_time->tm_sec);return buffer;
}
// 日志信息
void  Log_inf(std::string filename, int line, bool is_save, int level, const char *format, ...)
{std::string levelstr = get_level_string(level);std::string time = get_time_string();pid_t selfid = getpid();char buffer[1024];va_list arg;va_start(arg, format);vsnprintf(buffer, sizeof(buffer), format, arg);va_end(arg);std::string massage = "[" + time + "]" + "[" + levelstr + "]" + "[" + std::to_string(selfid) + "]" + "[" + filename + "]" + "[" + std::to_string(line) + "]" + buffer;LockGuard lockguard(mutex); // RAIIif (is_save){// 保存到文件中save_file(logname, massage);}else{   //向屏幕中打印std::cout << massage;}
}// 定义宏
#define LOG(level, format, ...)                                            \do                                                                     \{                                                                      \Log_inf(__FILE__, __LINE__, g_save, level, format, ##__VA_ARGS__); \} while (0)
#define Enablefile()   \do                 \{                  \g_save = true; \} while (0)
#define EnableScrean()  \do                  \{                   \g_save = false; \} while (0)
//互斥锁
#pragma once 
#include<iostream>
#include<pthread.h>
class LockGuard //互斥量RAII
{public:LockGuard(pthread_mutex_t& mutex):_mutex(mutex){pthread_mutex_init(&_mutex,nullptr);pthread_mutex_lock(&_mutex);}~LockGuard(){pthread_mutex_unlock(&_mutex);pthread_mutex_destroy(&_mutex);}private:pthread_mutex_t& _mutex;
};

(完)

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

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

相关文章

QNX的PPS发布/订阅模型

参考资料: QNX官方文档 以下摘自官网介绍: TheQNX NeutrinoPersistent Publish/Subscribe (PPS) service is a small, extensible publish/subscribe service that offers persistence across reboots. It’s designed to provide a simple and easy-to-use solution for b…

(二)FT2232HL调试器的驱动安装

1、FT2232HL调试器 FT2232HL调试器淘宝链接&#xff1a; http://e.tb.cn/h.TZH7byCQ1jwlqhy?tkdZo03JTjtwL ​ 2、软件下载 下载zadig-2.9.exe&#xff08;免安装&#xff09; 链接&#xff1a;https://www.filecroco.com/download-zadig/download/ ​ ​ 3、驱动安装 1…

远程debug

这里写自定义目录标题 一、首先配置idea二、配置jvm1、将刚才idea生成的jvm指令复制下来&#xff0c;就是如下内容&#xff08;注意要从你的idea中复制&#xff09;2、在粘贴之前&#xff0c;要拼接上java-jar命令&#xff0c;还有servery,suspendy命令&#xff0c;最后拼接项目…

Html笔记():蜘蛛纸牌之卡片设计

效果 代码 <!DOCTYPE html> <html><head><style>body{display: flex;justify-content: center;align-items: center;height: 100vh;background-color: #2b2b2b;}.card{/*设置卡牌的外观*/width: 150px;height: 200px;background-color: #00ffcc;borde…

深入浅出:PHP 文件操作

文章目录 引言文件的基本操作打开文件读取文件逐行读取读取整个文件 写入文件追加写入覆盖写入 关闭文件 文件和目录的管理检查文件或目录是否存在创建和删除文件创建和删除目录复制和移动文件 处理文件权限设置文件权限获取文件权限 处理文件属性获取文件大小获取文件最后修改…

docker-compose安装rocketmq

1. 创建RocketMq文件目录 mkdir rocketmq mkdir -p rocketmq/brokerconf rocketmq/logs rocketmq/store2.创建broker.conf配置文件 vim brokerconf/broker.conf# 集群名称 brokerClusterName DefaultCluster # broker 名字 brokerName broker-a # 0表示master&#xff0c…

【二分查找】力扣 875. 爱吃香蕉的珂珂

一、题目 二、思路 速度 k&#xff08;单位&#xff1a;根/小时&#xff09;是存在一个取值范围的。 速度越大肯定在规定的时间之内一定会吃完全部的香蕉&#xff0c;但也是可以确定出一个上界的。由于只要保证一小时之内&#xff0c;可以吃完香蕉数目最多的那一堆的香蕉&…

计算机网络-GRE基础实验二

前面我们学习了GRE隧道的建立以及通过静态路由指向的方式使得双方能够网络互联&#xff0c;但是通过静态路由可能比较麻烦&#xff0c;GRE支持组播、单播、广播因此可以在GRE隧道中运行动态路由协议使得网络配置更加灵活。 通过前面的动态路由协议的学习我们知道动态路由协议都…

QNX的内存布局和启动入口

参考资料: QNX官网文档 内存布局 添加图片注释,不超过 140 字(可选) 查看系统内存布局 # pidin syspage=asinfo Header size=0x00000108, Total Size=0x0000d1b0, #Cpu=8, Type=257 Section:asinfo offset:0x0000bdf0 size:0x00000d00 elsize:0x000000200000

使用 httputils + protostuff 实现高性能 rpc

1、先讲讲 protostuf protostuf 一直是高性能序列化的代表之一。但是用起来&#xff0c;可难受了&#xff0c;你得先申明 protostuf 配置文件&#xff0c;并且要把这个配置文件转成类。所以必然要学习新语法、新工具。 可能真的太难受了&#xff01;于是乎&#xff0c;&#…

重生之我在异世界学智力题(1)

大家好&#xff0c;这里是小编的博客频道 小编的博客&#xff1a;就爱学编程 很高兴在CSDN这个大家庭与大家相识&#xff0c;希望能在这里与大家共同进步&#xff0c;共同收获更好的自己&#xff01;&#xff01;&#xff01; 本文目录 引言智力题题目&#xff1a;《奇怪的时钟…

【优选算法】模拟

目录 一、[替换所有的问号](https://leetcode.cn/problems/replace-all-s-to-avoid-consecutive-repeating-characters/description/)二、[提莫攻击](https://leetcode.cn/problems/teemo-attacking/description/)三、[Z 字形变换](https://leetcode.cn/problems/zigzag-conver…

Pandas | 检查布尔序列函数any() 和 all()的区别

在 Python 中使用 pandas 库时&#xff0c;.any() 和 .all() 是两个用于检查布尔序列&#xff08;如 pandas 的 Series&#xff09;的函数&#xff0c;它们的行为和用途有所不同&#xff1a; 通常用于检查两列元素是否一致或者个别一致的情况 .any(): .any() 函数用于检查序列…

关于HTTP DEBUGGER PRO的DURATION列一点理解

最近在排查一个网络问题的时候&#xff0c;使用了HTTP DEBUGGER PRO进行抓包。发现HTTP DEBUGGER PRO抓包显示的DURATION列的耗时不太对劲&#xff0c;于是排查完网络问题就去看了下这个DURATION列实际所指的耗时&#xff0c;就有了这篇文章。 使用POSTMAN对https://www.rust-l…

Mysql数据库基础篇笔记

目录 sql语句 DDL——数据库定义语言&#xff08;定义库&#xff0c;表&#xff0c;字段&#xff09; 数据库操作&#xff1a; 表操作&#xff1a; DML 增删改语句 DQL 语法编写顺序&#xff1a; 条件查询 DCL 用户管理&#xff1a; 权限管理&#xff1a; 函数 常见字符串内置函…

联想按下“AI加速键”!目标:与5000万中小企业共创

根据相关数据显示&#xff0c;截至2023年末中国中小企业数量超过5300万家&#xff0c;中小企业支撑了中国经济的发展与前进。在AI大模型风潮到来之际&#xff0c;相比于AI带给大企业的长期价值&#xff0c;AI对中小企业有着更加直接、显著、决定性的意义。同时&#xff0c;AI与…

SpringBoot项目启动报错-Slf4j日志相关类找不到

天行健&#xff0c;君子以自强不息&#xff1b;地势坤&#xff0c;君子以厚德载物。 每个人都有惰性&#xff0c;但不断学习是好好生活的根本&#xff0c;共勉&#xff01; 文章均为学习整理笔记&#xff0c;分享记录为主&#xff0c;如有错误请指正&#xff0c;共同学习进步。…

《OpenCV 基础全攻略:从入门到精通》

《OpenCV 基础全攻略&#xff1a;从入门到精通》 一、OpenCV 简介&#xff08;一&#xff09;特点&#xff08;二&#xff09;优势&#xff08;三&#xff09;应用场景 二、安装与配置三、OpenCV 函数详解1. 图像读取函数 cv2.imread ()2. 图像显示函数 cv2.imshow ()3. 图像保…

懒人笔记-QT程序quazip篇

懒人笔记-QT程序quazip篇 1 、前言 之前整的工程&#xff0c;在虚拟机里的UOS家庭版里测试&#xff0c;突然发现不会用了&#xff0c;折腾了好久&#xff0c;再PC里面UOS试了下&#xff0c;突然发现可以很简单&#xff0c;记录下&#xff0c;以备后用。&#xff08;工程还没有…

MacOS编译webRTC源码小tip

简单记录一下&#xff0c;本人在编译webRTC时&#xff0c;碰到了一下比较烦人的问题&#xff0c;在MacOS终端下&#xff0c;搭建科学上网之后&#xff0c;chromium的depot_tools仓库成功拉下来了&#xff0c;紧接着&#xff0c;使用fetch以及gclient sync始终都返回curl相关的网…