window下cc++异步发送udp和非阻塞的方式接收udp的类封装

window下cc++异步发送udp和非阻塞的方式接收udp的类封装

2023年7月15日发(作者:)

window下cc++异步发送udp和⾮阻塞的⽅式接收udp的类封装以下代码对udp发送和接收都做了封装,在发送和接收前都需要去注册使⽤的功能,从⽽做到需要哪个模块才启动哪个模块的功能,避免资源的浪费。udp发送功能:使⽤列表和信号量的⽅式实现异步发送数据,避免主线程发送数据时出现阻塞的情况udp接收功能:使⽤select函数可以实现⾮阻塞⽅式接收,避免主线程接收数据需要阻塞等待消息的到来更详细的说明在代码的注释中,如发现问题欢迎批评指正~udp.h#pragma once#include #include #include #include #include #include #pragma comment(lib, "WS2_32")#define CACHE_LENGTH 1024 //接收区⼤⼩#define UDP_SERVER 0x02#define UDP_SEND 0x01namespace UDP_SERVE { typedef struct { u_short port; //端⼝ std::string ip; //IP地址 }network_config; class udp_server { public: udp_server(); ~udp_server(); // desc:

注册服务 // param:

参数⼀/说明要注册的服务的类型(UDP_SERVER为UDP接收,UDP_SEND为UDP发送)

参数⼆/配置的⽹络信息

// return:

注册成功或者已注册返回true,注册失败返回false bool Register_Service(size_t, network_config); // desc:

注销服务 // param:

参数⼀/说明要注销的服务的类型(UDP_SERVER为UDP接收,UDP_SEND为UDP发送) // return:

注销成功或者已注册返回true,注销失败返回false bool Cancel_Service(size_t); // desc:

发送数据 // param:

参数⼀/要发送的数据 // return:

发送成功返回true,发送失败返回false bool send_data(const char *); // desc:

⾮阻塞接收数据 // param: NULL // return:

没接收到数据返回-1,接收服务未注册返回-2,监听失败返回-3,recvfrom接收失败返回-4,成功则返回接收到的字符数 long receive_data(); public: char UDP_receive_buffer[CACHE_LENGTH]; //接收缓冲区 char UDP_receive_buffer[CACHE_LENGTH]; //接收缓冲区 private: // desc:

注册接收服务 // param:

参数⼀/配置的⽹络信息

// return:

注册成功返回true,注册失败返回false bool Register_Server(network_config); // desc:

注册发送服务 // param:

参数⼀/配置的⽹络信息

// return:

注册成功返回true,注册失败返回false bool Register_Sender(network_config); // desc:

启动WinSock2 // param: NULL // return:

启动成功返回true,启动失败返回false bool InitWinsock(); // desc:

注销发送服务 // param: NULL // return:

取消成功返回true,取消失败返回false bool Cancel_Sender_Service(); // desc:

注销接收服务 // param: NULL // return:

取消成功返回true,取消失败返回false bool Cancel_Server_Service(); // desc:

发送端多线程函数 // param: udp_server类指针 // return: NULL static DWORD WINAPI Udp_Send_Fun(LPVOID lpParamter); private: volatile bool is_register_Server; //Server是否初始化标识位 volatile bool is_register_Sender; //Sender是否初始化标识位 fd_set rfd; //描述符集

这个将⽤来测试有没有⼀个可⽤的连接 struct timeval timeout; //定时

int rev; SOCKET sockListen; //接收者socket SOCKADDR_IN addrServer; //接收端⽹络信息 SOCKET sockClient; //发送端socket SOCKADDR_IN addrSender; //发送端⽹络信息 HANDLE hThread_sender; //发送端多线程句柄 std::list udp_send_list; //发送数据的列表 HANDLE hSemaphore; //定义信号量句柄 };}#include "udp_server.h"namespace UDP_SERVE { udp_server::udp_server() :is_register_Server(false), is_register_Sender(false), hThread_sender(NULL) { //开启Winsock InitWinsock(); } udp_server::~udp_server() udp_server::~udp_server() { //关闭Winsock的使⽤ WSACleanup(); } bool udp_server::Register_Service(size_t type, network_config config) { if (type & UDP_SERVER) { if (!is_register_Server) { if (!Register_Server(config)) return false; else is_register_Server = true; } else printf("UDP_SERVER have already registeredn"); } if (type & UDP_SEND) { if (!is_register_Sender) { if (!Register_Sender(config)) return false; else is_register_Sender = true; } else { printf("UDP_SEND have already registeredn"); } } return true; } bool udp_server::Cancel_Service(size_t type) { if (type & UDP_SERVER) { if (is_register_Server) { if (!Cancel_Server_Service()) return false; else is_register_Server = false; } else printf("UDP_SERVER have already logoutn"); } if (type & UDP_SEND) { if (is_register_Sender) { is_register_Sender = false; ReleaseSemaphore(hSemaphore, 1, NULL); if (!Cancel_Sender_Service()) return false; else is_register_Sender = false; } else printf("UDP_SEND have already logoutn"); } return true; } bool udp_server::send_data(const char *data) { { if (is_register_Sender) { udp_send__back(std::string(data)); ReleaseSemaphore(hSemaphore, 1, NULL); //增加信号量 } else { printf("The Sender service is not registeredn"); return false; } return true; } long udp_server::receive_data() { if (is_register_Server) { int fromlen = sizeof(struct sockaddr_in); FD_ZERO(&rfd); //总是这样先清空⼀个描述符集 FD_SET(sockListen, &rfd); //把sock放⼊要测试的描述符集 int SelectRcv = select(FD_SETSIZE, &rfd, 0, 0, &timeout); //检查该套接字是否可读 if (SelectRcv == 0) { //没接收到数据 return -1; } else if (SelectRcv < 0) { std::cout << "监听失败" << GetLastError() << std::endl; return -3; } else { memset(UDP_receive_buffer, '0', (CACHE_LENGTH) * sizeof(char)); rev = 0; rev = recvfrom(sockListen, UDP_receive_buffer, (CACHE_LENGTH) * sizeof(char), 0, (struct sockaddr*)&addrServer, &fromlen); if (rev != SOCKET_ERROR) { //数据接收成功 return rev; } else { return -4; } } } else { printf("The Server service is not registeredn"); return -2; } } bool udp_server::Register_Server(network_config config) { _sec = 0; //等下select⽤到这个 _usec = 0; //timeout设置为0,可以理解为⾮阻塞 rev = 0; sockListen = socket(AF_INET, SOCK_DGRAM, 0); if (sockListen == -1) { std::cout << "Socket error" << std::endl; return false; } int recvbuf = 1; setsockopt(sockListen, SOL_SOCKET, SO_RCVBUF, (char*)&recvbuf, sizeof(int)); setsockopt(sockListen, SOL_SOCKET, SO_RCVBUF, (char*)&recvbuf, sizeof(int)); //设置为⾮阻塞模式

u_long imode = 1; rev = ioctlsocket(sockListen, FIONBIO, &imode); if (rev == SOCKET_ERROR) { printf("ioctlsocket failed!"); //closesocket(sockListen); //WSACleanup(); return false; } memset(&addrServer, 0, sizeof(sockaddr_in)); _family = AF_INET; _port = htons(); //监听端⼝ _addr.s_addr = inet_addr(.c_str()); //INADDR_ANY if (0 != ::bind(sockListen, (struct sockaddr*)&addrServer, sizeof(struct sockaddr))) { std::cout << "recv_bind()失败,error: " << GetLastError() << std::endl; return false; } return true; } bool udp_server::Register_Sender(network_config config) { sockClient = socket(AF_INET, SOCK_DGRAM, 0); _addr.S_un.S_addr = inet_addr(.c_str()); _family = AF_INET; _port = htons(); hThread_sender = CreateThread(NULL, 0, Udp_Send_Fun, this, 0, NULL); //创建发送⼦线程 hSemaphore = CreateSemaphore(NULL, 0, 100, NULL); //创建信号量 return true; } bool udp_server::InitWinsock() { int Error; WORD VersionRequested; WSADATA WsaData; VersionRequested = MAKEWORD(2, 2); Error = WSAStartup(VersionRequested, &WsaData); if (Error != 0) { return false; } else { if (LOBYTE(on) != 2 || HIBYTE(ersion) != 2) { WSACleanup(); return false; } } return true; } bool udp_server::Cancel_Sender_Service() { WaitForMultipleObjects(1, &hThread_sender, TRUE, INFINITE); CloseHandle(hSemaphore); CloseHandle(hThread_sender); closesocket(sockClient); return true; } bool udp_server::Cancel_Server_Service() { closesocket(sockListen); return false; } DWORD udp_server::Udp_Send_Fun(LPVOID lpParamter) { udp_server *p = (udp_server *)lpParamter; while (1) { WaitForSingleObject(p->hSemaphore, INFINITE); //阻塞等待信号,直到信号量为signal状态。函数执⾏后信号量⾃动减1 if (!p->is_register_Sender) { break; } if (!(p->udp_send_list).empty()) { if (-1 == sendto(p->sockClient, (p->udp_send_list).front().c_str(), (p->udp_send_list).front().size(), 0, (SOCKADDR*)&(p->addrSender), sizeof(SOCKADDR))) { //发送数据 printf("UDP SendTo error -> %sn", strerror(errno)); } (p->udp_send_list).pop_front(); //数据出列 } else { printf("udp_send_list is emptyn"); } Sleep(100); } printf("Udp_Send_Fun() exitn"); return 0; }}#include "udp_server.h"//轮询查看有没有消息到来DWORD WINAPI test_Func(LPVOID lpParamter) { UDP_SERVE::udp_server *p = (UDP_SERVE::udp_server *)lpParamter; while (1) { long l_buf = p->receive_data(); //接收错误 if (-1 > l_buf) { break; } //未接收到数据 else if (l_buf == -1) { continue; } //接收到数据 else { printf("len %ld, ", l_buf); printf("data %sn", p->UDP_receive_buffer); } Sleep(100); } return 0;}int main(){ UDP_SERVE::udp_server *p = new UDP_SERVE::udp_server(); //设置接收udp模块的信息 UDP_SERVE::network_config config; = "0.0.0.0"; = 5600; //注册接收udp模块 if (!p->Register_Service(UDP_SERVER, config)) { printf("Register_Service errorn"); } //设置发送udp模块的信息 = "127.0.0.1"; = 5600; //注册发送udp模块 if (!p->Register_Service(UDP_SEND, config)) { printf("Register_Service errorn"); } //创建测试线程 CreateThread(NULL, 0, test_Func, p, 0, NULL); Sleep(1000); //发送数据 std::string data = "ggrerrrrr"; p->send_data(data.c_str()); data = "gg1"; p->send_data(data.c_str()); data = "gg2"; p->send_data(data.c_str()); data = "gg3"; p->send_data(data.c_str()); data = "gg4"; p->send_data(data.c_str()); data = "gg5"; p->send_data(data.c_str()); data = "gg6"; p->send_data(data.c_str()); data = "gg7"; p->send_data(data.c_str()); data = "gg8"; p->send_data(data.c_str()); Sleep(1000);

//注销发送udp模块 p->Cancel_Service(UDP_SEND); //注销接收udp模块 p->Cancel_Service(UDP_SERVER); delete p; system("pause"); return 0;}

发布者:admin,转转请注明出处:http://www.yc00.com/xiaochengxu/1689408916a243357.html

相关推荐

发表回复

评论列表(0条)

  • 暂无评论

联系我们

400-800-8888

在线咨询: QQ交谈

邮件:admin@example.com

工作时间:周一至周五,9:30-18:30,节假日休息

关注微信