使用UDP協(xié)議實現單詞翻譯服務器
前言
上一篇文章中,我們使用UDP協(xié)議編碼完成了一個簡單的服務器,實現數據通信,服務器設計出來后目的不僅僅只是實現數據通信,而是根據客戶端發(fā)過來的請求,實現一定的需求,今天我們要介紹的是當客戶端給服務端發(fā)送英文單詞,然后服務端獲取客戶端的請求,將翻譯結果返回給客戶端,通過這樣的方式,實現了一款英文翻譯服務器。下面我們就一起具體來看看是如何編碼完成。
1.設計思路
如圖所示
- 第一步:啟動服務器,然后服務器加載詞庫
- 第二步:客戶端向服務器,發(fā)送請求
- 第三步:服務器處理請求查找單詞,將查找結果返回給客戶端
- 第四步:客戶端獲取查詢結果
2.詞庫設計
說明:在這里只是簡單模擬實現一個詞庫,主要是實現業(yè)務邏輯
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); //發(fā)送請求 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協(xié)議實現的一款翻譯服務器,細心的小伙伴也已經發(fā)現了,在上面的代碼中服務器的任務只是接受請求,然后將請求的數據回調處理,讓上層處理業(yè)務邏輯,這樣的實現方式實現了服務器與業(yè)務邏輯代碼之間的解耦,如果以后想實現一款別的需求的服務器,只需要更改上層的業(yè)務邏輯就可以了。
到此這篇關于使用UDP協(xié)議實現單詞翻譯服務器的文章就介紹到這了,更多相關UDP翻譯服務器內容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關文章希望大家以后多多支持腳本之家!
相關文章
C++實現LeetCode(28.實現strStr()函數)
這篇文章主要介紹了C++實現LeetCode(28.實現strStr()函數),本篇文章通過簡要的案例,講解了該項技術的了解與使用,以下就是詳細內容,需要的朋友可以參考下2021-07-07