赞
踩
需要云服务器等云产品来学习Linux的同学可以移步/–>腾讯云<–/官网,轻量型云服务器低至112元/年,优惠多多。(联系我有折扣哦)
在之前的代码基础上,我们需要修改的只有服务端业务逻辑部分和客户端run的部分
完整代码如下:
/*udpServer.cc*/ #include "udpServer.hpp" #include <fstream> #include <memory> #include <string> #include <map> using namespace Server; // demo1:网络翻译 /** * 业务逻辑: * 1. 在服务器启动之前加载数据文件(对应的翻译),然后启动服务端 * 2. 服务端接收客户端发来的原文,在数据文件中找到对应的翻译内容 * 3. 将翻译内容发回给客户端 * 4. 服务端提供热更新数据文件 */ // 配置文件:可以提供一个转门的配置文件存放,这里为了方便,就直接写死 const std::string filename = "dict.txt"; const std::string filepath = "./"; std::map<std::string, std::string> dict; static bool cutString(const std::string &line, std::string *s1, std::string *s2, const std::string &sep) { auto pos = line.find(sep); if (pos == std::string::npos) return false; *s1 = line.substr(0, pos); *s2 = line.substr(pos + sep.size()); return true; } static void initDict() { std::string file = filepath + filename; std::ifstream in(file.c_str(), std::ios::binary); // 二进制读取的方式打开文件 if (!in.is_open()) { std::cerr << "open file error " << errno << " : " << strerror(errno) << std::endl; exit(1); } std::string line; std::string key, value; while (getline(in, line)) { if (cutString(line, &key, &value, ":")) { dict.insert(std::make_pair(key, value)); } } in.close(); std::cout << "load dict success" << std::endl; } void handleMessage(int sockfd, std::string clientIp, uint16_t clientPort, std::string message) { // 在这里做一些服务端需要完成的任务 std::string response_message; auto it = dict.find(message); if(it != dict.end()) response_message = it->second; else response_message = "can not find this word"; // 将结果返回给客户端 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)); } // 调用的指令 :./udpServer port int main(int argc, char *argv[]) { // 解析指令 if (argc != 2) { Usage(); exit(USAGE_ERR); } uint16_t port = atoi(argv[1]); // 加载配置文件 initDict(); // 创建对象,进行通信 std::unique_ptr<udpServer> usvr(new udpServer(handleMessage, port)); usvr->initServer(); // 初始化服务进程 usvr->start(); // 开始监听 return 0; }
/*udpServer.hpp*/ #pragma once #include <iostream> #include <string> #include <functional> #include <string.h> #include <cerrno> #include <cstdlib> #include <sys/types.h> #include <sys/socket.h> #include <arpa/inet.h> namespace Server { // using func_t = std::function<void(std::string, uint16_t, std::string)>; typedef std::function<void(int, std::string, uint16_t, std::string)> func_t; static void Usage() { std::cout << "\nUsage:\n\t./udpServer local_port\n\n"; } enum // 枚举出错类型 { USAGE_ERR = 1, SOCKET_ERR, BIND_ERR }; const static std::string defaultIP = "0.0.0.0"; const int gnum = 1024; // 处理任务的缓冲区大小 class udpServer { public: udpServer(const func_t &cb, const uint16_t &port, const std::string &ip = defaultIP) :_callback(cb), _port(port), _ip(ip) {} // 这里初始化要做的事情有两件: 1. 创建sockfd 2.bind端口号和ip void initServer() { _sockfd = socket(AF_INET, SOCK_DGRAM, 0); // 参数1:这里使用AF_INET表示使用IPv4进行网络通信;参数2:我们这里使用UDP策略;参数3:这里使用0表示默认 if (_sockfd == -1) // 差错处理 { std::cerr << "socket error " << errno << strerror(errno) << std::endl; exit(SOCKET_ERR); } // std::cout << "socket sucess : " << _sockfd << std::endl; // 在当前函数的栈帧上创建一个local对象,设置相关属性,然后将相关属性bind到系统内核中 struct sockaddr_in local; // 这里struct sockaddr_in类型需要头文件arpa/inet.h bzero(&local, sizeof(local)); // 在填充数据之前首先将对象内部元素清空,这里使用bzero local.sin_family = AF_INET; // 设定协议家族 local.sin_port = htons(_port); // 设置端口号,这里端口号需要首先转换成网络端口号 // local.sin_addr.s_addr = inet_addr(_ip.c_str()); // 设置ip,这里的ip是string类型,但是实际在传输的时候使用的是整型,所以需要转换,这里使用inet_addr local.sin_addr.s_addr = INADDR_ANY; // inet_addr的作用有两个: 1.string -> uint32_t; 2. htonl() int n = bind(_sockfd, (struct sockaddr *)&local, sizeof(local)); // 将local设置到内核中,即bind if (n == -1) { std::cerr << "bind error " << errno << strerror(errno) << std::endl; exit(BIND_ERR); } // 至此初始化的操作完成 } void start() // 让服务器开始跑起来 { // 服务器的本质是一个死循环,在循环内部处理收到的任务 char buffer[gnum]; while (true) { // 1. 读取数据 struct sockaddr_in peer; // 定义一个变量用于接收数据 socklen_t len = sizeof(peer); ssize_t n = recvfrom(_sockfd, buffer, sizeof(buffer) - 1, 0, (struct sockaddr *)&peer, &len); // a. 数据是什么 b. 谁发的 if (n > 0) { buffer[n] = 0; std::string clientIp = inet_ntoa(peer.sin_addr); // 转换网络字节序, 点分十进制 uint16_t clientPort = ntohs(peer.sin_port); std::string message = buffer; std::cout << clientIp << "[" << clientPort << "]# " << message << std::endl; // 2. 处理任务 _callback(_sockfd, clientIp, clientPort, message); } } } private: // 成员变量分析:作为一个服务端进程,我们首先需要一个端口号port和一个本地ip // 还需要有一个文件描述符sockfd,用于进行通信(网络通信是基于文件的,所以使用的都是文件的一套内容,包括fd) int _sockfd; // socket文件描述符 std::string _ip; // 本地ip uint16_t _port; // 服务进程端口号 func_t _callback; }; }
/*udpClient.hpp*/ #pragma once #include <iostream> #include <string> #include <string.h> #include <cerrno> #include <cstdlib> #include <sys/types.h> #include <sys/socket.h> #include <arpa/inet.h> namespace Client { enum // 枚举出错类型 { USAGE_ERR = 1, SOCKET_ERR, BIND_ERR, }; class udpClient { public: udpClient(const std::string &serverIp, const uint16_t &serverPort) : _serverIp(serverIp), _serverPort(serverPort), _sockfd(-1), _quit(false) {} void initClient() { // 1.创建套接字 _sockfd = socket(AF_INET, SOCK_DGRAM, 0); if (_sockfd == -1) { std::cerr << "socket error: " << errno << " : " << strerror(errno) << std::endl; exit(SOCKET_ERR); } std::cout << "socket success: " << _sockfd << std::endl; } 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); std::string message; #define NUM 1024 char buffer[NUM]; while(!_quit) { std::cout << "Please Enter# "; std::cin >> message; // 1. 向服务端发送 sendto(_sockfd, message.c_str(), message.size(), 0, (struct sockaddr *)&server, sizeof(server)); // 2. 接收服务端返回的结果 struct sockaddr_in peer; // 用于接收发送端的相关信息 socklen_t len = sizeof peer; ssize_t n = recvfrom(_sockfd, buffer, sizeof buffer, 0, (struct sockaddr *)&peer, &len); if(n >= 0) buffer[n] = 0; std::cout << "服务器翻译结果# " << buffer << std::endl; } } private: int _sockfd; // 套接字 std::string _serverIp; // 服务端IP uint16_t _serverPort; // 服务端端口号 bool _quit; // 客户端退出标志 }; } // namespace Client
/*udpCilent.cc*/ #include "udpClient.hpp" #include <string> #include <memory> using namespace Client; static void Usage(std::string proc) { std::cout << "\nUsage:\n\t" << proc << " server_ip server_port\n\n"; } // ./udpClient server_ip server_port int main(int argc, char *argv[]) { // 解析指令 if (argc != 3) { Usage(argv[0]); exit(USAGE_ERR); } std::string serverIp = argv[1]; uint16_t serverPort = atoi(argv[2]); std::unique_ptr<udpClient> ucli(new udpClient(serverIp, serverPort)); ucli->initClient(); ucli->run(); return 0; }
实际上命令行解析需要做的事情就是客户端发送命令行数据,然后服务器接收,进行解析处理,然后将结果再发送回客户端
/* udpServer.hpp */ #pragma once #include <string> #include <iostream> #include <functional> #include <cassert> #include <sys/types.h> #include <sys/socket.h> #include <arpa/inet.h> #include <strings.h> namespace Server { using func_t = std::function<void(int, std::string, uint16_t, std::string)>; class udpServer { public: udpServer(func_t cp, uint16_t &port) : _callback(cp), _port(port), _sockfd(-1) {} void initServer() { // 1. 创建socket _sockfd = socket(AF_INET, SOCK_DGRAM, 0); if(_sockfd == -1) { std::cerr << "socket error" << std::endl; exit(1); } // 2. bind struct sockaddr_in local; bzero(&local, sizeof local); local.sin_family = AF_INET; local.sin_port = htons(_port); local.sin_addr.s_addr = INADDR_ANY; int n = bind(_sockfd, (sockaddr *)&local, sizeof local); assert(n == 0); (void)n; } void start() { #define NUM 1024 char buffer[NUM]; while(true) { struct sockaddr_in peer; socklen_t len = sizeof peer; int n = recvfrom(_sockfd, buffer, sizeof(buffer) - 1, 0, (struct sockaddr *)&peer, &len); if(n > 0) { buffer[n] = 0; std::string clientIP = inet_ntoa(peer.sin_addr); uint16_t clientPort = ntohs(peer.sin_port); std::cout << clientIP << "[" << clientPort << "]" << buffer << std::endl; _callback(_sockfd, clientIP, clientPort, buffer); } } } private: int _sockfd; uint16_t _port; func_t _callback; }; } /* udpServer.cc */ #include "udpServer.hpp" #include <iostream> #include <memory> using namespace Server; static void remoteShell(int sockfd, std::string clientIp, uint16_t clientPort, std::string cmd) { // cmd : ls -a -l std::string response; FILE* fp = popen(cmd.c_str(), "r"); if(fp == nullptr) response = cmd + "exec fail"; char line[1024]; while(fgets(line, sizeof line, fp)) { response += line; } pclose(fp); // 开始返回 struct sockaddr_in client; client.sin_family = AF_INET; client.sin_addr.s_addr = inet_addr(clientIp.c_str()); client.sin_port = htons(clientPort); sendto(sockfd, response.c_str(), response.size(), 0, (struct sockaddr*)&client, sizeof client); } static void Usage(std::string proc) { std::cout << "\n\tUsage: " << proc << " local_port\n"; } int main(int argc, char* argv[]) { if(argc != 2) { Usage(argv[0]); exit(1); } uint16_t port = atoi(argv[1]); std::unique_ptr<udpServer> usvr(new udpServer(remoteShell, port)); usvr->initServer(); usvr->start(); return 0; } /* udpClient.hpp */ #pragma once #include <string> #include <iostream> #include <functional> #include <cassert> #include <sys/types.h> #include <sys/socket.h> #include <arpa/inet.h> #include <strings.h> namespace Client { class udpClient { public: udpClient(const std::string &serverIP, const uint16_t &serverPort) : _serverIP(serverIP), _serverPort(serverPort), _sockfd(-1) { } void initClient() { _sockfd = socket(AF_INET, SOCK_DGRAM, 0); if(_sockfd == -1) { std::cerr << "create socket error" << std::endl; exit(1); } // OS在发起通信的时候自动bind } void run() { struct sockaddr_in server; bzero(&server, sizeof server); server.sin_family = AF_INET; server.sin_addr.s_addr = inet_addr(_serverIP.c_str()); server.sin_port = htons(_serverPort); char buffer[1024]; std::string message; while(true) { std::cout << "Enter# "; std::getline(std::cin, message); sendto(_sockfd, message.c_str(), message.size(), 0, (struct sockaddr*)&server, sizeof server); struct sockaddr_in peer; bzero(&peer, sizeof peer); socklen_t len = sizeof peer; int n = recvfrom(_sockfd, buffer, sizeof(buffer) - 1, 0, (struct sockaddr*)& peer, &len); if(n > 0) buffer[n] = 0; std::cout << "服务器运行结果# \n" << buffer << std::endl; buffer[0] = 0;//清空上次运行结果 } } ~udpClient() { } private: int _sockfd; std::string _serverIP; uint16_t _serverPort; }; } /* udpClient.cc */ #include "udpClient.hpp" #include <memory> using namespace Client; static void Usage(std::string proc) { std::cout << "\n\tUsage: " << proc << " local_ip local_port\n"; } int main(int argc, char* argv[]) { if(argc != 3) { Usage(argv[0]); exit(1); } std::string IP = argv[1]; uint16_t Port = atoi(argv[2]); std::unique_ptr<udpClient> uclt(new udpClient(IP, Port)); uclt->initClient(); uclt->run(); return 0; }
对于网络聊天室,实现逻辑就是:首先需要在线用户的管理,当任意一个在线用户发送消息的时候,把消息广播给所有在线用户
/* User.hpp */ #pragma once #include <string> #include <map> #include <sys/types.h> #include <sys/socket.h> #include <netinet/in.h> #include <arpa/inet.h> class User { public: User(const std::string &ip, const uint16_t &port) : _ip(ip), _port(port) { } std::string ip() { return _ip; } uint16_t port() { return _port; } private: std::string _ip; uint16_t _port; }; class OnlineUser { public: void addUser(const std::string &ip, const uint16_t &port) { std::string id = ip + "-" + std::to_string(port); _users.insert(std::make_pair(id, User(ip, port))); } void delUser(const std::string &ip, const uint16_t &port) { std::string id = ip + "-" + std::to_string(port); _users.erase(id); } bool isOnline(const std::string &ip, const uint16_t &port) { std::string id = ip + "-" + std::to_string(port); return _users.find(id) == _users.end() ? false : true; } void boardcastMessage(int sockfd, const std::string &ip, const uint16_t &port, std::string &massage) // 给当前在线的所有用户都发送消息(广播以实现群聊天) { for(auto &user : _users) { struct sockaddr_in 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()); std::string s = "[" + ip + "-" + std::to_string(port) + "]# "; s += massage; sendto(sockfd, s.c_str(), s.size(), 0, (struct sockaddr*)&client, sizeof client); } } private: std::map<std::string, User> _users; }; /* udpServer.hpp */ #pragma once #include <string> #include <iostream> #include <functional> #include <cassert> #include <sys/types.h> #include <sys/socket.h> #include <arpa/inet.h> #include <strings.h> namespace Server { using func_t = std::function<void(int, std::string, uint16_t, std::string)>; class udpServer { public: udpServer(func_t cp, uint16_t &port) : _callback(cp), _port(port), _sockfd(-1) {} void initServer() { // 1. 创建socket _sockfd = socket(AF_INET, SOCK_DGRAM, 0); if(_sockfd == -1) { std::cerr << "socket error" << std::endl; exit(1); } // 2. bind struct sockaddr_in local; bzero(&local, sizeof local); local.sin_family = AF_INET; local.sin_port = htons(_port); local.sin_addr.s_addr = INADDR_ANY; int n = bind(_sockfd, (sockaddr *)&local, sizeof local); assert(n == 0); (void)n; } void start() { #define NUM 1024 char buffer[NUM]; while(true) { struct sockaddr_in peer; socklen_t len = sizeof peer; int n = recvfrom(_sockfd, buffer, sizeof(buffer) - 1, 0, (struct sockaddr *)&peer, &len); if(n > 0) { buffer[n] = 0; std::string clientIP = inet_ntoa(peer.sin_addr); uint16_t clientPort = ntohs(peer.sin_port); std::cout << clientIP << "[" << clientPort << "]" << buffer << std::endl; _callback(_sockfd, clientIP, clientPort, buffer); } } } private: int _sockfd; uint16_t _port; func_t _callback; }; } /* udpServer.cc */ #include "udpServer.hpp" #include "User.hpp" #include <iostream> #include <memory> using namespace Server; OnlineUser onlineUser; static void remoteMessage(int sockfd, std::string clientIp, uint16_t clientPort, std::string message) { // 在进入聊天室之前需要先输入online if(message == "online") onlineUser.addUser(clientIp, clientPort); if(message == "offline") onlineUser.delUser(clientIp, clientPort); // 退出聊天室 if(onlineUser.isOnline(clientIp, clientPort)) { //在线,进行消息的路由 onlineUser.boardcastMessage(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()); std::string response = "你还没上线,请发送online上线"; sendto(sockfd, response.c_str(), response.size(), 0, (struct sockaddr*)&client, sizeof(client)); } } static void Usage(std::string proc) { std::cout << "\n\tUsage: " << proc << " local_port\n"; } int main(int argc, char* argv[]) { if(argc != 2) { Usage(argv[0]); exit(1); } uint16_t port = atoi(argv[1]); std::unique_ptr<udpServer> usvr(new udpServer(remoteMessage, port)); usvr->initServer(); usvr->start(); return 0; } /* udpClient.hpp */ #pragma once #include <string> #include <iostream> #include <functional> #include <cassert> #include <sys/types.h> #include <sys/socket.h> #include <arpa/inet.h> #include <strings.h> namespace Client { class udpClient { public: udpClient(const std::string &serverIP, const uint16_t &serverPort) : _serverIP(serverIP), _serverPort(serverPort), _sockfd(-1) { } void initClient() { _sockfd = socket(AF_INET, SOCK_DGRAM, 0); if(_sockfd == -1) { std::cerr << "create socket error" << std::endl; exit(1); } // OS在发起通信的时候自动bind } 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; std::cout << buffer << std::endl; } return nullptr; } void run() { pthread_create(&_reader, nullptr, readMessage, &_sockfd); struct sockaddr_in server; bzero(&server, sizeof server); server.sin_family = AF_INET; server.sin_addr.s_addr = inet_addr(_serverIP.c_str()); server.sin_port = htons(_serverPort); char buffer[1024]; std::string message; while(true) { std::cout << "Enter# "; std::getline(std::cin, message); sendto(_sockfd, message.c_str(), message.size(), 0, (struct sockaddr*)&server, sizeof server); } } ~udpClient() { } private: int _sockfd; std::string _serverIP; uint16_t _serverPort; pthread_t _reader; }; } /* udpClient.cc */ #include "udpClient.hpp" #include <memory> using namespace Client; static void Usage(std::string proc) { std::cout << "\n\tUsage: " << proc << " local_ip local_port\n"; } int main(int argc, char* argv[]) { if(argc != 3) { Usage(argv[0]); exit(1); } std::string IP = argv[1]; uint16_t Port = atoi(argv[2]); std::unique_ptr<udpClient> uclt(new udpClient(IP, Port)); uclt->initClient(); uclt->run(); return 0; }
/* Window端代码,编译环境 Windows11, Visual Studio 2022 */ #define _CRT_SECURE_NO_WARNINGS #pragma warning(disable:4996) #include <iostream> #include <string> #include <cstring> #include <WinSock2.h> #pragma comment(lib,"ws2_32.lib") // 表示需要链接库 ws2_32.lib using namespace std; // 写死端口号和ip uint16_t serverport = 8080; string serverip = "8.134.152.121"; int main() { // 创建WSAData对象并初始化 WSAData wsd; if (WSAStartup(MAKEWORD(2, 2), &wsd) != 0) { cout << "WSAStartup Error = " << WSAGetLastError() << endl; return 0; } else { cout << "WSAStartup Success" << endl; } // 创建socket SOCKET csock = socket(AF_INET, SOCK_DGRAM, 0); if (csock == SOCKET_ERROR) { cout << "socket Error = " << WSAGetLastError() << endl; return 1; } else { cout << "socket success" << endl; } // 创建sockaddr_in对象进行通信 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 1024 char 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端,编译环境 centOS7 g++ (GCC) 4.8.5 20150623 (Red Hat 4.8.5-44)*/ /* User.hpp */ #pragma once #include <string> #include <map> #include <sys/types.h> #include <sys/socket.h> #include <netinet/in.h> #include <arpa/inet.h> class User { public: User(const std::string &ip, const uint16_t &port) : _ip(ip), _port(port) { } std::string ip() { return _ip; } uint16_t port() { return _port; } private: std::string _ip; uint16_t _port; }; class OnlineUser { public: void addUser(const std::string &ip, const uint16_t &port) { std::string id = ip + "-" + std::to_string(port); _users.insert(std::make_pair(id, User(ip, port))); } void delUser(const std::string &ip, const uint16_t &port) { std::string id = ip + "-" + std::to_string(port); _users.erase(id); } bool isOnline(const std::string &ip, const uint16_t &port) { std::string id = ip + "-" + std::to_string(port); return _users.find(id) == _users.end() ? false : true; } void boardcastMessage(int sockfd, const std::string &ip, const uint16_t &port, std::string &massage) // 给当前在线的所有用户都发送消息(广播以实现群聊天) { for(auto &user : _users) { struct sockaddr_in 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()); std::string s = "[" + ip + "-" + std::to_string(port) + "]# "; s += massage; sendto(sockfd, s.c_str(), s.size(), 0, (struct sockaddr*)&client, sizeof client); } } private: std::map<std::string, User> _users; }; /* udpServer.hpp */ #pragma once #include <string> #include <iostream> #include <functional> #include <cassert> #include <sys/types.h> #include <sys/socket.h> #include <arpa/inet.h> #include <strings.h> namespace Server { using func_t = std::function<void(int, std::string, uint16_t, std::string)>; class udpServer { public: udpServer(func_t cp, uint16_t &port) : _callback(cp), _port(port), _sockfd(-1) {} void initServer() { // 1. 创建socket _sockfd = socket(AF_INET, SOCK_DGRAM, 0); if(_sockfd == -1) { std::cerr << "socket error" << std::endl; exit(1); } // 2. bind struct sockaddr_in local; bzero(&local, sizeof local); local.sin_family = AF_INET; local.sin_port = htons(_port); local.sin_addr.s_addr = INADDR_ANY; int n = bind(_sockfd, (sockaddr *)&local, sizeof local); assert(n == 0); (void)n; } void start() { #define NUM 1024 char buffer[NUM]; while(true) { struct sockaddr_in peer; socklen_t len = sizeof peer; int n = recvfrom(_sockfd, buffer, sizeof(buffer) - 1, 0, (struct sockaddr *)&peer, &len); if(n > 0) { buffer[n] = 0; std::string clientIP = inet_ntoa(peer.sin_addr); uint16_t clientPort = ntohs(peer.sin_port); std::cout << clientIP << "[" << clientPort << "]" << buffer << std::endl; _callback(_sockfd, clientIP, clientPort, buffer); } } } private: int _sockfd; uint16_t _port; func_t _callback; }; } /* udpServer.cc */ #include "udpServer.hpp" #include "User.hpp" #include <iostream> #include <memory> using namespace Server; OnlineUser onlineUser; static void remoteMessage(int sockfd, std::string clientIp, uint16_t clientPort, std::string message) { // 在进入聊天室之前需要先输入online if(message == "online") onlineUser.addUser(clientIp, clientPort); if(message == "offline") onlineUser.delUser(clientIp, clientPort); // 退出聊天室 if(onlineUser.isOnline(clientIp, clientPort)) { //在线,进行消息的路由 onlineUser.boardcastMessage(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()); std::string response = "你还没上线,请发送online上线"; sendto(sockfd, response.c_str(), response.size(), 0, (struct sockaddr*)&client, sizeof(client)); } } static void Usage(std::string proc) { std::cout << "\n\tUsage: " << proc << " local_port\n"; } int main(int argc, char* argv[]) { if(argc != 2) { Usage(argv[0]); exit(1); } uint16_t port = atoi(argv[1]); std::unique_ptr<udpServer> usvr(new udpServer(remoteMessage, port)); usvr->initServer(); usvr->start(); return 0; }
本节完…
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。