织梦关闭网站,山东省建设部网站官网,云南建设工程网站,做课展网站目录
1.server 服务端
1.1.完整代码展示#xff1a;
1.2.代码解析#xff1a;
1.2.1 给服务端创建套接字
1.2.2 绑定套接字
1.2.3 服务端接受数据并返回
2.客户端#xff1a;
2.1 完整代码展示#xff1a;
2.2 代码解析 2.2.1 客户端使用手则#xff1a;
2.2.2 …目录
1.server 服务端
1.1.完整代码展示
1.2.代码解析
1.2.1 给服务端创建套接字
1.2.2 绑定套接字
1.2.3 服务端接受数据并返回
2.客户端
2.1 完整代码展示
2.2 代码解析 2.2.1 客户端使用手则
2.2.2 创建客户端套接字
2.2.3 关于客户端是否绑定问题
2.2.4 客户端传输信息给服务端 3.主函数
3.1完整代码
3.2代码解析
3.2.1 回调函数
3.2.2 功能拓展
4.log日志代码
5.makefile代码 1.server 服务端
1.1.完整代码展示
#pragma once#include iostream
#include string
#include strings.h
#include cstring
#include sys/types.h
#include sys/socket.h
#include netinet/in.h
#include arpa/inet.h
#include functional
#include Log.hpp// using func_t std::functionstd::string(const std::string);
typedef std::functionstd::string(const std::string) func_t;Log lg;enum{SOCKET_ERR1,BIND_ERR
};uint16_t defaultport 8080;
std::string defaultip 0.0.0.0;
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 socketsockfd_ socket(AF_INET, SOCK_DGRAM, 0); // PF_INETif(sockfd_ 0){lg(Fatal, socket create error, sockfd: %d, sockfd_);exit(SOCKET_ERR);}lg(Info, socket create success, sockfd: %d, sockfd_);// 2. bind socketstruct sockaddr_in local;bzero(local, sizeof(local));local.sin_family AF_INET;local.sin_port htons(port_); //需要保证我的端口号是网络字节序列因为该端口号是要给对方发送的local.sin_addr.s_addr inet_addr(ip_.c_str()); //1. string - uint32_t 2. uint32_t必须是网络序列的 // ??// 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_; // 任意地址bind 0uint16_t port_; // 表明服务器进程的端口号bool isrunning_;
};
1.2.代码解析
1.2.1 给服务端创建套接字
// 1. 创建udp socketsockfd_ socket(AF_INET, SOCK_DGRAM, 0); // PF_INETif(sockfd_ 0){lg(Fatal, socket create error, sockfd: %d, sockfd_);exit(SOCKET_ERR);}lg(Info, socket create success, sockfd: %d, sockfd_);// 2. bind socketstruct sockaddr_in local;bzero(local, sizeof(local));local.sin_family AF_INET;local.sin_port htons(port_); //需要保证我的端口号是网络字节序列因为该端口号是要给对方发送的local.sin_addr.s_addr inet_addr(ip_.c_str()); //1. string - uint32_t 2. uint32_t必须是网络序列的 // ??// local.sin_addr.s_addr htonl(INADDR_ANY);
创建套接字时我们要将字符型的port和ip转化为网络序列
参考如下
整数ip和字符串ip之间的相互转化_uint ip转string-CSDN博客
inet_addr原理-CSDN博客
1.2.2 绑定套接字
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));}
绑定套接字应注意ip和port可能绑定失败
参考如下
关于bind绑定时出现 Permission denied_bind: permission denied-CSDN博客
云服务器不允许绑定bind公网ip_bind主机-CSDN博客 1.2.3 服务端接受数据并返回 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_);} 使用 func() 函数回调从main()函数中获取数据
2.客户端
2.1 完整代码展示
#include iostream
#include cstdlib
#include unistd.h
#include strings.h
#include sys/types.h
#include sys/socket.h
#include netinet/in.h
#include arpa/inet.husing namespace std;void Usage(std::string proc)
{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);}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;server.sin_port htons(serverport); //?server.sin_addr.s_addr inet_addr(serverip.c_str());socklen_t len sizeof(server);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);// std::cout message std::endl;// 1. 数据 2. 给谁发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;
}
2.2 代码解析 2.2.1 客户端使用手则
void Usage(std::string proc)
{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);}std::string serverip argv[1];uint16_t serverport std::stoi(argv[2]);
2.2.2 创建客户端套接字 struct sockaddr_in server;bzero(server, sizeof(server));server.sin_family AF_INET;server.sin_port htons(serverport); //?server.sin_addr.s_addr inet_addr(serverip.c_str());socklen_t len sizeof(server);int sockfd socket(AF_INET, SOCK_DGRAM, 0);if (sockfd 0){cout socker error endl;return 1;}2.2.3 关于客户端是否绑定问题 1client 要bind吗要只不过不需要用户显示的bind一般有OS自由随机选择 2一个端口号只能被一个进程bind对server是如此对于client也是如此 3其实client的port是多少其实不重要只要能保证主机上的唯一性就可以 4系统什么时候给我bind呢首次发送数据的时候
参考如下: 客户端需要bind吗端口号绑定的理解_客戶端bind-CSDN博客
2.2.4 客户端传输信息给服务端 string message;char buffer[1024];while (true){cout Please Enter ;getline(cin, message);// std::cout message std::endl;// 1. 数据 2. 给谁发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;
} 3.主函数
3.1完整代码
#include UdpServer.hpp
#include memory
#include cstdio// 120.78.126.148 点分十进制字符串风格的IP地址void Usage(std::string proc)
{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;// pid_t id fork();// if(id 0)// {// // ls -a -l - ls -a -l// // exec*();// }return res;
}std::string ExcuteCommand(const std::string cmd)
{// SafeCheck(cmd);FILE *fp popen(cmd.c_str(), r);if(nullptr fp){perror(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]);std::unique_ptrUdpServer svr(new UdpServer(port));svr-Init(/**/);svr-Run(Handler);return 0;
}
3.2代码解析
3.2.1 回调函数
std::string Handler(const std::string str)
{std::string res Server get a message: ;res str;std::cout res std::endl;// pid_t id fork();// if(id 0)// {// // ls -a -l - ls -a -l// // exec*();// }return res;
}
服务端接受数据返回时的回调函数funHandler
3.2.2 功能拓展
std::string ExcuteCommand(const std::string cmd)
{// SafeCheck(cmd);FILE *fp popen(cmd.c_str(), r);if(nullptr fp){perror(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;
}
远程执行命令
参考如下
popen()-CSDN博客 4.log日志代码
#pragma once#include iostream
#include time.h
#include stdarg.h
#include sys/types.h
#include sys/stat.h
#include fcntl.h
#include unistd.h
#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.txtclass Log
{
public:Log(){printMethod Screen;path ./log/;}void Enable(int method){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 logmessage(int level, const char *format, ...)// {// time_t t time(nullptr);// struct tm *ctime localtime(t);// char leftbuffer[SIZE];// snprintf(leftbuffer, sizeof(leftbuffer), [%s][%d-%d-%d %d:%d:%d], levelToString(level).c_str(),// ctime-tm_year 1900, ctime-tm_mon 1, ctime-tm_mday,// ctime-tm_hour, ctime-tm_min, ctime-tm_sec);// // va_list s;// // va_start(s, format);// char rightbuffer[SIZE];// vsnprintf(rightbuffer, sizeof(rightbuffer), format, s);// // va_end(s);// // 格式默认部分自定义部分// char logtxt[SIZE * 2];// snprintf(logtxt, sizeof(logtxt), %s %s\n, leftbuffer, rightbuffer);// // printf(%s, logtxt); // 暂时打印// printLog(level, logtxt);// }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;int fd open(_logname.c_str(), O_WRONLY | O_CREAT | O_APPEND, 0666); // log.txtif (fd 0)return;write(fd, logtxt.c_str(), logtxt.size());close(fd);}void printClassFile(int level, const std::string logtxt){std::string filename LogFile;filename .;filename levelToString(level); // log.txt.Debug/Warning/FatalprintOneFile(filename, logtxt);}~Log(){}void operator()(int level, const char *format, ...){time_t t time(nullptr);struct tm *ctime localtime(t);char leftbuffer[SIZE];snprintf(leftbuffer, sizeof(leftbuffer), [%s][%d-%d-%d %d:%d:%d], levelToString(level).c_str(),ctime-tm_year 1900, ctime-tm_mon 1, ctime-tm_mday,ctime-tm_hour, ctime-tm_min, ctime-tm_sec);va_list s;va_start(s, format);char rightbuffer[SIZE];vsnprintf(rightbuffer, sizeof(rightbuffer), format, s);va_end(s);// 格式默认部分自定义部分char logtxt[SIZE * 2];snprintf(logtxt, sizeof(logtxt), %s %s, leftbuffer, rightbuffer);// printf(%s, logtxt); // 暂时打印printLog(level, logtxt);}private:int printMethod;std::string path;
};// int sum(int n, ...)
// {
// va_list s; // char*
// va_start(s, n);// int sum 0;
// while(n)
// {
// sum va_arg(s, int); // printf(hello %d, hello %s, hello %c, hello %d,, 1, hello, c, 123);
// n--;
// }// va_end(s); //s NULL
// return sum;
// }
5.makefile代码
.PHONY:all
all:udpserver udpclientudpserver:Main.ccg -o $ $^ -stdc11
udpclient:UdpClient.ccg -o $ $^ -stdc11.PHONY:clean
clean:rm -f udpserver udpclient