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 ...
随机推荐
- paste---合并文件的列。
Linux paste命令用于合并文件的列. paste指令会把每个文件以列对列的方式,一列列地加以合并. 语法 paste [-s][-d <间隔字符>][--help][--versi ...
- 脚本实现自动化安装lamp&lnmp
#备注:前提是将lnmp和lnmp自动化脚本写好放在相应的路径, 脚本已写好,请查看我博客中的 shell脚本 专栏! #!/bin/bash #安装lamp或者lnmp path=/server/s ...
- 【Uva 10934】Dropping water balloons
[Link]: [Description] 等价题意: 某人在1..n内选一个数x; 然后让你去猜; 你可以问他是不是在哪个范围里; 每次会告诉你YES或者NO; 问你在最坏的情况下猜出答案需要猜多少 ...
- snmpd修改端口
http://blog.csdn.net/cau99/article/details/5077239 http://blog.csdn.net/gua___gua/article/details/48 ...
- IOS的四种数据存储方式及优劣
IOS有四种经常使用数据存储方式: 第一种方法:用NSUserDefaults存储配置信息 NSUserDefaults被设计用来存储设备和应用的配置信息.它通过一个工厂方法返回默认的.也是最经常使用 ...
- 聊聊高并发(十九)理解并发编程的几种"性" -- 可见性,有序性,原子性
这篇的主题本应该放在最初的几篇.讨论的是并发编程最基础的几个核心概念.可是这几个概念又牵扯到非常多的实际技术.比方Java内存模型.各种锁的实现,volatile的实现.原子变量等等,每个都可以展开写 ...
- OpenCascade Sweep Algorithm
OpenCascade Sweep Algorithm eryar@163.com Abstract. Sweeps are the objects you obtain by sweeping a ...
- 一些优秀的学习网站(Android)
突然发现自己学习没有总结,从今天开始会持续更新此博文,总结自己的学习情况,也便于自己时常查阅.官方文档就列举了,因为那是必读资料. 一.GitHub部分 1.我的github仓库地址 收藏了我常看的开 ...
- Looksery Cup 2015
A题水 C题 博弈论,如果不是CF有WA具体哪个点错了和数据的话,AC要难许多. 如果D的操作数大于奇数个数直接Win 偶数个数大于等于n – k 时,S直接Win 偶数个数小于n – k时,若D操作 ...
- 网上看到的一些IT资源
A.网站模板+logo+服务器主机+发票生成 HTML5 UP:响应式的HTML5和CSS3网站模板. Bootswatch:免费的Bootstrap主题. Templated:收集了845个免费的C ...