You can not select more than 25 topics Topics must start with a chinese character,a letter or number, can include dashes ('-') and can be up to 35 characters long.

udpcommu.cpp 4.4 kB

9 years ago
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189
  1. #include "udpcommu.h"
  2. #include <string.h>
  3. #include <errno.h>
  4. #include <sys/socket.h>
  5. #include <sys/types.h>
  6. #include <arpa/inet.h>
  7. #include <stdio.h>
  8. #include <unistd.h>
  9. #include <thread>
  10. #include <net/if.h>
  11. #include <sys/ioctl.h>
  12. #include <netinet/in.h>
  13. #include <net/if_dl.h>
  14. #include <sys/sysctl.h>
  15. #include <array>
  16. #define setFailedMsgAndReturnFalse(msg) \
  17. {mErrMsg = msg;\
  18. return false;}
  19. #define setErrnoMsgAndReturnFalse()\
  20. {mErrMsg = strerror(errno);\
  21. return false;}
  22. #define setErrnoMsg() mErrMsg = strerror(errno);
  23. UdpCommu::UdpCommu(){}
  24. bool UdpCommu::bindTo(int port)
  25. {
  26. if (mSocket != -1)
  27. setFailedMsgAndReturnFalse("已经初始化");
  28. //创建socket
  29. mSocket = socket(PF_INET, SOCK_DGRAM, 0);
  30. if (mSocket == -1)
  31. setErrnoMsgAndReturnFalse();
  32. auto ret = -1;
  33. //允许广播
  34. auto broadcast = 1;
  35. ret = setsockopt(mSocket, SOL_SOCKET, SO_BROADCAST, &broadcast, sizeof(int));
  36. if (ret == -1)
  37. setErrnoMsgAndReturnFalse();
  38. //地址复用
  39. auto reuse = 1;
  40. ret = setsockopt(mSocket, SOL_SOCKET, SO_REUSEADDR, &reuse, sizeof(int));
  41. if (ret == -1)
  42. setErrnoMsgAndReturnFalse();
  43. //绑定
  44. sockaddr_in addr;
  45. addr.sin_family = AF_INET;
  46. addr.sin_addr.s_addr = htonl(INADDR_ANY);
  47. addr.sin_port = htons(port);
  48. ret = ::bind(mSocket, (sockaddr*)&addr, sizeof(addr));
  49. if (ret == -1)
  50. setErrnoMsgAndReturnFalse();
  51. return true;
  52. }
  53. int UdpCommu::sentTo(const string& ip, int port, const void *data, int size)
  54. {
  55. sockaddr_in addr;
  56. addr.sin_family = AF_INET;
  57. addr.sin_addr.s_addr = inet_addr(ip.c_str());
  58. addr.sin_port = htons(port);
  59. auto ret = ::sendto(mSocket, data, size, 0, (sockaddr*)&addr, sizeof(addr));
  60. if (ret == -1)
  61. setErrnoMsg();
  62. return ret;
  63. }
  64. bool UdpCommu::startAsyncRecv(UdpRecvHandler handler)
  65. {
  66. if (handler == nullptr)
  67. setFailedMsgAndReturnFalse("handler不能为空")
  68. if (mSocket == -1)
  69. setFailedMsgAndReturnFalse("请先初始化socket");
  70. mRecvHandler = handler;
  71. if (!mAsyncMode)
  72. {
  73. mAsyncMode = true;
  74. std::thread t(&UdpCommu::recvThread, this);
  75. t.detach();
  76. }
  77. return true;
  78. }
  79. void UdpCommu::close()
  80. {
  81. if (mSocket == -1)
  82. return;
  83. ::close(mSocket);
  84. mSocket = -1;
  85. mAsyncMode=false;
  86. }
  87. string UdpCommu::getBoundMac()
  88. {
  89. //osx未定义SIOCGIFHWADDR,写死获取en0
  90. int mib[6];
  91. size_t len=0;
  92. unsigned char *ptr;
  93. struct if_msghdr *ifm;
  94. struct sockaddr_dl *sdl;
  95. mib[0] = CTL_NET;
  96. mib[1] = AF_ROUTE;
  97. mib[2] = 0;
  98. mib[3] = AF_LINK;
  99. mib[4] = NET_RT_IFLIST;
  100. if ((mib[5] = if_nametoindex("en0")) == 0) {
  101. perror("if_nametoindex error");
  102. return "";
  103. }
  104. if (sysctl(mib, 6, NULL, &len, NULL, 0) < 0) {
  105. perror("sysctl 1 error");
  106. return "";
  107. }
  108. unique_ptr<char[]> buf(new char[len]);
  109. if (sysctl(mib, 6, buf.get(), &len, NULL, 0) < 0) {
  110. perror("sysctl 2 error");
  111. return "";
  112. }
  113. ifm = (struct if_msghdr *)buf.get();
  114. sdl = (struct sockaddr_dl *)(ifm + 1);
  115. ptr = (unsigned char *)LLADDR(sdl);
  116. char macStr[20]={0};
  117. snprintf(macStr, sizeof(macStr), "%02x%02x%02x%02x%02x%02x", *ptr, *(ptr+1), *(ptr+2),
  118. *(ptr+3), *(ptr+4), *(ptr+5));
  119. return macStr;
  120. }
  121. string UdpCommu::getErrMsg()
  122. {
  123. return mErrMsg;
  124. }
  125. void UdpCommu::recvThread()
  126. {
  127. timeval timeo = {3,0};
  128. auto ret = setsockopt(mSocket, SOL_SOCKET, SO_RCVTIMEO, &timeo, sizeof(timeval));
  129. if (ret != 0){
  130. printf("faield to set recv timeo\n");
  131. mAsyncMode=false;
  132. return;
  133. }
  134. std::array<char,MAX_RCV_SIZE> buf;
  135. sockaddr_in addr;
  136. socklen_t len = sizeof(addr);
  137. while (mSocket != -1) {
  138. buf.fill(0);
  139. memset(&addr, 0, len);
  140. auto size = recvfrom(mSocket, buf.data(), MAX_RCV_SIZE, 0, (sockaddr*)&addr, &len);
  141. if (size < 0)
  142. {
  143. if (errno == EAGAIN || errno == ETIMEDOUT)
  144. continue;
  145. printf("error occur:%s\n", strerror(errno));
  146. break;
  147. }
  148. auto ip = inet_ntoa(addr.sin_addr);
  149. vector<char> data(std::begin(buf), std::begin(buf)+size);
  150. mRecvHandler(ip, data);
  151. }
  152. printf("end recv thread\n");
  153. mAsyncMode=false;
  154. }

mac下的“飞秋”大多数只是飞鸽传书协议,而且未发现令人满意的开源项目,所以基于c++与qt实现了基础的飞秋协议。

Contributors (1)