1. //
  2. // SocketUDPServerClient.m
  3. // socket_server_client
  4. //
  5. // Created by lujunjie on 2016/11/26.
  6. // Copyright © 2016年 lujunjie. All rights reserved.
  7. //
  8.  
  9. #import "SocketUDPServerClient.h"
  10. #import <sys/socket.h>
  11. #import <netinet/in.h>
  12. #import <arpa/inet.h>
  13. #import "UDPProtocolHerader.h"
  14. #import <ifaddrs.h>
  15. #include <net/if.h>
  16. @interface SocketUDPServerClient()
  17. {
  18. in_addr_t broadcastClientAddr; // 发送广播的地址
  19. }
  20. @end
  21. @implementation SocketUDPServerClient
  22. int serverSockfd = -;
  23. /**
  24. 启动服务监听接收广播
  25. */
  26. - (void)startUDPServer
  27. {
  28. // 第一步:打开套节字描述
  29. serverSockfd = socket(AF_INET, SOCK_DGRAM, );// 协议族、数据报、0
  30. if(serverSockfd < )
  31. {
  32. NSLog(@"error:打开套节字描述符失败socket()");
  33. }
  34. NSLog(@"打开套节字描述sockfd:%d",serverSockfd);
  35. // 第二步:设置广播包
  36. int opt;
  37. if ((setsockopt(serverSockfd, SOL_SOCKET, SO_BROADCAST, &opt, sizeof(int)))< ) {
  38. NSLog(@"error:广播包setsockopt");
  39. }
  40. // 第三步: bind
  41. struct sockaddr_in serveraddr;
  42. serveraddr.sin_family = AF_INET;
  43. serveraddr.sin_port = htons(); // 5000~655355
  44. serveraddr.sin_addr.s_addr = INADDR_ANY;
  45. // 当你调用bind()函数绑定IP时使用INADDR_ANY ,明接收来自任意IP、任意网卡的发给指定端口的数据。作为发送端,当用调用bind()函数绑定IP时使用INADDR_ANY,表明使用网卡号最低的网卡进行发送数据,也就是UDP数据广播。
  46. if ((bind(serverSockfd, (struct sockaddr *)&serveraddr, sizeof(serveraddr))) < ) {
  47. NSLog(@"error:bind");
  48. }
  49.  
  50. [NSThread detachNewThreadSelector:@selector(recvFromThread) toTarget:self withObject:nil];
  51.  
  52. }
  53.  
  54. - (void)recvFromThread
  55. {
  56. struct sockaddr_in clientaddr;
  57. socklen_t clientaddrLen = sizeof(clientaddr);
  58. int msgHeaderSize = sizeof(CC_searchBrodcastHeader);
  59. char *buf = (char *)malloc(msgHeaderSize);
  60. memset(buf, , sizeof(msgHeaderSize));
  61. long recvSize = ;
  62. while () {
  63.  
  64. if ([self selectReadSockfd:serverSockfd]) {
  65.  
  66. long recvRet = recvfrom(serverSockfd,buf + recvSize,msgHeaderSize -recvSize, ,(struct sockaddr *)&clientaddr,&clientaddrLen);
  67. if (recvRet <= ) {
  68. NSLog(@"<= 0 error:recvfrom errorcode:%zi",recvRet);
  69. sleep();
  70. continue;
  71. }
  72. recvSize += recvRet;
  73.  
  74. if (recvSize >= msgHeaderSize) {
  75. NSString *ipaddr = [self getIPAddress];
  76. const char *addr = [ipaddr UTF8String];
  77. NSString* tempIPString=[NSString stringWithCString:inet_ntoa(clientaddr.sin_addr) encoding:NSUTF8StringEncoding];
  78. NSLog(@"RECV:::::IPADDR: %@",tempIPString);
  79. if (clientaddr.sin_addr.s_addr != inet_addr(addr)) {// 自己不能收到自己的广播
  80. // 接收到的广播
  81. broadcastClientAddr = clientaddr.sin_addr.s_addr;
  82. [self recvSuccessWithBuf:buf];
  83. }
  84. // 清空出来
  85. recvSize = ;
  86. memset(buf, , sizeof(msgHeaderSize));
  87. }
  88. }
  89.  
  90. }
  91. }
  92.  
  93. - (BOOL)selectReadSockfd:(int)sockfd
  94. {
  95. fd_set read_set;
  96. struct timeval tmval;
  97. tmval.tv_sec = ;
  98. tmval.tv_usec = ;
  99.  
  100. FD_ZERO(&read_set); // 将指定的文件描述符集清空
  101. FD_SET(sockfd,&read_set); // 用于在文件描述符集合中增加一个新的文件描述符
  102. int ret =select(sockfd+,&read_set, NULL, NULL,&tmval);
  103. if (ret <= ) {
  104. NSLog(@"<= 0 error:select errorcode:%zi",ret);
  105. return NO;
  106. }
  107. if (FD_ISSET(sockfd, &read_set)) {
  108. return YES;
  109. }
  110. return NO;
  111. }
  112.  
  113. - (BOOL)selectWriteSockfd:(int)sockfd
  114. {
  115. fd_set w_set;
  116. struct timeval tmval;
  117. tmval.tv_sec = ;
  118. tmval.tv_usec = ;
  119.  
  120. FD_ZERO(&w_set); // 将指定的文件描述符集清空
  121. FD_SET(sockfd,&w_set); // 用于在文件描述符集合中增加一个新的文件描述符
  122. int ret =select(sockfd+,NULL, &w_set, NULL,&tmval);
  123. if (ret <= ) {
  124. NSLog(@"<= 0 error:select errorcode:%zi",ret);
  125. return NO;
  126. }
  127. if (FD_ISSET(sockfd, &w_set)) {
  128. return YES;
  129. }
  130. return NO;
  131. }
  132.  
  133. - (void)recvSuccessWithBuf:(char *)buf
  134. {
  135. CC_searchBrodcastHeader *header = (CC_searchBrodcastHeader *)buf;
  136. char pheader[] = {};
  137. memcpy(pheader,header->protocolHeader, sizeof(pheader));
  138. memset(pheader+, , );
  139. NSString *protocolHeader=[NSString stringWithCString:pheader encoding:NSASCIIStringEncoding];
  140. if ([protocolHeader isEqualToString:@"CC"]) {
  141. if (header->controlMask == udp_broadcast_request) {
  142.  
  143. [self sendtoClient];
  144.  
  145. }else if(header->controlMask == udp_broadCast_reply)
  146. {
  147. struct in_addr temp_in_addr;
  148. memset(&temp_in_addr, , sizeof(temp_in_addr));
  149.  
  150. memcpy(&temp_in_addr, &header->IP, sizeof(header->IP));
  151. NSString* tempIPString=[NSString stringWithCString:inet_ntoa(temp_in_addr) encoding:NSUTF8StringEncoding];
  152. NSLog(@"对方的IP地址是: %@",tempIPString);
  153. }
  154. }
  155. }
  156.  
  157. - (void)sendtoClient
  158. {
  159. // 回复
  160. NSString *ipaddr = [self getIPAddress];
  161. const char *localAddr = [ipaddr UTF8String];
  162.  
  163. CC_searchBrodcastHeader header;
  164. memset(&header, , sizeof(header));
  165. header.controlMask = udp_broadCast_reply;
  166. header.protocolHeader[] = 'C';
  167. header.protocolHeader[] = 'C';
  168. header.IP = inet_addr(localAddr);
  169.  
  170. char *buf = (char *)malloc(sizeof(header));
  171. memcpy(buf, &header, sizeof(header));
  172.  
  173. if ([self selectWriteSockfd:serverSockfd]) {
  174. if ([self sendtoWithSockfd:serverSockfd Buffer:buf size:sizeof(header) addr:broadcastClientAddr]) {
  175. NSLog(@"=====IP:%@",ipaddr);
  176. NSLog(@"=====IP发送成功");
  177. }
  178. }
  179. }
  180.  
  181. - (BOOL)sendtoWithSockfd:(int)sockfd Buffer:(char *)buffer size:(int)size addr:(in_addr_t)addr
  182. {
  183. struct sockaddr_in clientaddr;
  184. clientaddr.sin_family = AF_INET;
  185. clientaddr.sin_port = htons();
  186. clientaddr.sin_addr.s_addr = addr;
  187.  
  188. long sendSize = ;
  189. while (sendSize < size) {
  190. long retSize = sendto(sockfd, buffer+sendSize, size-sendSize, , (struct sockaddr*)&clientaddr, sizeof(clientaddr));
  191. if (retSize <= ) {
  192. continue;
  193. }
  194. sendSize += retSize;
  195. if (sendSize >= size) {
  196. // 发送成功
  197. return true;
  198. }
  199. }
  200.  
  201. return true;
  202. }
  203.  
  204. int clientSockfd = -;
  205. /**
  206. 发送广播
  207. */
  208. - (void)searchUDPServer
  209. {
  210. // 第一步:打开套节字描述
  211. clientSockfd = socket(AF_INET, SOCK_DGRAM, );// 协议族、数据报、0
  212. if(clientSockfd < )
  213. {
  214. NSLog(@"error:打开套节字描述符失败socket()");
  215. }
  216. NSLog(@"打开套节字描述sockfd:%d",clientSockfd);
  217. // 第二步:设置广播包
  218. int clientOpt;
  219. if ((setsockopt(clientSockfd, SOL_SOCKET, SO_BROADCAST, &clientOpt, sizeof(int)))< ) {
  220. NSLog(@"error:广播包setsockopt");
  221. }
  222.  
  223. if ([self selectSockfd:clientSockfd]) {
  224. CC_searchBrodcastHeader header;
  225. memset(&header, , sizeof(header));
  226. header.controlMask = udp_broadcast_request;
  227. header.protocolHeader[] = 'C';
  228. header.protocolHeader[] = 'C';
  229.  
  230. char *buf = (char *)malloc(sizeof(header));
  231. memcpy(buf, &header, sizeof(header));
  232.  
  233. if ([self sendtoWithSockfd:clientSockfd Buffer:buf size:sizeof(header) addr:INADDR_BROADCAST]) {
  234. NSLog(@"=====广播发送成功");
  235. }
  236. }
  237.  
  238. close(clientSockfd);
  239. clientSockfd = -;
  240. }
  241.  
  242. - (BOOL)selectSockfd:(int)sockfd
  243. {
  244. fd_set w_set;
  245. struct timeval tmval;
  246. tmval.tv_sec = ;
  247. tmval.tv_usec = ;
  248.  
  249. FD_ZERO(&w_set); // 将指定的文件描述符集清空
  250. FD_SET(sockfd,&w_set); // 用于在文件描述符集合中增加一个新的文件描述符
  251. int ret =select(sockfd+,NULL, &w_set, NULL,&tmval);
  252. if (ret <= ) {
  253. NSLog(@"<= 0 error:select errorcode:%zi",ret);
  254. return NO;
  255. }
  256. if (FD_ISSET(sockfd, &w_set)) {
  257. return YES;
  258. }
  259. return NO;
  260. }
  261.  
  262. - (NSString *)getIPAddress
  263. {
  264. NSArray *searchArray = @[@"en1/ipv4",@"en0/ipv4"];
  265.  
  266. NSDictionary *addresses = [self getIPAddresses];
  267. NSLog(@"addresses: %@", addresses);
  268.  
  269. __block NSString *address;
  270. [searchArray enumerateObjectsUsingBlock:^(NSString *key, NSUInteger idx, BOOL *stop)
  271. {
  272. address = addresses[key];
  273. if(address) *stop = YES;
  274. } ];
  275. return address ? address : @"0.0.0.0";
  276. }
  277. - (NSDictionary *)getIPAddresses
  278. {
  279. NSMutableDictionary *addresses = [NSMutableDictionary dictionaryWithCapacity:];
  280.  
  281. // retrieve the current interfaces - returns 0 on success
  282. struct ifaddrs *interfaces;
  283. if(!getifaddrs(&interfaces)) {
  284. // Loop through linked list of interfaces
  285. struct ifaddrs *interface;
  286. for(interface=interfaces; interface; interface=interface->ifa_next) {
  287. if(!(interface->ifa_flags & IFF_UP) /* || (interface->ifa_flags & IFF_LOOPBACK) */ ) {
  288. continue; // deeply nested code harder to read
  289. }
  290. const struct sockaddr_in *addr = (const struct sockaddr_in*)interface->ifa_addr;
  291. char addrBuf[ MAX(INET_ADDRSTRLEN, INET6_ADDRSTRLEN) ];
  292. if(addr && (addr->sin_family==AF_INET || addr->sin_family==AF_INET6)) {
  293. NSString *name = [NSString stringWithUTF8String:interface->ifa_name];
  294. NSString *type;
  295. if(addr->sin_family == AF_INET) {
  296. if(inet_ntop(AF_INET, &addr->sin_addr, addrBuf, INET_ADDRSTRLEN)) {
  297. type = @"ipv4";
  298. }
  299. } else {
  300. const struct sockaddr_in6 *addr6 = (const struct sockaddr_in6*)interface->ifa_addr;
  301. if(inet_ntop(AF_INET6, &addr6->sin6_addr, addrBuf, INET6_ADDRSTRLEN)) {
  302. type = @"ipv6";
  303. }
  304. }
  305. if(type) {
  306. NSString *key = [NSString stringWithFormat:@"%@/%@", name, type];
  307. addresses[key] = [NSString stringWithUTF8String:addrBuf];
  308. }
  309. }
  310. }
  311. // Free memory
  312. freeifaddrs(interfaces);
  313. }
  314. return [addresses count] ? addresses : nil;
  315. }
  316. @end

socket UDP简单通讯的更多相关文章

  1. socket TCP简单通讯

    socket 服务器 // // main.m // socket_server // // Created by lujunjie on 2016/11/23. // Copyright © 201 ...

  2. C++ 利用socket实现TCP,UDP网络通讯

    学习孙鑫老师的vc++深入浅出,有一段时间了,第一次接触socket说实话有点儿看不懂,第一次基本上是看他说一句我写一句完成的,第二次在看SOCKET多少有点儿感觉了,接下来我把利用SOCKET完成T ...

  3. socket.io简单说明及在线抽奖demo

    socket.io简单说明及在线抽奖demo socket.io 简介 Socket.IO可以实现实时双向的基于事件的通信. 它适用于各种平台,浏览器或设备,也同样注重可靠性和速度. socket.i ...

  4. Nginx学习笔记(四) 源码分析&socket/UDP/shmem

    源码分析 在茫茫的源码中,看到了几个好像挺熟悉的名字(socket/UDP/shmem).那就来看看这个文件吧!从简单的开始~~~ src/os/unix/Ngx_socket.h&Ngx_s ...

  5. socket.io简单入门(一.实现简单的图表推送)

    引子:随着nodejs蓬勃发展,虽然主要业务系统因为架构健壮性不会选择nodejs座位应用服务器.但是大量的内部系统却可以使用nodejs试水,大量的前端开发人员转入全堆开发也是一个因素. 研究本例主 ...

  6. Winform MDI窗体容器、权限、简单通讯

    MDI窗体容器: 一般来说,窗体是顶级容器,不允许放在其他任何容器内,但是如果将某个窗体的IsMdiContainer属性设置为True,那此窗体就会成为窗体容器,可以在其中放入其他窗体 在内部的窗体 ...

  7. Winform MDI窗体容器,权限以及简单通讯

    MDI窗体容器: 一般来说,窗体是顶级容器,不允许放在其他任何容器内,但是如果将某个窗体的IsMdiContainer属性设置为True,那此窗体就会成为窗体容器,可以在其中放入其他窗体 在内部的窗体 ...

  8. Winform MDI窗体容器 权限 简单通讯

    MDI窗体容器 权限  using System; using System.Collections.Generic; using System.ComponentModel; using Syste ...

  9. 重新想象 Windows 8 Store Apps (62) - 通信: Socket TCP, Socket UDP

    [源码下载] 重新想象 Windows 8 Store Apps (62) - 通信: Socket TCP, Socket UDP 作者:webabcd 介绍重新想象 Windows 8 Store ...

随机推荐

  1. 未能将基于用户的Visual C++项目设置保存到user文件错误的解决

    作者:朱金灿 来源:http://blog.csdn.net/clever101 最近遇见一个诡异错误,将Win7家庭版升级到Win7旗舰版.然后使用原来安装的VS2008开发,保存工程时总是出现未能 ...

  2. Ionic2集成ArcGIS JavaScript API.md

    1. Ionic同原生ArcGIS JavaScript API结合 1.1. 安装esri-loader 在工程目录下命令行安装: npm install angular2-esri-loader ...

  3. 170703 锐姿公司winserver2012 标准版安装过程

    背景: 锐姿公司一台服务器,配置为:X3650M5 8871 E5 2620V4     32G  双电源  3*1T  raid5  . 原系统由供应商(日闹)上家安装,在安装好的SQL2008,到 ...

  4. MyEclipse的代码自动提示功能

     一般默认情况下,Eclipse ,MyEclipse的代码提示功能是比Microsoft Visual Studio的差很多的,主要是Eclipse ,MyEclipse本身有很多选项是默认关闭的, ...

  5. Windows10 Linux子系统的启用和中文用户名的修改

    一直用的虚拟机Linux,忽然心血来潮,看到Windows 10可以使用Linux子系统,于是来装一波,按照这位前辈的教程 https://blog.csdn.net/zhangdongren/art ...

  6. Javascript 模块化理解

    原始时代: script标签引入javascript文件 -------- html ------- <div id="result"></div> < ...

  7. Reference Counting GC (Part one)

    目录 引用计数法 计数器值的增减 new_obj()和update_ptr()函数 new_obj()生成对象 update_ptr()更新指针ptr,对计数器进行增减 优点 可即可回收垃圾 最大暂停 ...

  8. CCF模拟题 窗口

    窗口 时间限制: 1.0s 内存限制: 256.0MB   问题描述 在某图形操作系统中,有 N 个窗口,每个窗口都是一个两边与坐标轴分别平行的矩形区域.窗口的边界上的点也属于该窗口.窗口之间有层次的 ...

  9. CCF模拟题 最大的矩形

    最大的矩形 时间限制: 1.0s 内存限制: 256.0MB     问题描述 在横轴上放了n个相邻的矩形,每个矩形的宽度是1,而第i(1 ≤ i ≤ n)个矩形的高度是hi.这n个矩形构成了一个直方 ...

  10. qt程序实现打开文件夹

    QString path=QDir::currentPath();//获取程序当前目录 path.replace("/","\\");//将地址中的" ...