1.先創建好udpServer.hpp、udpServer.cc、udpClient.hpp、udpClient.cc的框架。
#pragma once
#include <string>
#include <iostream>
#include <sys/types.h>
#include <sys/socket.h>
#include <unistd.h>
#include <cerrno>
#include <cstring>
#include <cstdlib>
#include <arpa/inet.h>
#include <strings.h>
#include <netinet/in.h>
#include <functional>
#include"userManager"
#include<pthread.h>
using namespace std;
const static string defaultip = "0.0.0.0";
// typedef function<void(int,string,uint16_t,string)> func_t;
typedef void (*func_t)(int,string,uint16_t,string);
class udpServer
{
public:udpServer(uint16_t port,func_t callback) : _port(port),_callback(callback){}void init(){}void start(){}~udpServer() {}private:int _fd;uint16_t _port;string _ip;func_t _callback;
};
#include "udpServer.hpp"
#include <memory>
#include<fstream>
using namespace std;
int main(int argc, char *argv[])
{if (argc != 2){cout << "輸入錯誤,請重新輸入" << endl;}uint16_t port = atoi(argv[1]);unique_ptr<udpServer> server(new udpServer(port, callback));server->init();server->start();return 0;
}
#pragma once
#include <string>
#include <iostream>
#include <sys/types.h>
#include <sys/socket.h>
#include <unistd.h>
#include <cerrno>
#include <cstring>
#include <cstdlib>
#include <arpa/inet.h>
#include <strings.h>
#include <netinet/in.h>
#include <pthread.h>
using namespace std;
class udpClient
{public:udpClient(string serverip,uint16_t serverport):_serverip(serverip),_serverport(serverport),_fd(-1){}void init(){}void start(){}~udpClient(){}private:int _fd;string _serverip;uint16_t _serverport;pthread_t reader;//這是后期需要的,看不懂接著往下看就可以
};
#include"udpClient.hpp"
#include<memory>
using namespace std;int main(int argc,char* argv[]){if(argc!=3){cout<<"輸入錯誤,請重新輸入"<<endl;}uint16_t port = atoi(argv[2]);string ip = argv[1];unique_ptr<udpClient> client(new udpClient(ip,port));client->init();client->start();
}
2.init初始化。
//udpServer.hpp
void init(){// 創建套接字返回fd_fd = socket(AF_INET, SOCK_DGRAM, 0);if (_fd == -1){cerr << "socket error:" << errno << ":" << strerror(errno) << endl;exit(1);}// 將fd和ip,port進行綁定struct sockaddr_in sock;sock.sin_family = AF_INET;sock.sin_port = htons(_port);sock.sin_addr.s_addr = INADDR_ANY;int n = bind(_fd, (struct sockaddr *)&sock, sizeof(sock));if (n == -1){cerr << "bind error:" << errno << ":" << strerror(errno) << endl;exit(2);}}
//udpClient.hpp
void init(){_fd = socket(AF_INET,SOCK_DGRAM,0);if(_fd == -1){cout<<"socket err:"<<errno<<":"<<strerror(errno)<<endl;exit(1);}}
3.start發送、接收數據。
//udpServer.cc
void callback(int fd, string ip, uint16_t port, string messages)
{sockaddr_in client;socklen_t len = sizeof(client);client.sin_family = AF_INET;client.sin_port = htons(port);client.sin_addr.s_addr = inet_addr(ip.c_str());messages = "服務端的輸出結果:"+messages;sendto(fd, messages.c_str(), messages.size(), 0,(struct sockaddr *)&client, len);}//udpServer.hpp
void start(){char buffer[1024];size_t len = sizeof(buffer);char writer[1024];struct sockaddr_in clientsock;socklen_t clientlen = sizeof(clientsock);while (1)//服務器的本質就是一個死循環{size_t n = recvfrom(_fd, buffer, len-1, 0, (struct sockaddr *)&clientsock, &clientlen);if (n > 0){buffer[n]=0;string ip = inet_ntoa(clientsock.sin_addr); // uint32_t->stringuint16_t port = ntohs(clientsock.sin_port);string messages = buffer;cout << ip << "[" << port << "]" << "#" << messages << endl;_callback(_fd,ip,port,messages);}}}
//udpCLient.hpp
static void* readroutine(void* args){pthread_detach(pthread_self());udpClient* c = static_cast<udpClient*>(args);sockaddr_in server;socklen_t serverlen = sizeof(server);while(1){char buffer[1024];int len = sizeof(buffer);size_t n = recvfrom(c->_fd, buffer, len-1, 0, (struct sockaddr *)&server, &serverlen);if (n > 0){buffer[n]=0;cout <<buffer << endl;}}}void start(){pthread_create(&reader,NULL,readroutine,(void*)this);char buffer[1024];struct sockaddr_in serveraddr;serveraddr.sin_family = AF_INET;serveraddr.sin_port = htons(_serverport);serveraddr.sin_addr.s_addr = inet_addr(_serverip.c_str());while(1){cin>>buffer;ssize_t n = sendto(_fd,buffer,sizeof(buffer),0,(struct sockaddr*)&serveraddr,sizeof(serveraddr));if(n == -1){cout<<"sendto err:"<<errno<<":"<<strerror(errno)<<endl;}}}
完整代碼:
udpClient.cc
#include"udpClient.hpp"
#include<memory>
using namespace std;int main(int argc,char* argv[]){if(argc!=3){cout<<"輸入錯誤,請重新輸入"<<endl;}uint16_t port = atoi(argv[2]);string ip = argv[1];unique_ptr<udpClient> client(new udpClient(ip,port));client->init();client->start();
}
?udpClient.hpp
#pragma once
#include <string>
#include <iostream>
#include <sys/types.h>
#include <sys/socket.h>
#include <unistd.h>
#include <cerrno>
#include <cstring>
#include <cstdlib>
#include <arpa/inet.h>
#include <strings.h>
#include <netinet/in.h>
#include <pthread.h>
using namespace std;
class udpClient
{public:udpClient(string serverip,uint16_t serverport):_serverip(serverip),_serverport(serverport),_fd(-1){}void init(){_fd = socket(AF_INET,SOCK_DGRAM,0);if(_fd == -1){cout<<"socket err:"<<errno<<":"<<strerror(errno)<<endl;exit(1);}}static void* readroutine(void* args){pthread_detach(pthread_self());udpClient* c = static_cast<udpClient*>(args);sockaddr_in server;socklen_t serverlen = sizeof(server);while(1){char buffer[1024];int len = sizeof(buffer);size_t n = recvfrom(c->_fd, buffer, len-1, 0, (struct sockaddr *)&server, &serverlen);if (n > 0){buffer[n]=0;cout <<buffer << endl;}}}void start(){pthread_create(&reader,NULL,readroutine,(void*)this);char buffer[1024];struct sockaddr_in serveraddr;serveraddr.sin_family = AF_INET;serveraddr.sin_port = htons(_serverport);serveraddr.sin_addr.s_addr = inet_addr(_serverip.c_str());while(1){cin>>buffer;ssize_t n = sendto(_fd,buffer,sizeof(buffer),0,(struct sockaddr*)&serveraddr,sizeof(serveraddr));if(n == -1){cout<<"sendto err:"<<errno<<":"<<strerror(errno)<<endl;}}}~udpClient(){}private:int _fd;string _serverip;uint16_t _serverport;pthread_t reader;
};
?udpServer.cc
#include "udpServer.hpp"
#include <memory>
#include<fstream>
using namespace std;
// 處理方式1:翻譯軟件
unordered_map<string, string> dictmap;
void to_map(string messages);
// 1.打開文件,按行讀取
void openfile()
{ifstream in;in.open("dict.txt",std::ios::binary);if(in.is_open()){std::string line;while(getline(in,line)){to_map(line);}}
}
// 2.按行存到map中
void to_map(string messages)
{size_t pos = messages.find(":");dictmap.insert(make_pair(messages.substr(0, pos), messages.substr(pos + 1)));
}
// 3.接收傳來的message并通過map查詢
void translate(int fd, string ip, uint16_t port, string messages)
{sockaddr_in client;socklen_t len = sizeof(client);client.sin_family = AF_INET;client.sin_port = htons(port);client.sin_addr.s_addr = inet_addr(ip.c_str());if (dictmap.find(messages) != dictmap.end()){cout<<"messages:"<<dictmap[messages].c_str()<<endl;sendto(fd, dictmap[messages].c_str(), dictmap[messages].size(), 0,(struct sockaddr *)&client, len);}else{string mes = "無結果";sendto(fd, mes.c_str(), mes.size(),0, (struct sockaddr *)&client, len);}
}
// 4.test測試文件有沒有加載成功
void printdict()
{for (auto e : dictmap){cout << e.first << ":" << e.second << endl;}
}
// 處理方式2:群聊
onlineUser onlineuser;
void group_chat(int fd, string ip, uint16_t port, string messages)
{// 將客戶端的信息傳進來onlineuser.addOnlineUser(ip, port);onlineuser.broadcastMessage(fd, ip, port, messages);
}
// 處理方式3:最簡單版本收到什么原樣返回
void callback(int fd, string ip, uint16_t port, string messages)
{sockaddr_in client;socklen_t len = sizeof(client);client.sin_family = AF_INET;client.sin_port = htons(port);client.sin_addr.s_addr = inet_addr(ip.c_str());messages = "服務端的輸出結果:"+messages;sendto(fd, messages.c_str(), messages.size(), 0,(struct sockaddr *)&client, len);}
int main(int argc, char *argv[])
{if (argc != 2){cout << "輸入錯誤,請重新輸入" << endl;}uint16_t port = atoi(argv[1]);//openfile();//printdict();unique_ptr<udpServer> server(new udpServer(port, callback));server->init();server->start();return 0;
}
?udpServer.hpp
#pragma once
#include <string>
#include <iostream>
#include <sys/types.h>
#include <sys/socket.h>
#include <unistd.h>
#include <cerrno>
#include <cstring>
#include <cstdlib>
#include <arpa/inet.h>
#include <strings.h>
#include <netinet/in.h>
#include <functional>
#include"userManager"
#include<pthread.h>
using namespace std;const static string defaultip = "0.0.0.0";
// typedef function<void(int,string,uint16_t,string)> func_t;
typedef void (*func_t)(int,string,uint16_t,string);
class udpServer
{
public:udpServer(uint16_t port,func_t callback) : _port(port),_callback(callback){}void init(){// 創建套接字返回fd_fd = socket(AF_INET, SOCK_DGRAM, 0);if (_fd == -1){cerr << "socket error:" << errno << ":" << strerror(errno) << endl;exit(1);}// 將fd和ip,port進行綁定struct sockaddr_in sock;sock.sin_family = AF_INET;sock.sin_port = htons(_port);sock.sin_addr.s_addr = INADDR_ANY;int n = bind(_fd, (struct sockaddr *)&sock, sizeof(sock));if (n == -1){cerr << "bind error:" << errno << ":" << strerror(errno) << endl;exit(2);}}void start(){char buffer[1024];size_t len = sizeof(buffer);char writer[1024];struct sockaddr_in clientsock;socklen_t clientlen = sizeof(clientsock);while (1){size_t n = recvfrom(_fd, buffer, len-1, 0, (struct sockaddr *)&clientsock, &clientlen);if (n > 0){buffer[n]=0;string ip = inet_ntoa(clientsock.sin_addr); // uint32_t->stringuint16_t port = ntohs(clientsock.sin_port);string messages = buffer;cout << ip << "[" << port << "]" << "#" << messages << endl;_callback(_fd,ip,port,messages);}}}~udpServer() {}private:int _fd;uint16_t _port;string _ip;pthread_t writer;func_t _callback;
};
?makefile
cc=g++
.PHONY:all
all:udpClient udpServerudpClient:udpClient.cc$(cc) -o $@ $^ -std=c++11 -lpthread
udpServer:udpServer.cc$(cc) -o $@ $^ -std=c++11 -lpthread
.PHONY:clean
clean:rm -f udpClient udpServer
以下是拓展的代碼:
群聊:userManager
#pragma once
#include <iostream>
#include <string>
#include <unordered_map>
#include <cerrno>
#include <cstring>
#include <cstdlib>
#include <arpa/inet.h>
#include <strings.h>
#include <netinet/in.h>
#include <functional>
using namespace std;
class User
{
public:User(std::string ip, uint16_t port) : _ip(ip), _port(port){}~User(){}std::string _ip;int16_t _port;
};
class onlineUser
{
public:onlineUser() {}~onlineUser() {}void addOnlineUser(std::string ip, uint16_t port){string id = ip + "[" + std::to_string(port) + "]#";onUser.insert(make_pair(id, User(ip, port)));}void offOnlineUser(std::string ip, uint16_t port){string id = ip + "[" + std::to_string(port) + "]#";onUser.erase(id);}void broadcastMessage(int sockfd, const string &ip, const int16_t &port, const string &messages){string id = ip + "[" + std::to_string(port) + "]#";for (auto &user : onUser){if (user.first != id){sockaddr_in usersock;usersock.sin_family = AF_INET;usersock.sin_port = htons(user.second._port);usersock.sin_addr.s_addr = inet_addr(user.second._ip.c_str());string sendmessage = id + messages;sendto(sockfd, sendmessage.c_str(), sendmessage.size(), 0, (struct sockaddr *)&usersock, sizeof(usersock));}}}private:unordered_map<string, User> onUser;
};
?字典:dict.txt
hello:你好
why:為什么
so:所以
then:然后