【网络】UDP的应用场景

文章目录

  • 翻译功能
  • 命令行解析
  • 网络聊天室
  • UDP之Windows与Linux

翻译功能

我们写的UDP服务端并不是只接收到数据就完了,还需要进行处理任务

我们可以在服务端udpServer.hpp中设置一个回调函数 _callback,具体的逻辑通过udpServer.cc中由外部进行传入

代码如下所示:

 		void start(){// 服务器的本质其实就是一个死循环char buffer[gnum];for(;;){// 读取数据struct sockaddr_in peer;socklen_t len = sizeof(peer); //必填ssize_t s = recvfrom(_sockfd, buffer, sizeof(buffer) - 1, 0, (struct sockaddr*)&peer, &len);if(s > 0){buffer[s] = 0;string clientip = inet_ntoa(peer.sin_addr); uint16_t clientport = ntohs(peer.sin_port);string message = buffer;cout << clientip <<"[" << clientport << "]# " << message << endl;//把收到的消息打印出来_callback(_sockfd, clientip, clientport, message);}}}

翻译功能:客户端输入一个单词,然后发送给服务端,然后去接收服务端翻译之后的结果。

首先提供一个字典dict:把鞋有英语和汉语对应的文件dicTxt加载进我们的unordered_map词典,此时的unordered_map就保存了字典的内容

dict.txt:外部文件可由自己填写补充,这里只是给个样例测试代码而已

apple:苹果
world:世界
hello:你好
goodman:你是一个好人
const std::string dictTxt="./dict.txt";//文件
unordered_map<string, string> dict;//字典

下面,初始化我们的字典:打开文件,把文件中的每一行切分成key和value,也就是英文和中文,然后把结果插入到dict中,也就是把结果放进dict中,代码如下:

static bool cutString(const string &target, string *s1, string *s2, const string &sep)
{//apple:苹果auto pos = target.find(sep);if(pos == string::npos) return false;*s1 = target.substr(0, pos); //[)*s2 = target.substr(pos + sep.size()); //[)return true;
}static void initDict()
{ifstream in(dictTxt, std::ios::binary);if(!in.is_open()){cerr << "open file " << dictTxt << " error" << endl;exit(OPEN_ERR);}string line;std::string key, value;while(getline(in, line))//读取文件{if(cutString(line, &key, &value, ":")){dict.insert(make_pair(key, value));}}in.close();cout << "load dict success" << endl;
}

在udpServer.cc中通过函数handlerMessage处理数据,然后在把处理的结果反馈给客户端:

void handlerMessage(int sockfd, string clientip, uint16_t clientport, string message)
{string response_message;auto iter = dict.find(message);if(iter == dict.end()) response_message = "unknown";else response_message = iter->second;// 开始返回struct sockaddr_in client;bzero(&client, sizeof(client));client.sin_family = AF_INET;client.sin_port = htons(clientport);client.sin_addr.s_addr = inet_addr(clientip.c_str());sendto(sockfd, response_message.c_str(), response_message.size(), 0, (struct sockaddr*)&client, sizeof(client));
}

客户端udpClient.hpp输入消息cin并发送sendto给服务端,然后服务端udpServer.hpp调用回调函数对消息进行翻译,翻译完成后把最终的结果在传送sendto给客户端,客户端udpClient.hpp在接收recvfrom翻译之后的结果,最终把翻译结果打印出来即可:

 		void run(){struct sockaddr_in server;memset(&server, 0, sizeof(server));server.sin_family = AF_INET;server.sin_addr.s_addr = inet_addr(_serverip.c_str());server.sin_port = htons(_serverport);string message;char cmdline[1024];while (!_quit){cout<<"Please Enter#";cin>>message;sendto(_sockfd,message.c_str(),message.size(),0,(struct sockaddr*)&server,sizeof(server));char buffer[1024];struct sockaddr_in temp;socklen_t temp_len = sizeof(temp);size_t n = recvfrom(_sockfd,buffer,sizeof(buffer)-1,0,(struct sockaddr*)&temp,&temp_len);if(n>0) buffer[n] = 0;cout<<"服务器的翻译结果# "<<buffer<<endl;   }}

下面,进行测试运行结果:

//udpServer.cc
int main(int argc, char *argv[])
{if (argc != 2){Usage(argv[0]);exit(USAGE_ERR);}uint16_t port = atoi(argv[1]);initDict();std::unique_ptr<udpServer> usvr(new udpServer(handlerMessage, port));
}
//udpClient.cc
int main(int argc, char *argv[])
{if(argc != 3){Usage(argv[0]);exit(1);}string serverip = argv[1];uint16_t serverport = atoi(argv[2]);unique_ptr<udpClient> ucli(new udpClient(serverip, serverport));ucli->initClient();ucli->run();return 0;
}

先启动服务端:

image-20230530191842224

在启动客户端输入信息,给服务端传送消息,服务端收到消息打印出来,并将翻译完成的结果返回给客户端,客户端再把翻译后的结果打印出来,这就是上面所说的整个过程:

image-20230530191942072

image-20230530192002279

命令行解析

借用popen接口:(功能相当于pipe+fork,exec*)

#include <stdio.h>
FILE *popen(const char *command, const char *type);
int pclose(FILE *stream);

command:传递进来的字符串,比如 ls -a -l ;type:以什么方式打开文件(r/w/a),我们通过一个函数execComand进行调用即可,只需要在udpServer.cc文件中修改传入的函数即可实现该功能:

void execCommand(int sockfd, string clientip, uint16_t clientport, string cmd)
{//1. cmd解析,ls -a -l//先禁止一下非法操作,防止有人搞破坏if(cmd.find("rm") != string::npos || cmd.find("mv") != string::npos || cmd.find("rmdir") != string::npos){cerr << clientip << ":" << clientport << " 正在做一个非法的操作: " << cmd << endl;return;}string response;FILE *fp = popen(cmd.c_str(), "r");if(fp == nullptr) response = cmd + " exec failed";char line[1024];while(fgets(line, sizeof(line), fp)){response += line;}pclose(fp);// 开始返回struct sockaddr_in client;bzero(&client, sizeof(client));client.sin_family = AF_INET;client.sin_port = htons(clientport);client.sin_addr.s_addr = inet_addr(clientip.c_str());sendto(sockfd, response.c_str(), response.size(), 0, (struct sockaddr*)&client, sizeof(client));
}

测试运行:

//udpServer.cc
int main(int argc, char *argv[])
{if (argc != 2){Usage(argv[0]);exit(USAGE_ERR);}uint16_t port = atoi(argv[1]);std::unique_ptr<udpServer> usvr(new udpServer(execCommand, port));
}

image-20230530194723712

image-20230530194732874

网络聊天室

我们需要去管理用户,而对于每个用户我们用IP和port来标识唯一性,那么多的用户我们可以用哈希表来进行统一管理:

class User
{
public:User(const string &ip, const uint16_t &port) : _ip(ip), _port(port){}~User(){}string ip(){ return _ip; }uint16_t port(){ return _port; }
private:string _ip;uint16_t _port;
};class OnlineUser
{
public:OnlineUser() {}~OnlineUser() {}void addUser(const string &ip, const uint16_t &port){string id = ip + "-" + to_string(port);users.insert(make_pair(id, User(ip, port)));}void delUser(const string &ip, const uint16_t &port){string id = ip + "-" + to_string(port);users.erase(id);}bool isOnline(const string &ip, const uint16_t &port){string id = ip + "-" + to_string(port);return users.find(id) == users.end() ? false : true;}void broadcastMessage(int sockfd, const string &ip, const uint16_t &port, const string &message){for (auto &user : users){struct sockaddr_in client;bzero(&client, sizeof(client));client.sin_family = AF_INET;client.sin_port = htons(user.second.port());client.sin_addr.s_addr = inet_addr(user.second.ip().c_str());string s = ip + "-" + to_string(port) + "# ";s += message;sendto(sockfd, s.c_str(), s.size(), 0, (struct sockaddr *)&client, sizeof(client));}}private:unordered_map<string, User> users;
};

在回调函数中,如果收到的消息是online,就把用户添加进哈希表。如果是offline,就从哈希表中删除

if (message == "online") onlineuser.addUser(clientip, clientport);
if (message == "offline") onlineuser.delUser(clientip, clientport);
OnlineUser onlineuser;
void routeMessage(int sockfd, string clientip, uint16_t clientport, string message)
{if (message == "online") onlineuser.addUser(clientip, clientport);if (message == "offline") onlineuser.delUser(clientip, clientport);if (onlineuser.isOnline(clientip, clientport)){// 消息的路由onlineuser.broadcastMessage(sockfd, clientip, clientport, message);}else{struct sockaddr_in client;bzero(&client, sizeof(client));client.sin_family = AF_INET;client.sin_port = htons(clientport);client.sin_addr.s_addr = inet_addr(clientip.c_str());string response = "你还没有上线,请先上线,运行: online";sendto(sockfd, response.c_str(), response.size(), 0, (struct sockaddr *)&client, sizeof(client));}
}

多线程:客户端udpClient.hpp不能立即收到消息打印出来,为了解决这个问题我们可以使用多线程,一个线程专门接收消息,一个线程专门发送消息:让主线程负责发送消息,子线程负责接收消息:

static void *readMessage(void *args){int sockfd = *(static_cast<int *>(args));pthread_detach(pthread_self());while (true){char buffer[1024];struct sockaddr_in temp;socklen_t temp_len = sizeof(temp);size_t n = recvfrom(sockfd, buffer, sizeof(buffer) - 1, 0, (struct sockaddr *)&temp, &temp_len);if (n >= 0)buffer[n] = 0;cout << buffer << endl;}return nullptr;}void run(){pthread_create(&_reader, nullptr, readMessage, (void *)&_sockfd);struct sockaddr_in server;memset(&server, 0, sizeof(server));server.sin_family = AF_INET;server.sin_addr.s_addr = inet_addr(_serverip.c_str());server.sin_port = htons(_serverport);string message;char cmdline[1024];while (!_quit){fprintf(stderr, "Enter# ");fflush(stderr);fgets(cmdline, sizeof(cmdline), stdin);cmdline[strlen(cmdline)-1] = 0;message = cmdline;sendto(_sockfd, message.c_str(), message.size(), 0, (struct sockaddr *)&server, sizeof(server));}}

image-20230530213639848

image-20230530213650726

UDP之Windows与Linux

UDP的实现可以在不同的平台上进行交互的,在这里我们以Linux充当服务端,windows充当客户端,进行连通

windows端代码:

#define _CRT_SECURE_NO_WARNINGS
#pragma warning(disable:4996)#include <iostream>
#include <string>
#include <cstring>
#include <WinSock2.h>#pragma comment(lib,"ws2_32.lib")using namespace std;
uint16_t serverport = 8080;
string serverip = "8.134.152.121";int main()
{WSAData wsd;if (WSAStartup(MAKEWORD(2, 2), &wsd) != 0){cout << "WSAStartup Error = " << WSAGetLastError() << endl;return 0;}else{cout << "WSAStartup Success" << endl;}SOCKET csock = socket(AF_INET, SOCK_DGRAM, 0);if (csock == SOCKET_ERROR){cout << "socket Error = " << WSAGetLastError() << endl;return 1;}else{cout << "socket success" << endl;}struct sockaddr_in server;memset(&server, 0, sizeof(server));server.sin_family = AF_INET;server.sin_port = htons(serverport);server.sin_addr.s_addr = inet_addr(serverip.c_str());
#define NUM 1024char inbuffer[NUM];string line;while (true){cout << "Please Enter#";getline(cin, line);int n = sendto(csock, line.c_str(), line.size(), 0, (struct sockaddr*)&server, sizeof(server));if (n < 0){cerr << "sendto error!" << endl;break;}struct sockaddr_in peer;int peerlen = sizeof(peer);inbuffer[0] = 0;n = recvfrom(csock, inbuffer, sizeof(inbuffer) - 1, 0, (struct sockaddr*)&peer, &peerlen);if (n > 0){inbuffer[n] = 0;cout << "server 返回的消息是#" << inbuffer << endl;}else break;}closesocket(csock);WSACleanup();return 0;
}

Linux端代码:

pragma once#include <iostream>
#include <string>
#include <strings.h>
#include <cerrno>
#include <cstring>
#include <functional>
#include <unistd.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <arpa/inet.h>
#include <netinet/in.h>namespace Server
{using namespace std;static const string defaultIp = "0.0.0.0";static const int gnum = 1024;enum  {USAGE_ERR = 1,SOCKET_ERR,BIND_ERR,OPEN_ERR};typedef function<void (int,string,uint16_t,string)> func_t;class udpServer{public:udpServer(const func_t&cb,const uint16_t&port,const string&ip = defaultIp):_callback(cb),_port(port),_ip(ip),_sockfd(-1){}void initServer(){_sockfd = socket(AF_INET,SOCK_DGRAM,0);if(_sockfd == -1){cerr<<"sdocket error: "<<errno<<" : "<<strerror(errno)<<endl;exit(SOCKET_ERR);}cout<<"socket success: "<<" : "<<_sockfd<<endl;struct 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());int n = bind(_sockfd,(struct sockaddr*)&local,sizeof(local));if(n == -1){cerr<<"bind errpr: "<<errno<<" : "<<strerror(errno)<<endl;exit(BIND_ERR);}}void start(){char buffer[gnum];for(;;){struct sockaddr_in peer;socklen_t len = sizeof(peer);ssize_t s = recvfrom(_sockfd,buffer,sizeof(buffer)-1,0,(struct sockaddr*)&peer,&len);if(s>0){buffer[s] = 0;string clientip = inet_ntoa(peer.sin_addr);uint16_t clientport = ntohs(peer.sin_port);string message = buffer;cout<<clientip<<"["<<clientport<<"]#"<< message<<endl;_callback(_sockfd,clientip,clientport,message);}}}~udpServer(){}private:int _sockfd;uint16_t _port;string _ip;func_t _callback;};
}
//udpServer.cc
#include <iostream>
#include <memory>
#include "udpServer.hpp"
using namespace std;
using namespace Server;static void Usage(string proc)
{cout<<"\nUsage:\n\t"<<proc<<" locla_port\n\n";
}void handlerMessage(int sockfd,string clientip,uint16_t clientport,string message)
{string response_message = message;response_message+=" [server echo]";struct sockaddr_in client;bzero(&client,sizeof(client));client.sin_family = AF_INET;client.sin_port = htons(clientport);client.sin_addr.s_addr = inet_addr(clientip.c_str());sendto(sockfd,response_message.c_str(),response_message.size(),0,(struct sockaddr*)&client,sizeof(client));
}int main(int argc,char*argv[])
{if(argc!=2){Usage(argv[0]);exit(USAGE_ERR);}uint16_t port = atoi(argv[1]);std::unique_ptr<udpServer> usvr(new udpServer(handlerMessage,port));usvr->initServer();usvr->start();return 0;
}

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

如若内容造成侵权/违法违规/事实不符,请联系瞎胡闹网进行投诉反馈,一经查实,立即删除!

相关文章

如何免费制作证件照

&#xff08;1&#xff09;打开微信&#xff0c;在小程序中搜索【万能工具助手】 &#xff08;2&#xff09;打开万能工具助手 选择好证件照尺寸&#xff0c;导入图片&#xff0c;它会自动抠除照片的原背景&#xff0c;点击“背景色”更换证件照底色&#xff0c;点击“美颜”&a…

如何制作电子证件照?十秒学会这个方法

如何制作电子证件照&#xff1f;现如今我们只要在网站办事或者说是报名考试都会使用到电子版的证件照&#xff0c;可以说电子证件照的应用十分广泛。那么问题来了&#xff0c;电子证件照如何制作呢&#xff1f;其实制作电子证件照并不困难&#xff0c;我们自己就可以完成。这里…

免费在线证件照制作-超级好用

地址&#xff1a;https://www.remove.bg/ 步骤&#xff1a; 1. 上传图片 2. 生成的图片&#xff0c;右上角覆盖了一个按钮&#xff0c;点击edit(编辑) 3. 点击编辑后&#xff0c;出现弹窗&#xff0c;切换到color。color第一个是取色器&#xff0c;自己随意选择颜色。还有常用…

证件照的要求是什么?

1.证件照的要求是免冠(不戴帽子)正面照片&#xff0c;照片上正常应该看到人的两耳轮廓和相当于男士的喉结处的地方 2.照片尺寸可以为一寸或二寸&#xff0c;颜色可以为黑白或彩色&#xff0c;拍照时不得上唇膏等影响真实面貌的化妆色彩&#xff0c;包括头发的染色。 3.拍照时…

手机上怎么照证件照照片?教你两招轻松拍出证件照

怎么使用手机拍出证件照呢&#xff1f;证件照是我们在日常生活或者是工作中必备的一个证件&#xff0c;很多地方都会用得到&#xff0c;大家在照证件照的时候一般都会去照相馆拍摄&#xff0c;但是随着现在电子科技的进步&#xff0c;我们已经可以使用手机就能够拍出美美的证件…

​可以给证件照换衣服的软件有哪些?教你如何一键换装

有什么软件可以给证件照换衣服呢&#xff1f;证件照是我们大学毕业之后必备的一种证件&#xff0c;报名各种考试或者是找工作都是需要使用到的。但是大家在使用证件照的时候&#xff0c;往往会因为各种原因使我们的证件照不合规定&#xff0c;其中就有因为服装不够正式导致使用…

毕业生找工作必备技能——自己制作正装证件照

又到了毕业季&#xff0c;又是令人忙忙碌碌的找工作阶段&#xff0c;都说今年是毕业生找工作最难的一年&#xff0c;希望大家都能找到心仪的工作。找工作之前&#xff0c;大家简历所需的正装证件照都准备的怎么样了&#xff1f;是否必须跑一趟照相馆再照一张正装的照片呢&#…

简历上面的证件照怎么制作?学会这个方法轻松制作

简历上面的证件照该怎么制作呢&#xff1f;很多小伙伴在大学毕业后&#xff0c;就需要找一份工作&#xff0c;而找工作的时候必然需要使用简历&#xff0c;简历上面是需要放我们的证件照的&#xff0c;而一份合适的证件照会让HR对我们更好的第一印象&#xff0c;从而也就增加面…

我的【毕业照】

2021年05月16日 毕业照 这是一篇没有谈论、介绍技术的文章&#xff0c;有的只是照片写真 #1 班级 四年的青春就这样宣布结束了 一张九宫图怎能承载我们的青春&#xff0c;愿大家前程似锦 #2 BAT高级架构师合照 就这样轻松流畅地过渡到宿舍集体照 留给我们的宿舍集体照不多&…

考研证件照要求?如何制作考研用的证件照?

考研报报名网上确认环节&#xff0c;网上确认的时候需要准备电子照片。疫情阶段今天教给大家不需要出门就可以方便&#xff0c;快捷的制作合格的证件照&#xff0c;免去出门办理和审核不过的麻烦&#xff01; 考研证件照要求&#xff1a; 1. 本人近三个月内正面、免冠、无妆、彩…

高考准考证的照片要跟大学四年吗?快GET保姆级最美证件照全攻略!

很多学弟学妹们都私信我&#xff0c;问高考准考证上的那张丑照真的要跟大学四年吗&#xff1f;的确&#xff0c;那个时候大家都熬夜苦读&#xff0c;哪有闲情逸致去打扮自己呢&#xff1f;就算拍照那天精心打扮了&#xff0c;得&#xff0c;死亡黑眼圈、死亡化妆技术、丑到爆的…

证件照还能直接换装?别再为了证件照买衣服了!证件照1秒换装换底色教程

在日常的工作学习生活当中&#xff0c;我们常常会用到证件照。但不同应用场景的证件照往往会对衣服、背景色、尺寸格式等等都有着不同的需求&#xff0c;比如&#xff1a;简历照需要穿正装、毕业照需要学士服、法考照不得着制服等等&#xff0c;这也给大家带来了很多麻烦&#…

社保证照片怎么做?一招教你get既专业又好看的证件照!

又到了毕业季&#xff0c;又有一大批小可爱即将涌入社会的浪潮&#xff01;回想起我自己刚入社会的时候&#xff0c;最迫切需要了解却又最茫然无措的就是社保的问题。那些政策云云宛若天书&#xff0c;分明每个字都认识&#xff0c;可连在一起就是啥也看不懂&#xff01;于是在…

SAP中贸易伙伴的应用原理简析

公司也称为贸易伙伴&#xff0c;是出具合并报表的组织单位&#xff0c;可以为客户和供应商分配公司&#xff08;贸易伙伴&#xff09;&#xff0c;用于识别集团内关闻公司间的业务往来&#xff0c;在编制合并报表时进行往来账务的计算处理。 如下图某贸易伙伴公司&#xff08;关…

山东大学——结算中的贸易单据

山东大学——结算中的贸易单据 结算中的贸易单据 结算中的贸易单据 国际贸易结算中&#xff0c;银行收付款是以单据为前提的。 单据的作用: →出口商履行买卖合约的证明; →对进口商来说&#xff0c;是货物的代表,是进口商付款的凭证; →重要的国际贸易融资手段。 单据按照其重…

相同名字比对公式,相似度对比算法

公司注册&#xff1a;公司名称相似如何认定&#xff1f; 公司名称相似有两种&#xff1a;名字当中的文字有与其它公司重叠&#xff08;三个字有两个相同&#xff09;、不同经营类型的公司名称&#xff0c;比如&#xff1a;“XX市美好家具贸易有限公司”和“XX市美好沐足服务有…

报价单与贸易术语关系

报价单,是新人接触外贸时必须用功的对象&#xff0c;也是新人实操过程中最关心的问题。 报价单是商业行为文件&#xff0c;包括报价单的头部、产品基本资料、产品技术参数、价格条款、数量条款、支付条、质量条款、交货期条款、品牌条款、原产地条款、报价单附注的其他资料等&a…

跨境贸易PayPal收款,个人美金额度不够了,如何提现美金?

很多做跨境贸易的朋友&#xff0c;总会遇到一些客户通过PayPal支付。自己提现几次&#xff0c;每年超过5万美元结汇额度之后&#xff0c;个人额度就不够了&#xff0c; 用亲属的又很麻烦。那么个人结汇&#xff0c;每年超过5万美元结汇额度之后&#xff0c;该如何将多余的美元低…

化工贸易拓客的10个经典方法

化工贸易拓客的10个经典方法 化工贸易精准拓客、拓客方法、客源线索获取、客源信息抓取、拓客软件、流同行的客户、截取竞争对手客户、渠道裂变方式、如何找到对化工贸易服务有需求的精准客源是每个老板每天思考要解决的问题&#xff0c;我教大家如何利用搜索引擎爬虫技术大数…

进出口贸易管理系统丨汇信

根据观察统计的角度不同&#xff0c;外贸有国际贸易&#xff08;International Trade&#xff09;与对外贸易&#xff08;Foreign Trade&#xff09;之分。 国际贸易亦称“世界贸易”&#xff0c;泛指国际间的商品和劳务&#xff08;或货物、知识和服务&#xff09;的交换。它…