socket UDP简单通讯
- //
- // SocketUDPServerClient.m
- // socket_server_client
- //
- // Created by lujunjie on 2016/11/26.
- // Copyright © 2016年 lujunjie. All rights reserved.
- //
- #import "SocketUDPServerClient.h"
- #import <sys/socket.h>
- #import <netinet/in.h>
- #import <arpa/inet.h>
- #import "UDPProtocolHerader.h"
- #import <ifaddrs.h>
- #include <net/if.h>
- @interface SocketUDPServerClient()
- {
- in_addr_t broadcastClientAddr; // 发送广播的地址
- }
- @end
- @implementation SocketUDPServerClient
- int serverSockfd = -;
- /**
- 启动服务监听接收广播
- */
- - (void)startUDPServer
- {
- // 第一步:打开套节字描述
- serverSockfd = socket(AF_INET, SOCK_DGRAM, );// 协议族、数据报、0
- if(serverSockfd < )
- {
- NSLog(@"error:打开套节字描述符失败socket()");
- }
- NSLog(@"打开套节字描述sockfd:%d",serverSockfd);
- // 第二步:设置广播包
- int opt;
- if ((setsockopt(serverSockfd, SOL_SOCKET, SO_BROADCAST, &opt, sizeof(int)))< ) {
- NSLog(@"error:广播包setsockopt");
- }
- // 第三步: bind
- struct sockaddr_in serveraddr;
- serveraddr.sin_family = AF_INET;
- serveraddr.sin_port = htons(); // 5000~655355
- serveraddr.sin_addr.s_addr = INADDR_ANY;
- // 当你调用bind()函数绑定IP时使用INADDR_ANY ,明接收来自任意IP、任意网卡的发给指定端口的数据。作为发送端,当用调用bind()函数绑定IP时使用INADDR_ANY,表明使用网卡号最低的网卡进行发送数据,也就是UDP数据广播。
- if ((bind(serverSockfd, (struct sockaddr *)&serveraddr, sizeof(serveraddr))) < ) {
- NSLog(@"error:bind");
- }
- [NSThread detachNewThreadSelector:@selector(recvFromThread) toTarget:self withObject:nil];
- }
- - (void)recvFromThread
- {
- struct sockaddr_in clientaddr;
- socklen_t clientaddrLen = sizeof(clientaddr);
- int msgHeaderSize = sizeof(CC_searchBrodcastHeader);
- char *buf = (char *)malloc(msgHeaderSize);
- memset(buf, , sizeof(msgHeaderSize));
- long recvSize = ;
- while () {
- if ([self selectReadSockfd:serverSockfd]) {
- long recvRet = recvfrom(serverSockfd,buf + recvSize,msgHeaderSize -recvSize, ,(struct sockaddr *)&clientaddr,&clientaddrLen);
- if (recvRet <= ) {
- NSLog(@"<= 0 error:recvfrom errorcode:%zi",recvRet);
- sleep();
- continue;
- }
- recvSize += recvRet;
- if (recvSize >= msgHeaderSize) {
- NSString *ipaddr = [self getIPAddress];
- const char *addr = [ipaddr UTF8String];
- NSString* tempIPString=[NSString stringWithCString:inet_ntoa(clientaddr.sin_addr) encoding:NSUTF8StringEncoding];
- NSLog(@"RECV:::::IPADDR: %@",tempIPString);
- if (clientaddr.sin_addr.s_addr != inet_addr(addr)) {// 自己不能收到自己的广播
- // 接收到的广播
- broadcastClientAddr = clientaddr.sin_addr.s_addr;
- [self recvSuccessWithBuf:buf];
- }
- // 清空出来
- recvSize = ;
- memset(buf, , sizeof(msgHeaderSize));
- }
- }
- }
- }
- - (BOOL)selectReadSockfd:(int)sockfd
- {
- fd_set read_set;
- struct timeval tmval;
- tmval.tv_sec = ;
- tmval.tv_usec = ;
- FD_ZERO(&read_set); // 将指定的文件描述符集清空
- FD_SET(sockfd,&read_set); // 用于在文件描述符集合中增加一个新的文件描述符
- int ret =select(sockfd+,&read_set, NULL, NULL,&tmval);
- if (ret <= ) {
- NSLog(@"<= 0 error:select errorcode:%zi",ret);
- return NO;
- }
- if (FD_ISSET(sockfd, &read_set)) {
- return YES;
- }
- return NO;
- }
- - (BOOL)selectWriteSockfd:(int)sockfd
- {
- fd_set w_set;
- struct timeval tmval;
- tmval.tv_sec = ;
- tmval.tv_usec = ;
- FD_ZERO(&w_set); // 将指定的文件描述符集清空
- FD_SET(sockfd,&w_set); // 用于在文件描述符集合中增加一个新的文件描述符
- int ret =select(sockfd+,NULL, &w_set, NULL,&tmval);
- if (ret <= ) {
- NSLog(@"<= 0 error:select errorcode:%zi",ret);
- return NO;
- }
- if (FD_ISSET(sockfd, &w_set)) {
- return YES;
- }
- return NO;
- }
- - (void)recvSuccessWithBuf:(char *)buf
- {
- CC_searchBrodcastHeader *header = (CC_searchBrodcastHeader *)buf;
- char pheader[] = {};
- memcpy(pheader,header->protocolHeader, sizeof(pheader));
- memset(pheader+, , );
- NSString *protocolHeader=[NSString stringWithCString:pheader encoding:NSASCIIStringEncoding];
- if ([protocolHeader isEqualToString:@"CC"]) {
- if (header->controlMask == udp_broadcast_request) {
- [self sendtoClient];
- }else if(header->controlMask == udp_broadCast_reply)
- {
- struct in_addr temp_in_addr;
- memset(&temp_in_addr, , sizeof(temp_in_addr));
- memcpy(&temp_in_addr, &header->IP, sizeof(header->IP));
- NSString* tempIPString=[NSString stringWithCString:inet_ntoa(temp_in_addr) encoding:NSUTF8StringEncoding];
- NSLog(@"对方的IP地址是: %@",tempIPString);
- }
- }
- }
- - (void)sendtoClient
- {
- // 回复
- NSString *ipaddr = [self getIPAddress];
- const char *localAddr = [ipaddr UTF8String];
- CC_searchBrodcastHeader header;
- memset(&header, , sizeof(header));
- header.controlMask = udp_broadCast_reply;
- header.protocolHeader[] = 'C';
- header.protocolHeader[] = 'C';
- header.IP = inet_addr(localAddr);
- char *buf = (char *)malloc(sizeof(header));
- memcpy(buf, &header, sizeof(header));
- if ([self selectWriteSockfd:serverSockfd]) {
- if ([self sendtoWithSockfd:serverSockfd Buffer:buf size:sizeof(header) addr:broadcastClientAddr]) {
- NSLog(@"=====IP:%@",ipaddr);
- NSLog(@"=====IP发送成功");
- }
- }
- }
- - (BOOL)sendtoWithSockfd:(int)sockfd Buffer:(char *)buffer size:(int)size addr:(in_addr_t)addr
- {
- struct sockaddr_in clientaddr;
- clientaddr.sin_family = AF_INET;
- clientaddr.sin_port = htons();
- clientaddr.sin_addr.s_addr = addr;
- long sendSize = ;
- while (sendSize < size) {
- long retSize = sendto(sockfd, buffer+sendSize, size-sendSize, , (struct sockaddr*)&clientaddr, sizeof(clientaddr));
- if (retSize <= ) {
- continue;
- }
- sendSize += retSize;
- if (sendSize >= size) {
- // 发送成功
- return true;
- }
- }
- return true;
- }
- int clientSockfd = -;
- /**
- 发送广播
- */
- - (void)searchUDPServer
- {
- // 第一步:打开套节字描述
- clientSockfd = socket(AF_INET, SOCK_DGRAM, );// 协议族、数据报、0
- if(clientSockfd < )
- {
- NSLog(@"error:打开套节字描述符失败socket()");
- }
- NSLog(@"打开套节字描述sockfd:%d",clientSockfd);
- // 第二步:设置广播包
- int clientOpt;
- if ((setsockopt(clientSockfd, SOL_SOCKET, SO_BROADCAST, &clientOpt, sizeof(int)))< ) {
- NSLog(@"error:广播包setsockopt");
- }
- if ([self selectSockfd:clientSockfd]) {
- CC_searchBrodcastHeader header;
- memset(&header, , sizeof(header));
- header.controlMask = udp_broadcast_request;
- header.protocolHeader[] = 'C';
- header.protocolHeader[] = 'C';
- char *buf = (char *)malloc(sizeof(header));
- memcpy(buf, &header, sizeof(header));
- if ([self sendtoWithSockfd:clientSockfd Buffer:buf size:sizeof(header) addr:INADDR_BROADCAST]) {
- NSLog(@"=====广播发送成功");
- }
- }
- close(clientSockfd);
- clientSockfd = -;
- }
- - (BOOL)selectSockfd:(int)sockfd
- {
- fd_set w_set;
- struct timeval tmval;
- tmval.tv_sec = ;
- tmval.tv_usec = ;
- FD_ZERO(&w_set); // 将指定的文件描述符集清空
- FD_SET(sockfd,&w_set); // 用于在文件描述符集合中增加一个新的文件描述符
- int ret =select(sockfd+,NULL, &w_set, NULL,&tmval);
- if (ret <= ) {
- NSLog(@"<= 0 error:select errorcode:%zi",ret);
- return NO;
- }
- if (FD_ISSET(sockfd, &w_set)) {
- return YES;
- }
- return NO;
- }
- - (NSString *)getIPAddress
- {
- NSArray *searchArray = @[@"en1/ipv4",@"en0/ipv4"];
- NSDictionary *addresses = [self getIPAddresses];
- NSLog(@"addresses: %@", addresses);
- __block NSString *address;
- [searchArray enumerateObjectsUsingBlock:^(NSString *key, NSUInteger idx, BOOL *stop)
- {
- address = addresses[key];
- if(address) *stop = YES;
- } ];
- return address ? address : @"0.0.0.0";
- }
- - (NSDictionary *)getIPAddresses
- {
- NSMutableDictionary *addresses = [NSMutableDictionary dictionaryWithCapacity:];
- // retrieve the current interfaces - returns 0 on success
- struct ifaddrs *interfaces;
- if(!getifaddrs(&interfaces)) {
- // Loop through linked list of interfaces
- struct ifaddrs *interface;
- for(interface=interfaces; interface; interface=interface->ifa_next) {
- if(!(interface->ifa_flags & IFF_UP) /* || (interface->ifa_flags & IFF_LOOPBACK) */ ) {
- continue; // deeply nested code harder to read
- }
- const struct sockaddr_in *addr = (const struct sockaddr_in*)interface->ifa_addr;
- char addrBuf[ MAX(INET_ADDRSTRLEN, INET6_ADDRSTRLEN) ];
- if(addr && (addr->sin_family==AF_INET || addr->sin_family==AF_INET6)) {
- NSString *name = [NSString stringWithUTF8String:interface->ifa_name];
- NSString *type;
- if(addr->sin_family == AF_INET) {
- if(inet_ntop(AF_INET, &addr->sin_addr, addrBuf, INET_ADDRSTRLEN)) {
- type = @"ipv4";
- }
- } else {
- const struct sockaddr_in6 *addr6 = (const struct sockaddr_in6*)interface->ifa_addr;
- if(inet_ntop(AF_INET6, &addr6->sin6_addr, addrBuf, INET6_ADDRSTRLEN)) {
- type = @"ipv6";
- }
- }
- if(type) {
- NSString *key = [NSString stringWithFormat:@"%@/%@", name, type];
- addresses[key] = [NSString stringWithUTF8String:addrBuf];
- }
- }
- }
- // Free memory
- freeifaddrs(interfaces);
- }
- return [addresses count] ? addresses : nil;
- }
- @end
socket UDP简单通讯的更多相关文章
- socket TCP简单通讯
socket 服务器 // // main.m // socket_server // // Created by lujunjie on 2016/11/23. // Copyright © 201 ...
- C++ 利用socket实现TCP,UDP网络通讯
学习孙鑫老师的vc++深入浅出,有一段时间了,第一次接触socket说实话有点儿看不懂,第一次基本上是看他说一句我写一句完成的,第二次在看SOCKET多少有点儿感觉了,接下来我把利用SOCKET完成T ...
- socket.io简单说明及在线抽奖demo
socket.io简单说明及在线抽奖demo socket.io 简介 Socket.IO可以实现实时双向的基于事件的通信. 它适用于各种平台,浏览器或设备,也同样注重可靠性和速度. socket.i ...
- Nginx学习笔记(四) 源码分析&socket/UDP/shmem
源码分析 在茫茫的源码中,看到了几个好像挺熟悉的名字(socket/UDP/shmem).那就来看看这个文件吧!从简单的开始~~~ src/os/unix/Ngx_socket.h&Ngx_s ...
- socket.io简单入门(一.实现简单的图表推送)
引子:随着nodejs蓬勃发展,虽然主要业务系统因为架构健壮性不会选择nodejs座位应用服务器.但是大量的内部系统却可以使用nodejs试水,大量的前端开发人员转入全堆开发也是一个因素. 研究本例主 ...
- Winform MDI窗体容器、权限、简单通讯
MDI窗体容器: 一般来说,窗体是顶级容器,不允许放在其他任何容器内,但是如果将某个窗体的IsMdiContainer属性设置为True,那此窗体就会成为窗体容器,可以在其中放入其他窗体 在内部的窗体 ...
- Winform MDI窗体容器,权限以及简单通讯
MDI窗体容器: 一般来说,窗体是顶级容器,不允许放在其他任何容器内,但是如果将某个窗体的IsMdiContainer属性设置为True,那此窗体就会成为窗体容器,可以在其中放入其他窗体 在内部的窗体 ...
- Winform MDI窗体容器 权限 简单通讯
MDI窗体容器 权限 using System; using System.Collections.Generic; using System.ComponentModel; using Syste ...
- 重新想象 Windows 8 Store Apps (62) - 通信: Socket TCP, Socket UDP
[源码下载] 重新想象 Windows 8 Store Apps (62) - 通信: Socket TCP, Socket UDP 作者:webabcd 介绍重新想象 Windows 8 Store ...
随机推荐
- 未能将基于用户的Visual C++项目设置保存到user文件错误的解决
作者:朱金灿 来源:http://blog.csdn.net/clever101 最近遇见一个诡异错误,将Win7家庭版升级到Win7旗舰版.然后使用原来安装的VS2008开发,保存工程时总是出现未能 ...
- Ionic2集成ArcGIS JavaScript API.md
1. Ionic同原生ArcGIS JavaScript API结合 1.1. 安装esri-loader 在工程目录下命令行安装: npm install angular2-esri-loader ...
- 170703 锐姿公司winserver2012 标准版安装过程
背景: 锐姿公司一台服务器,配置为:X3650M5 8871 E5 2620V4 32G 双电源 3*1T raid5 . 原系统由供应商(日闹)上家安装,在安装好的SQL2008,到 ...
- MyEclipse的代码自动提示功能
一般默认情况下,Eclipse ,MyEclipse的代码提示功能是比Microsoft Visual Studio的差很多的,主要是Eclipse ,MyEclipse本身有很多选项是默认关闭的, ...
- Windows10 Linux子系统的启用和中文用户名的修改
一直用的虚拟机Linux,忽然心血来潮,看到Windows 10可以使用Linux子系统,于是来装一波,按照这位前辈的教程 https://blog.csdn.net/zhangdongren/art ...
- Javascript 模块化理解
原始时代: script标签引入javascript文件 -------- html ------- <div id="result"></div> < ...
- Reference Counting GC (Part one)
目录 引用计数法 计数器值的增减 new_obj()和update_ptr()函数 new_obj()生成对象 update_ptr()更新指针ptr,对计数器进行增减 优点 可即可回收垃圾 最大暂停 ...
- CCF模拟题 窗口
窗口 时间限制: 1.0s 内存限制: 256.0MB 问题描述 在某图形操作系统中,有 N 个窗口,每个窗口都是一个两边与坐标轴分别平行的矩形区域.窗口的边界上的点也属于该窗口.窗口之间有层次的 ...
- CCF模拟题 最大的矩形
最大的矩形 时间限制: 1.0s 内存限制: 256.0MB 问题描述 在横轴上放了n个相邻的矩形,每个矩形的宽度是1,而第i(1 ≤ i ≤ n)个矩形的高度是hi.这n个矩形构成了一个直方 ...
- qt程序实现打开文件夹
QString path=QDir::currentPath();//获取程序当前目录 path.replace("/","\\");//将地址中的" ...