使用UDP協(xié)議實(shí)現(xiàn)單詞翻譯服務(wù)器
前言
上一篇文章中,我們使用UDP協(xié)議編碼完成了一個(gè)簡(jiǎn)單的服務(wù)器,實(shí)現(xiàn)數(shù)據(jù)通信,服務(wù)器設(shè)計(jì)出來后目的不僅僅只是實(shí)現(xiàn)數(shù)據(jù)通信,而是根據(jù)客戶端發(fā)過來的請(qǐng)求,實(shí)現(xiàn)一定的需求,今天我們要介紹的是當(dāng)客戶端給服務(wù)端發(fā)送英文單詞,然后服務(wù)端獲取客戶端的請(qǐng)求,將翻譯結(jié)果返回給客戶端,通過這樣的方式,實(shí)現(xiàn)了一款英文翻譯服務(wù)器。下面我們就一起具體來看看是如何編碼完成。
1.設(shè)計(jì)思路
如圖所示
- 第一步:?jiǎn)?dòng)服務(wù)器,然后服務(wù)器加載詞庫
- 第二步:客戶端向服務(wù)器,發(fā)送請(qǐng)求
- 第三步:服務(wù)器處理請(qǐng)求查找單詞,將查找結(jié)果返回給客戶端
- 第四步:客戶端獲取查詢結(jié)果
2.詞庫設(shè)計(jì)
說明:在這里只是簡(jiǎn)單模擬實(shí)現(xiàn)一個(gè)詞庫,主要是實(shí)現(xiàn)業(yè)務(wù)邏輯
dict.txt:
aunt:姨母 brother:兄弟 cousin:堂兄弟 couple:夫婦 dad:爸爸 daughter:女兒 family:家 father:爸爸 grandchild:孫子 granddaughger:孫女 grandfather:祖父 grandma:外婆 grandpa:外公 granny 老奶奶
3.設(shè)計(jì)客戶端
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 << "請(qǐng)輸入你想要翻譯的單詞:"; getline(cin,message); //發(fā)送請(qǐng)求 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); //接受查詢翻譯結(jié)果 size_t n = recvfrom(_sockfd, buffer, sizeof(buffer) - 1, 0, (struct sockaddr *)&temp, &len); if (n >= 0) buffer[n] = 0; cout << "翻譯的結(jié)果為: " << buffer << endl; } } private: string _serverIp; int _sockfd; uint16_t _serverPort; }; }
udpClient.cc:啟動(dòng)客戶端
#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.設(shè)計(jì)服務(wù)端
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; //服務(wù)器只負(fù)責(zé)接受數(shù)據(jù),處理方法采用回調(diào)的方式交給上層處理 _callback(_sockfd,clientIp,clientPort,message); } } } ~udpServer() {} private: uint16_t _port; string _ip; int _sockfd; func_t _callback; }; }
udpServer.cc:啟動(dòng)服務(wù)端
#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.編譯客戶端和服務(wù)端
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.測(cè)試結(jié)果
如圖所示:服務(wù)端能夠準(zhǔn)確處理客戶端的請(qǐng)求,將翻譯查詢結(jié)果返回給客戶端
7.總結(jié)
以上就是使用UDP協(xié)議實(shí)現(xiàn)的一款翻譯服務(wù)器,細(xì)心的小伙伴也已經(jīng)發(fā)現(xiàn)了,在上面的代碼中服務(wù)器的任務(wù)只是接受請(qǐng)求,然后將請(qǐng)求的數(shù)據(jù)回調(diào)處理,讓上層處理業(yè)務(wù)邏輯,這樣的實(shí)現(xiàn)方式實(shí)現(xiàn)了服務(wù)器與業(yè)務(wù)邏輯代碼之間的解耦,如果以后想實(shí)現(xiàn)一款別的需求的服務(wù)器,只需要更改上層的業(yè)務(wù)邏輯就可以了。
到此這篇關(guān)于使用UDP協(xié)議實(shí)現(xiàn)單詞翻譯服務(wù)器的文章就介紹到這了,更多相關(guān)UDP翻譯服務(wù)器內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
利用stream實(shí)現(xiàn)一個(gè)簡(jiǎn)單的http下載器
這篇文章主要介紹了利用stream實(shí)現(xiàn)一個(gè)簡(jiǎn)單的http下載器的相關(guān)資料,需要的朋友可以參考下2015-03-03C++實(shí)現(xiàn)LeetCode(28.實(shí)現(xiàn)strStr()函數(shù))
這篇文章主要介紹了C++實(shí)現(xiàn)LeetCode(28.實(shí)現(xiàn)strStr()函數(shù)),本篇文章通過簡(jiǎn)要的案例,講解了該項(xiàng)技術(shù)的了解與使用,以下就是詳細(xì)內(nèi)容,需要的朋友可以參考下2021-07-07淺談C++中對(duì)象的復(fù)制與對(duì)象之間的相互賦值
這篇文章主要介紹了淺談C++中對(duì)象的復(fù)制與對(duì)象之間的相互賦值,是C語言入門學(xué)習(xí)中的基礎(chǔ)知識(shí),需要的朋友可以參考下2015-09-09