#include "udpcommu.h" #include #include #include #include #include #include #include #include #include #include #include #include #include #include #define setFailedMsgAndReturnFalse(msg) \ {mErrMsg = msg;\ return false;} #define setErrnoMsgAndReturnFalse()\ {mErrMsg = strerror(errno);\ return false;} #define setErrnoMsg() mErrMsg = strerror(errno); UdpCommu::UdpCommu(){} bool UdpCommu::bindTo(int port) { if (mSocket != -1) setFailedMsgAndReturnFalse("已经初始化"); //创建socket mSocket = socket(PF_INET, SOCK_DGRAM, 0); if (mSocket == -1) setErrnoMsgAndReturnFalse(); auto ret = -1; //允许广播 auto broadcast = 1; ret = setsockopt(mSocket, SOL_SOCKET, SO_BROADCAST, &broadcast, sizeof(int)); if (ret == -1) setErrnoMsgAndReturnFalse(); //地址复用 auto reuse = 1; ret = setsockopt(mSocket, SOL_SOCKET, SO_REUSEADDR, &reuse, sizeof(int)); if (ret == -1) setErrnoMsgAndReturnFalse(); //绑定 sockaddr_in addr; addr.sin_family = AF_INET; addr.sin_addr.s_addr = htonl(INADDR_ANY); addr.sin_port = htons(port); ret = ::bind(mSocket, (sockaddr*)&addr, sizeof(addr)); if (ret == -1) setErrnoMsgAndReturnFalse(); return true; } int UdpCommu::sentTo(const string& ip, int port, const void *data, int size) { sockaddr_in addr; addr.sin_family = AF_INET; addr.sin_addr.s_addr = inet_addr(ip.c_str()); addr.sin_port = htons(port); auto ret = ::sendto(mSocket, data, size, 0, (sockaddr*)&addr, sizeof(addr)); if (ret == -1) setErrnoMsg(); return ret; } bool UdpCommu::startAsyncRecv(UdpRecvHandler handler) { if (handler == nullptr) setFailedMsgAndReturnFalse("handler不能为空") if (mSocket == -1) setFailedMsgAndReturnFalse("请先初始化socket"); mRecvHandler = handler; if (!mAsyncMode) { mAsyncMode = true; std::thread t(&UdpCommu::recvThread, this); t.detach(); } return true; } void UdpCommu::close() { if (mSocket == -1) return; ::close(mSocket); mSocket = -1; mAsyncMode=false; } string UdpCommu::getBoundMac() { //osx未定义SIOCGIFHWADDR,写死获取en0 int mib[6]; size_t len=0; unsigned char *ptr; struct if_msghdr *ifm; struct sockaddr_dl *sdl; mib[0] = CTL_NET; mib[1] = AF_ROUTE; mib[2] = 0; mib[3] = AF_LINK; mib[4] = NET_RT_IFLIST; if ((mib[5] = if_nametoindex("en0")) == 0) { perror("if_nametoindex error"); return ""; } if (sysctl(mib, 6, NULL, &len, NULL, 0) < 0) { perror("sysctl 1 error"); return ""; } unique_ptr buf(new char[len]); if (sysctl(mib, 6, buf.get(), &len, NULL, 0) < 0) { perror("sysctl 2 error"); return ""; } ifm = (struct if_msghdr *)buf.get(); sdl = (struct sockaddr_dl *)(ifm + 1); ptr = (unsigned char *)LLADDR(sdl); char macStr[20]={0}; snprintf(macStr, sizeof(macStr), "%02x%02x%02x%02x%02x%02x", *ptr, *(ptr+1), *(ptr+2), *(ptr+3), *(ptr+4), *(ptr+5)); return macStr; } string UdpCommu::getErrMsg() { return mErrMsg; } void UdpCommu::recvThread() { timeval timeo = {3,0}; auto ret = setsockopt(mSocket, SOL_SOCKET, SO_RCVTIMEO, &timeo, sizeof(timeval)); if (ret != 0){ printf("faield to set recv timeo\n"); mAsyncMode=false; return; } std::array buf; sockaddr_in addr; socklen_t len = sizeof(addr); while (mSocket != -1) { buf.fill(0); memset(&addr, 0, len); auto size = recvfrom(mSocket, buf.data(), MAX_RCV_SIZE, 0, (sockaddr*)&addr, &len); if (size < 0) { if (errno == EAGAIN || errno == ETIMEDOUT) continue; printf("error occur:%s\n", strerror(errno)); break; } auto ip = inet_ntoa(addr.sin_addr); vector data(std::begin(buf), std::begin(buf)+size); mRecvHandler(ip, data); } printf("end recv thread\n"); mAsyncMode=false; }