使用UDP协议实现单词翻译服务器
作者:终为nullptr
这篇文章主要为大家详细介绍了如何使用UDP协议实现英文单词翻译服务器,文中的示例代码讲解详细,具有一定的学习价值,感兴趣的小伙伴可以了解下
前言
上一篇文章中,我们使用UDP协议编码完成了一个简单的服务器,实现数据通信,服务器设计出来后目的不仅仅只是实现数据通信,而是根据客户端发过来的请求,实现一定的需求,今天我们要介绍的是当客户端给服务端发送英文单词,然后服务端获取客户端的请求,将翻译结果返回给客户端,通过这样的方式,实现了一款英文翻译服务器。下面我们就一起具体来看看是如何编码完成。
1.设计思路
如图所示
- 第一步:启动服务器,然后服务器加载词库
- 第二步:客户端向服务器,发送请求
- 第三步:服务器处理请求查找单词,将查找结果返回给客户端
- 第四步:客户端获取查询结果
2.词库设计
说明:在这里只是简单模拟实现一个词库,主要是实现业务逻辑
dict.txt:
aunt:姨母 brother:兄弟 cousin:堂兄弟 couple:夫妇 dad:爸爸 daughter:女儿 family:家 father:爸爸 grandchild:孙子 granddaughger:孙女 grandfather:祖父 grandma:外婆 grandpa:外公 granny 老奶奶
3.设计客户端
udpClient.hpp
#pragma once #include <iostream> #include <string> #include <strings.h> #include <cerrno> #include <cstring> #include <cstdlib> #include <functional> #include <unistd.h> #include <sys/types.h> #include <sys/socket.h> #include <arpa/inet.h> #include <netinet/in.h> namespace Client { using namespace std; class udpClient { public: udpClient(const string &serverIp, const uint16_t serverPort) : _serverIp(serverIp), _serverPort(serverPort), _sockfd(-1) {} void initClient() { _sockfd = socket(AF_INET, SOCK_DGRAM, 0); if (_sockfd == -1) { cerr << "socket error:" << errno << strerror(errno) << endl; exit(2); } } 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); while (1) { string message; cout << "请输入你想要翻译的单词:"; getline(cin,message); //发送请求 sendto(_sockfd, message.c_str(), message.size(), 0, (const struct sockaddr *)&server, sizeof(server)); char buffer[1024]; struct sockaddr_in temp; socklen_t len = sizeof(temp); //接受查询翻译结果 size_t n = recvfrom(_sockfd, buffer, sizeof(buffer) - 1, 0, (struct sockaddr *)&temp, &len); if (n >= 0) buffer[n] = 0; cout << "翻译的结果为: " << buffer << endl; } } private: string _serverIp; int _sockfd; uint16_t _serverPort; }; }
udpClient.cc:启动客户端
#include"udpClient.hpp" #include<memory> using namespace Client; static void Usage(string proc) { cout << "\nUsage:\n\t" << proc << " server_ip server_port\n\n"; } 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> uct(new udpClient(serverip,serverport)); uct->initClient(); uct->run(); return 0; }
4.设计服务端
udpServer.hpp
#pragma once #include <iostream> #include <string> #include <strings.h> #include <cerrno> #include <cstring> #include <cstdlib> #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; const static string defaultIP = "0.0.0.0"; 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,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<<"socket error:" << errno << strerror(errno) << endl; exit(SOCKET_ERR); } struct sockaddr_in local; bzero(&local,sizeof(local)); local.sin_family = AF_INET; local.sin_port = htons(_port); local.sin_addr.s_addr = htonl(INADDR_ANY); int n = bind(_sockfd,(struct sockaddr*)&local,sizeof(local)); if(n == -1) { cerr<<"bind error:" << errno << strerror(errno) << endl; exit(BIND_ERR); } } void startServer() { char buffer[1024]; 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) { 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: uint16_t _port; string _ip; int _sockfd; func_t _callback; }; }
udpServer.cc:启动服务端
#include "udpServer.hpp" #include <memory> #include <unordered_map> #include <fstream> using namespace Server; static void Usage(string proc) { cout << "\nUsage:\n\t" << proc << " local_port\n\n"; } const string DictTxt = "./dict.txt"; unordered_map<string,string> dict; static bool cutString(string& str,string& s1,string& s2,const string& sep) { auto pos = str.find(sep); if(pos == string::npos) return false; s1 = str.substr(0,pos); s2 = str.substr(pos + sep.size()); return true; } static void initDict() { ifstream in(DictTxt,ios::binary); if(!in.is_open()) { cerr << "open fail:" << DictTxt << "error" << endl; exit(OPEN_ERR); } string line; 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; } //翻译: void TranslationWord(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)); } int main(int argc, char *argv[]) { if (argc != 2) { Usage(argv[0]); exit(USAGE_ERR); } //加载词库 initDict(); uint16_t port = atoi(argv[1]); unique_ptr<udpServer> usvr(new udpServer(TranslationWord,port)); usvr->initServer(); usvr->startServer(); return 0; }
5.编译客户端和服务端
makefile:
.PHONY:all
all:udpServer udpClient
udpServer:udpServer.cc
g++ -o $@ $^ -std=c++11
udpClient:udpClient.cc
g++ -o $@ $^ -std=c++11
.PHONY:clean
clean:
rm -f udpServer udpClient
6.测试结果
如图所示:服务端能够准确处理客户端的请求,将翻译查询结果返回给客户端
7.总结
以上就是使用UDP协议实现的一款翻译服务器,细心的小伙伴也已经发现了,在上面的代码中服务器的任务只是接受请求,然后将请求的数据回调处理,让上层处理业务逻辑,这样的实现方式实现了服务器与业务逻辑代码之间的解耦,如果以后想实现一款别的需求的服务器,只需要更改上层的业务逻辑就可以了。
到此这篇关于使用UDP协议实现单词翻译服务器的文章就介绍到这了,更多相关UDP翻译服务器内容请搜索脚本之家以前的文章或继续浏览下面的相关文章希望大家以后多多支持脚本之家!