简单的Udp服务器
目录
- 简单的UDP网络程序
- 1.1 UdpServer.hpp
- 1.2 UdpClient.cc
- 1.3 main.cc
- 1.4 makefile
- 1.5 log.hpp
简单的UDP网络程序
1.1 UdpServer.hpp
#pragma once#include <iostream>
using namespace std;#include <unistd.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <arpa/inet.h>
#include <netinet/in.h>
#include "log.hpp"
#include <strings.h>
#include <functional>
#include <cstring>
#include <unordered_map>const static int NUM = 1024;
const static string DEFAULT_IP = "0.0.0.0";
const static uint16_t DEFAULT_PORT=8080;using func_t=function<string(string)>;Log log;class UdpServer
{
public:UdpServer(func_t func,uint16_t port=DEFAULT_PORT,string ip = DEFAULT_IP): _ip(ip), _port(port), _sockid(-1),_func(func){}~UdpServer(){if (_sockid > 0){close(_sockid);}}void Init(){// 创建套接字_sockid = socket(AF_INET, SOCK_DGRAM, 0);if (_sockid < 0){log(Fatal, "socket failed");exit(2);}log(Info,"create socket successful, sockid:%d",_sockid);// 绑定struct sockaddr_in local;bzero(&local, sizeof(local));local.sin_family = AF_INET;local.sin_port = htons(_port);//绑定任意地址,可以接收任意发送给该主机的信息,而不是绑定一个具体的IP地址local.sin_addr.s_addr = INADDR_ANY;if (bind(_sockid, (struct sockaddr *)&local, sizeof(local)) < 0){log(Fatal, "bind failed, errno:%d, error code:%s",errno,strerror(errno));exit(3);}log(Info, "Server bind successful");}//通过哈希表检查用户是否已经连上,如果没有就添加到连接的列表中void CheckUser(const struct sockaddr_in& client){string clientIp=inet_ntoa(client.sin_addr);auto it=_online_client.find(clientIp);if(it==_online_client.end()){_online_client.insert({clientIp,client});std::cout << "[" << clientIp << ":" << ntohs(client.sin_port) << "] add to online user." << std::endl;}}//广播给所有人,即给所有连上该服务器的人都发送这条信息,类似于我们的微信群,//自己发出的信息所有人都能看见void BroadCast(const string& info,const string& clientip,const uint16_t& clientport){for(const auto& it:_online_client){string message="client";message+='[';message+="clientip:";message+=clientip;message+=' ';message+="clientport";message+=":";message+=to_string(clientport);message+="]# ";message+=info;sendto(_sockid,message.c_str(),message.size(),0,(struct sockaddr*)(&it.second),sizeof(it.second));}}//启动服务器void Run(){struct sockaddr_in client;socklen_t len = sizeof(client);bzero(&client, sizeof(client));char buffer[NUM];bzero(buffer, sizeof(buffer));while (true){ssize_t s = recvfrom(_sockid, buffer, sizeof(buffer) - 1, 0, (struct sockaddr *)&client, &len);if (s > 0){buffer[s] = '\0';//cout << "client# " << buffer << endl;//printf("client[ip:%d,port:%d]# \n",client.sin_addr.s_addr,client.sin_port);char* clientip=inet_ntoa(client.sin_addr);//检查CheckUser(client);cout << "client[ip:"<<clientip<<" port:"<<ntohs(client.sin_port)<<"]# " << buffer << endl;uint16_t clientport=ntohs(client.sin_port);//广播给所有人BroadCast(buffer,clientip,clientport);}else if(s==0){log(Warning,"client quit...");break;}else{log(Fatal,"recvfrom failed...");break;}//string ret=_func(buffer);//sendto(_sockid, ret.c_str(), ret.size(), 0, (struct sockaddr *)&client, len);}}private:string _ip;uint16_t _port;int _sockid;//回调函数func_t _func;//通过IP地址映射标识一个已经连上服务器的客户端unordered_map<string,struct sockaddr_in> _online_client;
};
1.2 UdpClient.cc
#include <iostream>
using namespace std;#include <unistd.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <arpa/inet.h>
#include <netinet/in.h>
#include <strings.h>
#include <pthread.h>
#include <cstring>// 重定向:2>/dev/pts/(1,2,3,4)//UdpClient.ccconst static int NUM = 1024;//客户端使用手册
void Usage(string argv)
{cout << "\n\t"<< "Usage:" << argv << " ServerIp ServerPort" << endl<<endl;
}struct ThreadData
{int sockid;struct sockaddr_in server;string ip;
};//读取信息
void* recver_message(void* argv)
{//线程分离pthread_detach(pthread_self());ThreadData* td=static_cast<ThreadData*>(argv);char buffer[4096];memset(buffer,0,sizeof(buffer));while(true){struct sockaddr_in t;socklen_t len=sizeof(t);ssize_t s=recvfrom(td->sockid,buffer,sizeof(buffer)-1,0,(struct sockaddr*)&t,&len);string tip=inet_ntoa(t.sin_addr);if(s>0){buffer[s]='\0';// cout<<"server# "<<tmp<<endl;printf("server[ip:%s,port:%d]# %s\n",tip.c_str(),ntohs(t.sin_port),buffer);}}return nullptr;
}//发送信息
void * sender_message(void* argv)
{pthread_detach(pthread_self());ThreadData* td=static_cast<ThreadData*>(argv);std::string welcome = td->ip;welcome += " comming...";sendto(td->sockid, welcome.c_str(), welcome.size(), 0, (struct sockaddr *)&(td->server), sizeof(td->server));string buffer;while(true){cerr<<"Please Enter# ";getline(cin,buffer);sendto(td->sockid,buffer.c_str(),buffer.size(),0,(struct sockaddr*)(&(td->server)),sizeof(td->server));}return nullptr;
}int main(int argc, char *argv[])
{if (argc != 3){Usage(argv[0]);exit(1);}string ServerIp=argv[1];string str = argv[2];uint16_t ServerPort = (uint16_t)stoi(str.c_str());ThreadData td;//创建套接字int sockid=socket(AF_INET,SOCK_DGRAM,0);td.server.sin_family = AF_INET;td.server.sin_addr.s_addr=inet_addr(ServerIp.c_str());td.server.sin_port=htons(ServerPort);td.ip=ServerIp;td.sockid=sockid;socklen_t len=sizeof(td.server);pthread_t recver,sender;pthread_create(&recver,nullptr,recver_message,&td);pthread_create(&sender,nullptr,sender_message,&td); while(true){sleep(1);}close(sockid);
}
1.3 main.cc
#include <iostream>
using namespace std;
#include <string>
#include "UdpServer.hpp"
#include <vector>
#include <memory>//服务器的启动方式
void Usage(string argv)
{cout << "\n\t"<< "Usage:" << argv << " ServerPort" << endl<< endl;
}string func(string s)
{return s + " already handled\n";
}//安全检查
bool SafeCheck(const string &cmd)
{//把客户端发过来的信息当作命令来解析,检查该信息是否合法vector<string> key_word = {"rm", "mv", "cp", "kill", "sudo", "unlink", "uninstall","yum", "top", "while"};for(const auto& s:key_word){auto pos = cmd.find(s);if(pos!=string::npos){return false;}}return true;
}//执行指令
string ExcuteCommand(string cmd)
{if (!SafeCheck(cmd)){return "bad man\n";}//popen函数会自己创建子进程,创建管道,让子进程执行cmd.c_str()命令,//并通过管道把执行cmd命令的结果读取到FILE*的结构体对象中FILE *p = popen(cmd.c_str(), "r");if (nullptr == p){perror("popen failed");exit(5);}string ret="\n";char buffer[4096];while (true){//把执行命令后的结果按行读取出来char *s = fgets(buffer, sizeof(buffer) - 1, p);if (nullptr == s){break;}ret += buffer;}pclose(p);return ret;
}int main(int argc, char *argv[])
{if (argc != 2){Usage(argv[0]);exit(1);}string str = argv[1];uint16_t ServerPort = (uint16_t)stoi(str.c_str());unique_ptr<UdpServer> svr(new UdpServer(func, ServerPort));svr->Init();svr->Run();return 0;
}
1.4 makefile
.PHONY:all
all:Client ServerClient:UdpClient.ccg++ -o $@ $^ -std=c++11 -lpthreadServer:main.ccg++ -o $@ $^ -std=c++11 -lpthread.PHONY:clean
clean:rm -f Client Server
1.5 log.hpp
#pragma once#include <iostream>
using namespace std;
#include <sys/types.h>
#include <sys/stat.h>
#include <unistd.h>
#include <fcntl.h>
#include <string>
#include <time.h>
#include <stdarg.h>// 日志等级
#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 SIZE 1024#define LogFile "log.txt"class Log
{
public:Log(){printMethod = Screen;path = "./log/";}void Enable(int mothod){printMethod = mothod;}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 string& logtxt){switch(printMethod){case Screen:{cout<<logtxt<<endl;break;}case OneFile:{PrintOneFile(LogFile,logtxt);break;}case Classfile:{PrintClassfile(level,logtxt);break;}default:{break;}}}void PrintOneFile(const string& logname,const string& logtxt){string _logname=path+logname;int fd=open(_logname.c_str(),O_WRONLY|O_CREAT|O_APPEND,0666);if(fd<0){perror("open fail");return;}write(fd,logtxt.c_str(),logtxt.size());close(fd);}void PrintClassfile(int level,const string& logtxt){string filename=LogFile;filename+='.';filename+=LevelToString(level);PrintOneFile(filename,logtxt);}void operator()(int level,const char* format,...){time_t t=time(nullptr);struct tm* ctime=localtime(&t);char leftbuffer[SIZE];snprintf(leftbuffer,SIZE,"[%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]={0};vsnprintf(rightbuffer,SIZE,format,s);va_end(s);char logtxt[SIZE*2];snprintf(logtxt,sizeof(logtxt),"%s %s",leftbuffer,rightbuffer);printlog(level,logtxt);}~Log(){}private:// 打印方法int printMethod;string path;
};相关文章:
简单的Udp服务器
目录 简单的UDP网络程序1.1 UdpServer.hpp1.2 UdpClient.cc1.3 main.cc1.4 makefile1.5 log.hpp 简单的UDP网络程序 1.1 UdpServer.hpp #pragma once#include <iostream> using namespace std;#include <unistd.h> #include <sys/types.h> #include <sy…...
【Linux进程间通信】用管道实现简单的进程池、命名管道
【Linux进程间通信】用管道实现简单的进程池、命名管道 目录 【Linux进程间通信】用管道实现简单的进程池、命名管道为什么要实现进程池?代码实现命名管道创建一个命名管道 理解命名管道匿名管道与命名管道的区别命名管道的打开规则 作者:爱写代码的刚子…...
Linux操作系统基础(九):Linux用户与权限
文章目录 Linux用户与权限 一、文件权限概述 二、终端命令:组管理 三、终端命令:用户管理 1、创建用户 、 设置密码 、删除用户 2、查看用户信息 3、su切换用户 4、sudo 4.1、给指定用户授予权限 4.2、使用 用户 zhangsan登录, 操作管理员命令…...
蓝桥杯——第 5 场 小白入门赛(c++详解!!!)
文章目录 1 十二生肖基本思路: 2 欢迎参加福建省大学生程序设计竞赛基本思路:代码: 3 匹配二元组的数量基本思路:代码: 4 元素交换基本思路:代码: 5 下棋的贝贝基本思路:代码: 6 方程…...
Codeforces Round 303 (Div. 2)C. Kefa and Park(DFS、实现)
文章目录 题面链接题意题解代码总结 题面 链接 C. Kefa and Park 题意 求叶节点数量,叶节点满足,从根节点到叶节点的路径上最长连续1的长度小于m 题解 这道题目主要是实现,当不满足条件时直接返回。 到达叶节点后统计答案,用…...
797. 差分
Problem: 797. 差分 文章目录 思路解题方法复杂度Code 思路 这是一个差分数组的问题。差分数组的主要适用场景是频繁对原始数组的某一个区间进行增减操作。这种操作是区间修改操作,在这种操作下,差分数组只需要对区间的两个端点进行操作,时间…...
2024.2.5 vscode连不上虚拟机,始终waiting for server log
昨天还好好的,吃着火锅,做着毕设,突然就被vscode给劫了。 起初,哥们跟着网上教程有模有样地删除了安装包缓存,还删除了.vscode-server,发现没卵用,之前都是搜那个弹窗报错。 后来发现原来是vsco…...
CSS基础---新手入门级详解
CSS:层叠样式表 CSS(Cascading Style Sheets,层叠样式表),是一种用来为结构化文档添加样式(字体、间距和颜色)的计算机语言,css扩展名为.css。 实例: <!DOCTYPE html><html> <head><…...
Python中Pymysql库的常见用法和代码示例
关注B站可以观看更多实战教学视频:肆十二-的个人空间-肆十二-个人主页-哔哩哔哩视频 (bilibili.com) pymysql是一个用于连接MySQL数据库的Python库,它允许你执行SQL查询并处理返回的结果。以下是pymysql库的一些常见用法和代码示例: 1. 安装…...
使用 WPF + Chrome 内核实现高稳定性的在线客服系统复合应用程序
对于在线客服与营销系统,客服端指的是后台提供服务的客服或营销人员,他们使用客服程序在后台观察网站的被访情况,开展营销活动或提供客户服务。在本篇文章中,我将详细介绍如何通过 WPF Chrome 内核的方式实现复合客服端应用程序。…...
fastapi mysql 开发restful 3
pip install mysql-connector-python pymysql 数据库链接 创建src目录,里面创建db.py 代码如下: # 导入mysql.connector模块,该模块提供了与MySQL数据库进行连接和交互的功能。 import mysql.connector # 定义一个函数get_db_connectio…...
【Uniapp uni-app学习与快速上手——详细讲解】
Uniapp uni-app学习与快速上手——详细讲解 1. 介绍2. Uni-app 学习资源3. 快速上手4. 开始第一个项目5. 调试和发布 1. 介绍 Uni-app 是一个使用 Vue.js 编写多端应用的前端框架。开发者可以编写一份代码,然后发布到iOS、Android、网页(响应式…...
剑指offer——旋转数组的最小数字
目录 1. 题目描述2. 分析思路2.1 示例分析 3. 更完美的做法 1. 题目描述 把一个数组最开始的若干个元素搬到数组的末尾,我们称之为数组的旋转。输入一个递增排序的数组的一个旋转,输出旋转数组的最小元素。例如数组{3.4,5,1.2}为{1.2,3,4,5}的一个旋转&a…...
盘点数据可视化大屏焦点图十种样式
所谓焦点图就是大屏中居于中心位置的图,是视觉的中心,本位列举了十种焦点图样式供大家参考。 地球作为焦点图 图片来自网络 地图作为焦点图 图片来自网络 城市作为焦点图 图片来自网络 园区做焦点图 图片来自网络 建筑做焦点图 图片来自网络 生产线…...
问题 G: 老鼠和猫的交易
题目描述 小老鼠准备了M磅的猫粮,准备去和看守仓库的猫做交易,因为仓库里有小老鼠喜欢吃的五香豆。 仓库有N个房间; 第i个房间有J[i] 磅的五香豆,并且需要用F[i]磅的猫粮去交换; 老鼠不必交换该房间所有的五香豆&…...
HiveSQL——借助聚合函数与case when行转列
一、条件函数 if 条件函数 if函数是最常用到的条件函数,其写法是if(xn,a,b), xn代表判断条件,如果xn时,那么结果返回a ,否则返回b。 selectif(age < 25 or age is null, 25岁以下, 25岁以上) as age_cnt,count(1) as number from table…...
冒泡排序,判断回文,以及12-24小时制
6-7 定义函数,完成冒泡排序算法。 本题定义一个冒泡排序算法的函数,调用函数后实现数组的升序排序,其数组长度为任意长度。 函数接口定义: 在这里描述函数接口。例如: void sort(int arr[],int n); 在这里解释接口…...
【Vue】computed与watch
📝个人主页:五敷有你 🔥系列专栏:Vue⛺️稳重求进,晒太阳 计算属性 概念:基于现有的数据,计算出来新的属性,依赖的数据变化,自动重新计算 语法: 声明…...
探索设计模式的魅力:捕捉变化的风-用观察者模式提升用户体验
设计模式专栏:http://t.csdnimg.cn/U54zu 目录 一、引言 核心概念 应用场景 可以解决的问题 二、场景案例 2.1 不用设计模式实现 2.2 存在问题 2.3 使用设计模式实现 2.4 成功克服 三、工作原理 3.1 结构图和说明 3.2 工作原理详解 3.3 实现步骤 四、 优…...
SpringCloud-高级篇(十九)
我们已经学过使用 SpringAMQP去收和发消息,但是发和收消息是只是MQ最基本的功能了,在收发消息的过程中,会有很多的问题需要去解决,下面需要学习rabbitMQ的高级特性去解决 死信交换机:这个可以帮助我们实现消息的延迟的…...
docker详细操作--未完待续
docker介绍 docker官网: Docker:加速容器应用程序开发 harbor官网:Harbor - Harbor 中文 使用docker加速器: Docker镜像极速下载服务 - 毫秒镜像 是什么 Docker 是一种开源的容器化平台,用于将应用程序及其依赖项(如库、运行时环…...
Admin.Net中的消息通信SignalR解释
定义集线器接口 IOnlineUserHub public interface IOnlineUserHub {/// 在线用户列表Task OnlineUserList(OnlineUserList context);/// 强制下线Task ForceOffline(object context);/// 发布站内消息Task PublicNotice(SysNotice context);/// 接收消息Task ReceiveMessage(…...
可靠性+灵活性:电力载波技术在楼宇自控中的核心价值
可靠性灵活性:电力载波技术在楼宇自控中的核心价值 在智能楼宇的自动化控制中,电力载波技术(PLC)凭借其独特的优势,正成为构建高效、稳定、灵活系统的核心解决方案。它利用现有电力线路传输数据,无需额外布…...
CMake基础:构建流程详解
目录 1.CMake构建过程的基本流程 2.CMake构建的具体步骤 2.1.创建构建目录 2.2.使用 CMake 生成构建文件 2.3.编译和构建 2.4.清理构建文件 2.5.重新配置和构建 3.跨平台构建示例 4.工具链与交叉编译 5.CMake构建后的项目结构解析 5.1.CMake构建后的目录结构 5.2.构…...
服务器硬防的应用场景都有哪些?
服务器硬防是指一种通过硬件设备层面的安全措施来防御服务器系统受到网络攻击的方式,避免服务器受到各种恶意攻击和网络威胁,那么,服务器硬防通常都会应用在哪些场景当中呢? 硬防服务器中一般会配备入侵检测系统和预防系统&#x…...
1.3 VSCode安装与环境配置
进入网址Visual Studio Code - Code Editing. Redefined下载.deb文件,然后打开终端,进入下载文件夹,键入命令 sudo dpkg -i code_1.100.3-1748872405_amd64.deb 在终端键入命令code即启动vscode 需要安装插件列表 1.Chinese简化 2.ros …...
相机Camera日志分析之三十一:高通Camx HAL十种流程基础分析关键字汇总(后续持续更新中)
【关注我,后续持续新增专题博文,谢谢!!!】 上一篇我们讲了:有对最普通的场景进行各个日志注释讲解,但相机场景太多,日志差异也巨大。后面将展示各种场景下的日志。 通过notepad++打开场景下的日志,通过下列分类关键字搜索,即可清晰的分析不同场景的相机运行流程差异…...
C++ 求圆面积的程序(Program to find area of a circle)
给定半径r,求圆的面积。圆的面积应精确到小数点后5位。 例子: 输入:r 5 输出:78.53982 解释:由于面积 PI * r * r 3.14159265358979323846 * 5 * 5 78.53982,因为我们只保留小数点后 5 位数字。 输…...
基于matlab策略迭代和值迭代法的动态规划
经典的基于策略迭代和值迭代法的动态规划matlab代码,实现机器人的最优运输 Dynamic-Programming-master/Environment.pdf , 104724 Dynamic-Programming-master/README.md , 506 Dynamic-Programming-master/generalizedPolicyIteration.m , 1970 Dynamic-Programm…...
C# 求圆面积的程序(Program to find area of a circle)
给定半径r,求圆的面积。圆的面积应精确到小数点后5位。 例子: 输入:r 5 输出:78.53982 解释:由于面积 PI * r * r 3.14159265358979323846 * 5 * 5 78.53982,因为我们只保留小数点后 5 位数字。 输…...
