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

网页设计与网站建设 郑州大学推广普通话的意义论文

网页设计与网站建设 郑州大学,推广普通话的意义论文,郑州富士康最新招聘信息,兰州网站建设兰州文章目录 1. 实现一个简易的远程命令执行系统1.1 日志系统 (Log.hpp)1.2 UDP客户端 (UdpClient.cc)1.3 UDP服务器 (UdpServer.hpp)1.4 主程序 (main.c) 1. 实现一个简易的远程命令执行系统 1.1 日志系统 (Log.hpp) Log.hpp #pragma once // 防止头文件重复包含// 必要的头文…

文章目录

  • 1. 实现一个简易的远程命令执行系统
    • 1.1 日志系统 (Log.hpp)
    • 1.2 UDP客户端 (UdpClient.cc)
    • 1.3 UDP服务器 (UdpServer.hpp)
    • 1.4 主程序 (main.c)


1. 实现一个简易的远程命令执行系统

1.1 日志系统 (Log.hpp)

Log.hpp

#pragma once  // 防止头文件重复包含// 必要的头文件包含
#include <iostream>     // 标准输入输出流
#include <time.h>      // 时间相关函数
#include <stdarg.h>    // 可变参数函数支持
#include <sys/types.h> // 系统调用相关类型
#include <sys/stat.h>  // 文件状态
#include <fcntl.h>     // 文件控制选项
#include <unistd.h>    // UNIX标准函数
#include <stdlib.h>    // 标准库函数#define SIZE 1024  // 缓冲区大小// 日志级别定义
#define Info 0     // 信息
#define Debug 1    // 调试
#define Warning 2  // 警告
#define Error 3    // 错误
#define Fatal 4    // 致命错误// 日志输出方式定义
#define Screen 1     // 输出到屏幕
#define Onefile 2    // 输出到单个文件
#define Classfile 3  // 按日志级别分类输出到不同文件#define LogFile "log.txt"  // 默认日志文件名class Log
{
public:// 构造函数:初始化输出方式为屏幕输出,设置默认日志路径Log(){// 初始化日志输出方式为屏幕输出(Screen=1)// Screen:直接输出到终端屏幕// Onefile:输出到单个日志文件// Classfile:根据日志级别输出到不同文件printMethod = Screen;  // 设置日志文件存放的默认路径为当前目录下的log子目录// 注意:使用前需要确保该目录存在,否则写入文件会失败path = "./log/";      }// 设置日志输出方式的方法void Enable(int method){// 通过传入不同的参数来修改日志的输出方式:// method可以是:// Screen(1) - 输出到屏幕// Onefile(2) - 输出到单个文件// Classfile(3) - 按日志级别分类输出到不同文件printMethod = method;}// 将日志级别转换为对应的字符串std::string levelToString(int level){switch (level){case Info:    return "Info";case Debug:   return "Debug";case Warning: return "Warning";case Error:   return "Error";case Fatal:   return "Fatal";default:      return "None";}}// 根据不同的输出方式打印日志void printLog(int level, const std::string &logtxt){switch (printMethod){case Screen:     // 输出到屏幕std::cout << logtxt << std::endl;break;case Onefile:    // 输出到单个文件printOneFile(LogFile, logtxt);break;case Classfile:  // 按级别输出到不同文件printClassFile(level, logtxt);break;default:break;}}// 将日志写入指定文件void printOneFile(const std::string &logname, const std::string &logtxt){std::string _logname = path + logname;// 打开文件,使用以下标志:// O_WRONLY: 只写模式// O_CREAT: 如果文件不存在则创建// O_APPEND: 追加写入,新内容添加到文件末尾// 0666: 文件权限(rw-rw-rw-)//fd用来标识一个打开的文件int fd = open(_logname.c_str(), O_WRONLY | O_CREAT | O_APPEND, 0666);if (fd < 0) // 如果打开文件失败(fd<0),直接返回return;// 将日志内容写入文件// logtxt.c_str(): 获取日志内容的C风格字符串// logtxt.size(): 获取日志内容的长度write(fd, logtxt.c_str(), logtxt.size());  // 使用fd写入文件close(fd);  // 使用fd关闭文件}// 根据日志级别将日志写入对应的文件void printClassFile(int level, const std::string &logtxt){std::string filename = LogFile;filename += ".";filename += levelToString(level);  // 例如: "log.txt.Debug"printOneFile(filename, logtxt);}~Log(){}// 重载operator()函数,实现日志打印功能// level: 日志级别// format: 格式化字符串// ...: 可变参数列表void operator()(int level, const char *format, ...){// 1. 构造日志的左半部分:时间戳和日志级别time_t t = time(nullptr);          // 获取当前时间戳struct tm *ctime = localtime(&t);  // 转换为本地时间char leftbuffer[SIZE];             // 存储左半部分的缓冲区// 格式化左半部分:[级别][年-月-日 时:分:秒]/*int snprintf(char *buffer, size_t size, const char *format, ...);参数说明:buffer:输出缓冲区,用于存储格式化后的字符串size:缓冲区大小(字节数),包括结尾的空字符'\0'format:格式化字符串...:可变参数列表*/snprintf(leftbuffer, sizeof(leftbuffer), "[%s][%d-%d-%d %d:%d:%d]", levelToString(level).c_str(),  // 日志级别转字符串ctime->tm_year + 1900,         // 年(需要加1900)ctime->tm_mon + 1,             // 月(需要加1)ctime->tm_mday,                // 日ctime->tm_hour,                // 时ctime->tm_min,                 // 分ctime->tm_sec);                // 秒// 2. 处理可变参数部分(日志内容)va_list s;                        // 定义可变参数列表/*va_start 是一个宏,用来初始化 va_list 类型的变量,使其指向可变参数列表的第一个参数。void va_start(va_list ap, last_arg);参数:ap: va_list类型的变量last_arg: 最后一个固定参数的名字*/va_start(s, format);              // 初始化可变参数列表char rightbuffer[SIZE];           // 存储右半部分的缓冲区/*vsnprintf用于格式化字符串int vsnprintf(char *buffer, size_t size, const char *format, va_list args);参数说明:buffer:输出缓冲区,存储格式化后的字符串size:缓冲区大小(字节数),包括结尾的'\0'format:格式化字符串args:va_list类型的可变参数列表*/vsnprintf(rightbuffer, sizeof(rightbuffer), format, s);  // 格式化可变参数va_end(s);                        // 清理可变参数列表//vsnprintf 在执行时会将格式化后的结果存储在 rightbuffer 中,va_end(s) 只是清理 va_list 的状态,不会影响已经格式化好的字符串。// 3. 组合完整的日志信息char logtxt[SIZE * 2];            // 存储完整日志的缓冲区snprintf(logtxt, sizeof(logtxt), "%s %s", leftbuffer, rightbuffer);  // 合并左右部分// 4. 调用printLog函数输出日志printLog(level, logtxt);}private:int printMethod;      // 日志输出方式std::string path;     // 日志文件路径
};/* 注释掉的可变参数示例函数
int sum(int n, ...)
{va_list s;           // 定义可变参数列表va_start(s, n);      // 初始化可变参数列表int sum = 0;while(n){sum += va_arg(s, int);  // 依次获取参数n--;}va_end(s);          // 清理可变参数列表return sum;
}
*/

在这段UDP客户端代码中,套接字的使用主要体现在以下几个步骤:

  1. 创建套接字:
// 创建UDP套接字
int sockfd = socket(AF_INET, SOCK_DGRAM, 0);
// AF_INET: IPv4协议族
// SOCK_DGRAM: UDP数据报套接字
// 0: 使用默认协议
  1. 使用套接字发送数据:
// 发送数据到服务器
sendto(sockfd,                           // 套接字描述符message.c_str(),                  // 要发送的数据message.size(),                   // 数据长度0,                               // 标志位(struct sockaddr *)&server,      // 目标服务器地址len);                            // 地址结构长度
  1. 使用套接字接收数据:
// 接收服务器响应
struct sockaddr_in temp;     // 存储发送方地址
socklen_t len = sizeof(temp);ssize_t s = recvfrom(sockfd,            // 套接字描述符buffer,            // 接收缓冲区1023,             // 缓冲区大小0,                // 标志位(struct sockaddr*)&temp,  // 发送方地址&len);            // 地址结构长度
  1. 完整的通信流程示例:
int main() {// 1. 创建套接字int sockfd = socket(AF_INET, SOCK_DGRAM, 0);if (sockfd < 0) {cerr << "socket creation failed" << endl;return 1;}// 2. 准备服务器地址struct sockaddr_in server_addr;server_addr.sin_family = AF_INET;server_addr.sin_port = htons(8080);server_addr.sin_addr.s_addr = inet_addr("127.0.0.1");// 3. 发送数据string msg = "Hello Server";sendto(sockfd, msg.c_str(), msg.size(), 0,(struct sockaddr*)&server_addr, sizeof(server_addr));// 4. 接收响应char buffer[1024];struct sockaddr_in sender_addr;socklen_t sender_len = sizeof(sender_addr);ssize_t recv_len = recvfrom(sockfd, buffer, 1024, 0,(struct sockaddr*)&sender_addr, &sender_len);if (recv_len > 0) {buffer[recv_len] = '\0';cout << "Received: " << buffer << endl;}// 5. 关闭套接字close(sockfd);return 0;
}
  1. 错误处理示例:
// 创建套接字时的错误处理
int sockfd = socket(AF_INET, SOCK_DGRAM, 0);
if (sockfd < 0) {cerr << "Socket creation failed: " << strerror(errno) << endl;return 1;
}// 发送数据时的错误处理
ssize_t sent = sendto(sockfd, msg.c_str(), msg.size(), 0,(struct sockaddr*)&server_addr, sizeof(server_addr));
if (sent < 0) {cerr << "Send failed: " << strerror(errno) << endl;return 1;
}// 接收数据时的错误处理
ssize_t recv_len = recvfrom(sockfd, buffer, 1024, 0,(struct sockaddr*)&sender_addr, &sender_len);
if (recv_len < 0) {cerr << "Receive failed: " << strerror(errno) << endl;return 1;
}

关键点:

  1. UDP是无连接的,不需要建立连接就可以直接发送数据
  2. 每次发送/接收都需要指定目标/来源地址
  3. UDP不保证数据的可靠传输
  4. 需要正确处理发送和接收可能出现的错误
  5. 记得在程序结束时关闭套接字

1.2 UDP客户端 (UdpClient.cc)

UdpClient.cc

// 必要的头文件包含
#include <iostream>      // 标准输入输出
#include <cstdlib>      // 标准库函数
#include <unistd.h>     // UNIX标准函数
#include <strings.h>    // 字符串操作函数
#include <sys/types.h>  // 基本系统数据类型
#include <sys/socket.h> // 套接字接口
#include <netinet/in.h> // Internet地址族
#include <arpa/inet.h>  // IP地址转换函数using namespace std;// 打印使用说明函数
void Usage(std::string proc)
{// 告诉用户正确的命令行参数格式:程序名 服务器IP 服务器端口std::cout << "\n\rUsage: " << proc << " serverip serverport\n"<< std::endl;
}// ./udpclient serverip serverport
int main(int argc, char *argv[])
{// 检查命令行参数数量是否正确if (argc != 3){Usage(argv[0]);exit(0);}// 获取服务器IP和端口信息std::string serverip = argv[1];uint16_t serverport = std::stoi(argv[2]);  // 字符串转整数// 配置服务器地址结构struct sockaddr_in server;bzero(&server, sizeof(server));            // 清零地址结构server.sin_family = AF_INET;               // 使用IPv4地址族server.sin_port = htons(serverport);       // 将端口转换为网络字节序server.sin_addr.s_addr = inet_addr(serverip.c_str());  // 将IP转换为网络字节序socklen_t len = sizeof(server);            // 地址结构长度// 创建UDP套接字int sockfd = socket(AF_INET, SOCK_DGRAM, 0);if (sockfd < 0){cout << "socker error" << endl;return 1;}/* 关于客户端绑定的说明:// client 要bind吗?要!只不过不需要用户显示的bind!一般由OS自动随机选择!// 一个端口号只能被一个进程bind,对server是如此,对于client,也是如此!// 其实client的port是多少其实不重要,只要能保证主机上的唯一性就可以!// 系统会在首次发送数据的时候自动完成bind操作*/string message;        // 用户输入的消息char buffer[1024];    // 接收服务器响应的缓冲区// 主循环while (true){// 获取用户输入cout << "Please Enter@ ";getline(cin, message);// 发送数据到服务器// 参数:套接字、数据、数据长度、标志位、目标地址结构、地址结构长度sendto(sockfd, message.c_str(), message.size(), 0, (struct sockaddr *)&server, len);// 接收服务器响应struct sockaddr_in temp;     // 用于存储响应方的地址信息socklen_t len = sizeof(temp);// 接收数据// 参数:套接字、缓冲区、缓冲区大小、标志位、发送方地址结构、地址结构长度ssize_t s = recvfrom(sockfd, buffer, 1023, 0, (struct sockaddr*)&temp, &len);if(s > 0)  // 如果成功接收到数据{buffer[s] = 0;  // 添加字符串结束符cout << buffer << endl;  // 打印服务器响应}}// 关闭套接字close(sockfd);return 0;
}

1.3 UDP服务器 (UdpServer.hpp)

UdpServer.hpp

#pragma once  // 防止头文件重复包含// 必要的头文件包含
#include <iostream>     // 标准输入输出
#include <string>       // 字符串类
#include <strings.h>    // bzero等字符串操作
#include <cstring>      // C风格字符串操作
#include <sys/types.h>  // 基本系统数据类型
#include <sys/socket.h> // 套接字接口
#include <netinet/in.h> // Internet地址族
#include <arpa/inet.h>  // IP地址转换函数
#include <functional>   // std::function
#include "Log.hpp"      // 日志类// 定义回调函数类型:接收一个string参数,返回一个string
// using func_t = std::function<std::string(const std::string&)>;
typedef std::function<std::string(const std::string&)> func_t;
//      |              |            |                    |                  
//      |              |            |                    └─ 新的类型名
//      |              |            └─ 函数参数类型         
//      |              └─ 函数返回值类型
//      └─ 函数包装器Log lg;  // 全局日志对象// 错误码枚举
enum{SOCKET_ERR=1,  // 套接字创建错误BIND_ERR       // 绑定错误
};// 默认配置
uint16_t defaultport = 8080;              // 默认端口号
std::string defaultip = "0.0.0.0";        // 默认IP地址(监听所有网卡)
const int size = 1024;                    // 缓冲区大小class UdpServer{
public:// 构造函数:初始化服务器参数UdpServer(const uint16_t &port = defaultport, const std::string &ip = defaultip):sockfd_(0), port_(port), ip_(ip), isrunning_(false){}// 初始化服务器void Init(){// 1. 创建UDP套接字sockfd_ = socket(AF_INET, SOCK_DGRAM, 0); // AF_INET: IPv4协议族, SOCK_DGRAM: UDP数据报套接字if(sockfd_ < 0){lg(Fatal, "socket create error, sockfd: %d", sockfd_); // 记录致命错误日志exit(SOCKET_ERR);}// 记录信息级别日志,显示创建成功的套接字描述符lg(Info, "socket create success, sockfd: %d", sockfd_);// 2. 绑定套接字到指定地址和端口//struct sockaddr_in 是用于IPv4地址的结构体struct sockaddr_in local;                    // 本地地址结构bzero(&local, sizeof(local));               // 清零地址结构local.sin_family = AF_INET;                 // 使用IPv4地址族local.sin_port = htons(port_);              // 将端口号转换为网络字节序local.sin_addr.s_addr = inet_addr(ip_.c_str()); // 将IP地址转换为网络字节序// local.sin_addr.s_addr = htonl(INADDR_ANY);   // 替代方案:监听所有网卡// 绑定套接字if(bind(sockfd_, (const struct sockaddr *)&local, sizeof(local)) < 0){lg(Fatal, "bind error, errno: %d, err string: %s", errno, strerror(errno));exit(BIND_ERR);}lg(Info, "bind success, errno: %d, err string: %s", errno, strerror(errno));}// 运行服务器主循环void Run(func_t func) // 使用回调函数处理请求{isrunning_ = true;char inbuffer[size];  // 接收数据的缓冲区while(isrunning_){struct sockaddr_in client;         // 客户端地址结构socklen_t len = sizeof(client);    // 地址结构长度// 接收数据ssize_t n = recvfrom(sockfd_, inbuffer, sizeof(inbuffer) - 1, 0, (struct sockaddr*)&client, &len);if(n < 0){lg(Warning, "recvfrom error, errno: %d, err string: %s", errno, strerror(errno));continue;}inbuffer[n] = 0;  // 字符串结束符// 处理请求并发送响应std::string info = inbuffer;std::string echo_string = func(info);  // 调用回调函数处理请求sendto(sockfd_, echo_string.c_str(), echo_string.size(), 0, (const sockaddr*)&client, len); // 发送响应}}// 析构函数:清理资源~UdpServer(){if(sockfd_ > 0) close(sockfd_);}private:int sockfd_;     // 网络套接字文件描述符std::string ip_; // 服务器IP地址uint16_t port_;  // 服务器端口号bool isrunning_; // 服务器运行状态标志
};

1.4 主程序 (main.c)

main.c

#include "UdpServer.hpp"  // 包含UDP服务器类的头文件
#include <memory>         // 智能指针
#include <cstdio>         // 标准输入输出// 打印使用说明函数
void Usage(std::string proc)
{// 告诉用户如何正确使用程序,要求输入大于1024的端口号std::cout << "\n\rUsage: " << proc << " port[1024+]\n" << std::endl;
}// 消息处理函数,处理接收到的字符串
std::string Handler(const std::string &str)
{// 构建响应消息std::string res = "Server get a message: ";res += str;std::cout << res << std::endl;return res;
}// 执行shell命令并获取执行结果的函数
std::string ExcuteCommand(const std::string &cmd)
{// TODO: 添加安全检查机制// SafeCheck(cmd);// popen()创建管道,执行命令,并返回文件指针// "r"表示我们要读取命令的输出FILE *fp = popen(cmd.c_str(), "r");if(nullptr == fp){perror("popen");  // 如果popen失败,打印错误信息return "error";}// 读取命令执行结果std::string result;char buffer[4096];  // 临时缓冲区while(true){// 从管道读取数据到缓冲区char *ok = fgets(buffer, sizeof(buffer), fp);if(ok == nullptr) break;  // 如果读取完毕或出错,退出循环result += buffer;         // 将读取的数据追加到结果字符串}pclose(fp);  // 关闭管道return result;
}// 主函数
// ./udpserver port
int main(int argc, char *argv[])
{// 检查命令行参数数量是否正确if(argc != 2){Usage(argv[0]);  // 如果参数数量不对,打印使用说明exit(0);         // 退出程序}// 将命令行参数(端口号)转换为整数uint16_t port = std::stoi(argv[1]);// 创建UDP服务器对象,使用智能指针管理std::unique_ptr<UdpServer> svr(new UdpServer(port));// 初始化服务器svr->Init(/**/);// 运行服务器,传入命令执行函数作为回调svr->Run(ExcuteCommand);return 0;
}

这是一个基于UDP协议的远程命令执行系统,主要包含以下组件:

  1. 日志系统 (Log.hpp)

    • 支持多种日志级别(Info、Debug、Warning、Error、Fatal)

    • 可以选择日志输出方式(屏幕、单文件、分类文件)

    • 记录带时间戳的日志信息

  2. UDP服务器 (UdpServer.hpp)

    • 创建UDP套接字监听指定端口

    • 接收客户端请求

    • 通过回调函数处理请求并返回结果

  3. UDP客户端 (UdpClient.cc)

    • 连接到指定IP和端口的服务器

    • 从用户获取输入并发送到服务器

    • 接收并显示服务器的响应

  4. 主程序 (main.c)

    • 初始化并启动UDP服务器

    • 实现命令执行功能(ExcuteCommand函数)

    • 将客户端发来的命令在服务器端执行,并将执行结果返回给客户端

工作流程:

  1. 客户端输入命令
  2. 通过UDP发送到服务器
  3. 服务器接收命令并在本地执行
  4. 将执行结果返回给客户端
  5. 客户端显示结果

也就是说main.c运行后创建服务器端,客户端运行可以和这个服务器端通信。

这实际上是一个简单的远程命令执行系统,允许客户端远程在服务器上执行命令并获取结果。不过需要注意,当前实现没有加入安全机制(如身份验证、命令过滤等),在实际使用中需要添加相应的安全措施。

http://www.dtcms.com/wzjs/260449.html

相关文章:

  • 域名访问网站怎么下载网店运营与推广
  • 余姚网站建设设计网络营销的含义是什么
  • 长沙找人做网站营销网络的建设
  • 湖南做网站价格宁波seo教程网
  • 莱芜人才网最新招聘google搜索引擎优化
  • lib wordpress达州seo
  • 莱芜最新广州网站运营专注乐云seo
  • 甘肃兰州做网站360网站收录提交
  • 郑州做网站找谁武汉最新今天的消息
  • 遵义建立公司网站的步骤百度平台营销软件
  • 企业模板网站怎么做竞价排名服务
  • 做计算机网站有哪些内容软文广告发布平台
  • 新乡市做网站的公司软文推广的优点
  • 网站建设培训业务心得厦门头条今日新闻
  • 百度网站搜索关键字seo上首页
  • 自己做的网站怎么用qq登入宁波网络营销策划公司
  • 莆田网站建设设计一个完整的产品运营方案
  • 国内优秀网页设计网站免费友情链接平台
  • 怎样看网站做的好不好搜狗提交入口网址
  • 小企业网站建设一般收费星巴克营销策划方案
  • 杭州做营销型网站友情链接推广
  • 有没有做旅游攻略的网站精准营销系统价值
  • 三个年轻人做电影网站800万镇江市网站
  • 百度搜不到 但搜关键词有的网站百度官方入口
  • 郑州招聘网站推广2024年重大新闻摘抄
  • 公司做普通网站会计培训机构
  • 动漫电影做英语教学视频网站seo网络推广排名
  • 做网站的策划需要做什么百度小程序对网站seo
  • 金山区网站制作查询网官网
  • 学校联网网站建设百度拉新推广平台