Socket之iOS项目中的socket应用/IPV6 转换/域名转IP/解析socket接受的数据/心跳包
2017-03-21 17:47
411 查看
使用系统API合成IPv6:
如果你的APP需要连接的服务器 只有IPv4地址,没有域名,可以用 getaddrinfo 来解决。下面的代码,将IPv4地址(如:192.0.2.1) 地址转换为IPv6地址(如:包含 64:ff9b::192.0.2.1 的struct sockaddr_in6 )
==================
#import "LTSocket.h"
#import <netinet/in.h>
#import <unistd.h>
#include <netdb.h>
#include <sys/socket.h>
#include <sys/types.h>
#include <arpa/inet.h>
#import "LTUserInfo.h"
#import "LTAerobicsWarningStatictics.h"
#import "LTSetAerobicsStatictics.h"
#import "LTPondAerobicsInfo.h"
#include <err.h>
#include <fcntl.h>
#include<sys/ioctl.h>
#define TIME_OUT_TIME 20//connect超时时间20秒
@interface LTSocket ()
@property (assign,nonatomic)
NSInteger iFlyState;
@property(retain,nonatomic) NSTimer
*heartbeatTimer;
@end
@implementation LTSocket
- (void)dealloc
{
self.m_pDelegeate =nil;
CFRelease(m_pSocket);
m_pSocket =nil;
[m_pInitThreadrelease];
m_pInitThread =nil;
[superdealloc];
}
- (id)init
{
self = [superinit];
if (self) {
[selfcreateConnect];//LTMainViewController创建的时候实例化socket,到这一步建立连接
////从appdelegate接收的通知
[[NSNotificationCenterdefaultCenter]addObserver:selfselector:@selector(initSocket:)name:@"initSocket"object:nil];
//从溶氧控制页面接收的通知
[[NSNotificationCenterdefaultCenter]addObserver:selfselector:@selector(cancelSocket)name:@"cancelSocket"object:nil];
}
returnself;
}
//点击退出按钮后取消socket
-(void)cancelSocket{
CFSocketInvalidate(m_pSocket);
}
//锁屏后从appdelegate接收通知重新连接socket
-(void)initSocket:(NSNotification *)noti{
[selfcreateConnect];
}
- (void)stopInitThread
{
m_isReturn =YES;
[m_pInitThreadcancel];//线程取消
}
////域名解析成IP
-(NSString*)hostNameToIP{
constchar *ptr;
char **pptr;
structhostent *hptr;//存储转换的结果
char str[32];
/* 取得命令后第一个参数,即要解析的域名或主机名 */
ptr ="www.hefeileran.cn";//60.173.247.137
/* 调用gethostbyname()。调用结果都存在hptr中
*/
if( (hptr =gethostbyname(ptr) ) ==
NULL )
{
printf("gethostbyname error for host:%s\n", ptr);
return0;
/*如果调用gethostbyname发生错误,返回1 */
}
/* 将主机的规范名打出来 */
printf("official hostname:%s\n",hptr->h_name);
/* 主机可能有多个别名,将所有别名分别打出来 */
for(pptr = hptr->h_aliases; *pptr !=NULL; pptr++)
printf(" alias:%s\n",*pptr);
/* 根据地址类型,将地址打出来 */
switch(hptr->h_addrtype)
{
caseAF_INET:
caseAF_INET6:
pptr=hptr->h_addr_list;
/* 将刚才得到的所有地址都打出来。其中调用了inet_ntop()函数
*/
for(;*pptr!=NULL;pptr++)
printf("address:%s\n",inet_ntop(hptr->h_addrtype,
*pptr, str,sizeof(str)));
//********************
NSString *sss =nil;
for(pptr = hptr->h_addr_list; *pptr !=NULL; pptr++){
printf("h_addr_list:%s\n",*pptr);
constchar *s=inet_ntop(hptr->h_addrtype,*pptr,str,sizeof(str));
sss=[NSStringstringWithFormat:@"%s",s];
NSLog(@"-OC-%@-",sss);
}
return sss;
//********************
// break;
// default:
// printf("unknown address type\n");
// break;
}
return0;
}
//建立连接
- (void)createConnect
{
NSString *ipv4_or_ipv6_strs=[selfhostNameToIP];//域名转换成IP地址
NSLog(@"-ddd-%@----",ipv4_or_ipv6_strs);
structaddrinfo hints, *res, *res0;
int error, s;
// const char *cause = NULL;
constchar *ipv4_or_ipv6_str = [ipv4_or_ipv6_strscStringUsingEncoding:NSASCIIStringEncoding];//NSString转成char
*类型
// const char *ipv4_or_ipv6_str = "60.173.247.137";//or IPv6 address string is well /ip地址
// const char *ipv4_or_ipv6_str = "http://www.hefeileran.cn";
NSUInteger port =9001;//port of connecting server/端口号
memset(&hints,0,
sizeof(hints));//分配一个hints结构体,把它清零后填写需要的字段,再调用getaddrinfo,然后遍历一个链表逐个尝试每个返回地址。
hints.ai_family =PF_UNSPEC;
hints.ai_socktype =SOCK_STREAM;
hints.ai_flags =AI_DEFAULT;
int flags;
error = getaddrinfo(ipv4_or_ipv6_str,NULL, &hints, &res);//函数的返回值:成功返回0,失败返回非零的
sockets error code
if (error)//非零则失败
{
errx(1,"%s",
gai_strerror(error));
/*NOTREACHED*/
}
s = -1;
for (res = res0; res; res = res->ai_next)
{
s = socket(res->ai_family,
res->ai_socktype,
res->ai_protocol);//返回值:非负描述符成功,返回一个新的套接字描述,出错返回-1
close(s);/////////////很关键,释放占用的socket描述//////////
//socket 设置成非阻塞状态-------------很重要
flags = fcntl(s,F_GETFL,0);
fcntl(s,F_SETFL, flags |O_NONBLOCK);
//socket 设置成非阻塞状态-------------很重要
//
//socket上下文
CFSocketContext sockContext = {0,
self,
NULL,
NULL,
NULL};
//创建socket
m_pSocket =CFSocketCreate(kCFAllocatorDefault,
res->ai_family,//AF_UNSPEC不限,PF_INET,PF_INET6
res->ai_socktype,
res->ai_protocol,
kCFSocketConnectCallBack,
TCPClientConnectCallBack, //连接后的回调函数
&sockContext
);
if (s <0)
{
// cause = "socket";
continue;
}
switch(res->ai_addr->sa_family)//是IPV4还是IPV6
{
caseAF_INET://IPV4
{
structsockaddr_in *v4sa = (structsockaddr_in
*)res->ai_addr;
v4sa->sin_port =htons(port);
CFDataRef address =CFDataCreate(kCFAllocatorDefault, (UInt8
*)&v4sa,sizeof(v4sa));
// 建立连接
CFSocketConnectToAddress(m_pSocket,
address,
-1 //超时
);
CFRunLoopRef cRunRef =CFRunLoopGetCurrent();
CFRunLoopSourceRef sourceRef =CFSocketCreateRunLoopSource(kCFAllocatorDefault,m_pSocket,
0);
CFRunLoopAddSource(cRunRef,
sourceRef,
kCFRunLoopCommonModes
);
CFRelease(sourceRef);
CFRelease(address);
NSLog(@"连接成功1");
}
break;
caseAF_INET6://IPV6
{
structsockaddr_in6 *v6sa = (structsockaddr_in6
*)res->ai_addr;
v6sa->sin6_port =htons(port);
CFDataRef address6 =CFDataCreate(kCFAllocatorDefault, (UInt8
*)&v6sa,sizeof(v6sa));
//建立连接IPV6
CFSocketConnectToAddress(m_pSocket,
address6,
-1
);
CFRunLoopRef cRunRef =CFRunLoopGetCurrent();
CFRunLoopSourceRef sourceRef =CFSocketCreateRunLoopSource(kCFAllocatorDefault,m_pSocket,
0);
CFRunLoopAddSource(cRunRef,
sourceRef,
kCFRunLoopCommonModes
);
CFRelease(sourceRef);
CFRelease(address6);
NSLog(@"连接成功2");
}
break;
}
// 函数说明:connect()用来将参数sockfd的socket连至参数serv_addr指定的网络地址.结构sockaddr请参考bind().参数addrlen为sockaddr的结构长度.
//
// 返回值:成功则返回0,失败返回-1,错误原因存于errno中.
//
// 错误代码:
// 1、EBADF参数sockfd非合法socket处理代码
// 2、EFAULT参数serv_addr指针指向无法存取的内存空间
// 3、ENOTSOCK参数sockfd为一文件描述词,非socket.
// 4、EISCONN参数sockfd的socket已是连线状态
// 5、 ETIMEDOUT企图连线的操作超过限定时间仍未有响应.
// 6、ENETUNREACH无法传送数据包至指定的主机.
// 7、EAFNOSUPPORT sockaddr结构的sa_family不正确.
// 8、EALREADY socket为不可阻断且先前的连线操作还未完成.
if (connect(s, res->ai_addr, res->ai_addrlen)
< 0)//连接失败的处理
{
close(s);//关闭套接字描述
//socket 设置成非阻塞状态-------------很重要
flags = fcntl(s,F_GETFL,0);
fcntl(s,F_SETFL, flags |O_NONBLOCK);
//socket 设置成非阻塞状态-------------很重要
s = -1;
continue;
}
break;///连接成功就跳出循环
}
freeaddrinfo(res);
}
////关闭socket---无用
//- (void)closeSocket
//{
// CFSocketInvalidate(m_pSocket);
//}
//建立连接后的回调函数判断是否连接成功 (有数据返回说明没有连接成功)
static void TCPClientConnectCallBack(CFSocketRef socket,CFSocketCallBackType
type,CFDataRef address,
const void *data,void *info)
{
LTSocket *client = (LTSocket *)info;
if (data !=NULL)//有数据返回说明没有连接成功
{
NSLog(@"连接失败");
[client loginJudgeFalse:@"连接失败"];
return;
}
else
{
NSLog(@"连接成功");
// LTSocket *client = (LTSocket *)info;
[client connectSuccess];//连接成功
[client StartReadThread];//开启线程,读取数据(如果在电机控制页面点击了开关,就会有数据产生)
[client sendLoginMessage];//发送登录的信息
[client sendHeartbeat];//发送心跳检测
}
}
//连接失败
- (void)connectFail
{
if (self.m_pDelegeate && [self.m_pDelegeaterespondsToSelector:@selector(socketConnectFail)])
{
[self.m_pDelegeatesocketConnectFail];
}
}
//连接成功
- (void)connectSuccess
{
if (self.m_pDelegeate && [self.m_pDelegeaterespondsToSelector:@selector(socketConnectSuccess)])
{
[self.m_pDelegeatesocketConnectSuccess];
}
}
//开启新线程,读取数据在这里面实现的
- (void)StartReadThread
{
m_pInitThread = [[NSThreadalloc]initWithTarget:selfselector:@selector(InitThreadFunc:)object:self];
[m_pInitThreadstart];
}
//
- (void)reconnectNetWork1
{
[selfstopTimer];//关闭定时器
if ([LTUserInfodefaultUserInfo].m_isInterrupt
==NO) {
if (self.m_pDelegeate && [self.m_pDelegeaterespondsToSelector:@selector(reconnectNetWork)])
{
[self.m_pDelegeatereconnectNetWork];
}
}
[LTUserInfodefaultUserInfo].m_isInterrupt
=NO;
}
//读取数据在这里面实现
-(void)InitThreadFunc:(id)sender
{NSLog(@"标记1");
while (1) {
BOOL requestStop = [selfreadStream];//读取从服务器接收的数据(如果有数据返回YES,没有数据返回NO)
if (!requestStop)//走到这一步说明没有数据返回
{
NSLog(@"没有数据");
[m_pInitThreadcancel];//取消线程
[selfperformSelectorOnMainThread:@selector(reconnectNetWork1)withObject:nilwaitUntilDone:NO];//回到主线程执行reconnectNetWork方法
return;
}
}
}
//停止定时器
- (void)stopTimer{
if (self.heartbeatTimer) {
[self.heartbeatTimerinvalidate];//定时器失效
self.heartbeatTimer =nil;
}
}
//读取数据(读取服务器返回的数据)
- (BOOL)readStream
{
NSLog(@"标记2");
char buffer[1024];
NSAutoreleasePool *pool = [[NSAutoreleasePoolalloc]
init];
memset(&buffer,0,
sizeof(buffer));//用0覆盖前n个字节
//接收数据
ssize_t bufferSize =recv(CFSocketGetNative(m_pSocket),
buffer,sizeof(buffer),0);//recv方法返回的数据<0出错
,=0关闭连接 ,>接收到的数据大小(多少个字节)
NSLog(@"返回的数据----------------%s",buffer);
NSLog(@"bufferSize----------%zd",bufferSize);//返回的数据大小(所占的字节)
if (bufferSize <=0) {
returnNO;
}
//分析接收到的数据
//buffer是接收到的数据内容字符串;bufferSize是接收到的数据内容大小;
[selfresolveReceiveInfo:bufferBufNum:bufferSize];
memset(&buffer,0,
sizeof(buffer));
[pool release];
pool= nil;
returnYES;
}
//连接失败
- (void)loginJudgeFalse:(NSString *)pMessage
{
if (m_pSocket) {
[LTUserInfodefaultUserInfo].m_isInterrupt =YES;
CFSocketInvalidate(m_pSocket);
}
if (self.m_pDelegeate && [self.m_pDelegeaterespondsToSelector:@selector(loginJudgeFalse:)])
{
[self.m_pDelegeateloginJudgeFalse:pMessage];
}
}
//发送登录信息
- (void)sendLoginMessage {
int num =26;
char *dataList = (char *)malloc(sizeof(char)
* num);
memset(dataList,0,
sizeof(char)*(num));
getHeadData(dataList);
getDeviceData(dataList);
for (NSInteger i =10; i <
18; i++) {
dataList[i] = 0x00;
}
dataList[18] =0x00;
dataList[19] =0x01;
dataList[20] =0x00;///////
dataList[21] =0x00;
dataList[22] =0x00;
getChecksum(dataList,23);
getEndData(dataList, num);
// for (NSInteger i = 0; i < num; i++) {
//
// NSLog(@"sendLoginMessage %d", dataList[i]);
// }
send(CFSocketGetNative(m_pSocket), dataList, num,0);
free(dataList);
}
//定时器隔3秒发送心跳检测
- (void)sendHeartbeat
{
NSTimer *heartbeatTimer = [NSTimerscheduledTimerWithTimeInterval:3.0ftarget:selfselector:@selector(sendHeartbeatMessage)userInfo:nilrepeats:YES];
self.heartbeatTimer = heartbeatTimer;
}
//发送心跳检测信息
- (void)sendHeartbeatMessage
{
int num =27;
char *dataList = (char *)malloc(sizeof(char)
* num);//分配内存空间
memset(dataList,0,
sizeof(char)*(num));//将dataList中前n个字节(用
0替换并返回 dataList。
getHeadData(dataList);
getDeviceData(dataList);
dataList[10] =0x12;
dataList[11] =0x78;
dataList[12] =0xa0;
dataList[13] =0x9c;
dataList[14] =0x00;
dataList[15] =0x00;
dataList[16] =0x00;
dataList[17] =0x00;
dataList[18] =0x00;//////
dataList[19] =0x02;//////
dataList[20] =0x00;//////
dataList[21] =0x00;
dataList[22] =0x01;
dataList[23] =0x00;
getChecksum(dataList,24);
getEndData(dataList, num);
send(CFSocketGetNative(m_pSocket), dataList, num,0);
free(dataList);
// NSLog(@"发心跳包");
}
//发送控制单个电机开关的启消息
- (void)sendCtrSingleDeviceWithDeviceID:(NSString *)deviceID IsOpen:(BOOL)isOpen
PondDeviceId:(char)pondDeviceId
{
int num =28;
char *dataList = (char *)malloc(sizeof(char)
* num);
memset(dataList,0,
sizeof(char)*(num));
getHeadData(dataList);//[0]-[5],帧头(1字节)-厂家信息(2字节)-终端版本号(1字节)-设备类型(2字节)
getCtrDeviceIDStr(dataList, deviceID);//[6]-[9],设备地址(4字节)--数据:00000000-FFFFFFFF
getCtrDeviceCommandSerial(dataList);//[10]-[17]命令流水号(8字节):由命令发起设备产生,应答设备接收后,原封不动进行回传,对命令进行对应。
/**
*具体操作命令字[18]-[19],不同的设备定义了不同的命令字;
*数据:0000-ffff
这里的10表示:数据上报间隔,用两个16进制表示;
*/
dataList[18] =0x00;////////
dataList[19] =0x10;////////
/**
操作标志:(1字节)[20]
(1)00主动上报,接收端此字节用0x80应答。
(2)01查询参数,接收端此字节用0x81应答。
(3)02设置参数,接收端此字节用0x82应答。
(4)03命令执行,接收端此字节用0x83应答。
(5)04命令关闭,接收端此字节用0x84应答。
*数据:00-01
*/
dataList[20] =0x02;////////
if (isOpen) {//开关打开时发送的数据0X01;
getCtrSingleDeviceData(dataList,0x01, pondDeviceId);//获取单个控制设备数据
}
else {//开关关闭时发送的数据0X00;
getCtrSingleDeviceData(dataList,0x00, pondDeviceId);//获取单个控制设备数据
}
getChecksum(dataList,25);//[25][26]和校验码(2字节),从帧头到具体数据的校验
getEndData(dataList, num);//[27]帧尾(1字节),数据#(对应的ASCII吗值是16进制ox23)
for (NSInteger i =0; i < num; i++) {
// NSLog(@"控制设备 %d", dataList[i]);
}
/* 第一个参数指定发送端套接字描述符;
第二个参数指明一个存放应用程式要发送数据的缓冲区;
第三个参数指明实际要发送的数据的字符数;
第四个参数一般置0。*/
send(CFSocketGetNative(m_pSocket), dataList, num,0);//数据由指定
socket传给主机(服务器)
free(dataList);//释放malloc(或calloc、realloc)函数给指针变量分配的内存空间的函数
}
//发送一台机器所有电机(增氧,投饵,滴灌,风机,排污)开关的消息
- (void)sendCtrAllDeviceWithDeviceID:(NSString *)deviceID IsOpen:(BOOL)isOpen
LTPondInfoModal:(LTPondInfoModal *)ltPondInfoModal
{
//如果发送的是全开命令,已经开启的电机就不发送命令了,如果发送的是全关命令,已经关闭的电机就不发送命令了;
NSArray *electricBackStateArr=ltPondInfoModal.electricBackStateArr;
NSLog(@"--pond--%@",electricBackStateArr);
NSString *electric=ltPondInfoModal.electrics;
NSArray *electricsArr=[electriccomponentsSeparatedByString:@","];
for(int i=0;i<electricsArr.count;i++){
if((![electricBackStateArr[i]isEqualToString:@"1"]&&isOpen==YES)||(![electricBackStateArr[i]isEqualToString:@"0"]&&isOpen==NO)){
NSString *str=[NSStringstringWithFormat:@"0x0%d",i+1];
unsignedint deviceIDs;
[[NSScannerscannerWithString:str]scanHexInt:&deviceIDs];
char c=(char) deviceIDs;
// dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(2 * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{
//
// });
[selfsendCtrSingleDeviceWithDeviceID:deviceIDIsOpen:isOpen
PondDeviceId:c];//发送单个电机控制
if(electricsArr.count==7&&i==6){
//必须用GCD延迟执行,并配合socket中的线程改成非阻塞
dispatch_after(dispatch_time(DISPATCH_TIME_NOW,
(int64_t)(0.5*NSEC_PER_SEC)),dispatch_get_main_queue(),
^{
[selfsendCtrSingleDeviceWithDeviceID:deviceIDIsOpen:isOpen
PondDeviceId:0x07];
NSLog(@"第七路执行了");
});
}
if(electricsArr.count==8&&i==7){
dispatch_after(dispatch_time(DISPATCH_TIME_NOW,
(int64_t)(0.5 *NSEC_PER_SEC)),dispatch_get_main_queue(),
^{
[selfsendCtrSingleDeviceWithDeviceID:deviceIDIsOpen:isOpen
PondDeviceId:0x07];
[selfsendCtrSingleDeviceWithDeviceID:deviceIDIsOpen:isOpen
PondDeviceId:0x08];
NSLog(@"第八路执行了");
});
}
//
}
}
return;
}
//数据包长度[21]-[22]和具体的数据[23]-[24]
void getCtrSingleDeviceData(char *dataList,char openData,
char pondDeviceId)
{
/**(2字节)由不同设备之间的通信和业务,决定具体数据包长度。
*数据包长度,N字节(数据包占N个字节的长度)
*数据:N
*把N用两个字节的16进制表示;
*/
dataList[21] =0x00;
dataList[22] =0x02;
/**
*具体的数据(2字节)
*
*/
dataList[23] = pondDeviceId;//把单个的电机号赋值给他
dataList[24] = openData; //0x01表示开,0x00表示关;
}
//获取所有控制设备数据
void getCtrAllDeviceData(char *dataList,char openData)
{
dataList[21] =0x00;
dataList[22] =0x04;
dataList[23] =0x01;
dataList[24] = openData;
dataList[25] =0x02;
dataList[26] = openData;
/////// ///////////////////////lb
// dataList[27] = 0x03;
// dataList[28] = openData;
//
// dataList[29] = 0x04;
// dataList[30] = openData;
//
// dataList[31] = 0x05;
// dataList[32] = openData;
// dataList[33] = 0x06;
// dataList[34] = openData;
//
// dataList[35] = 0x07;
// dataList[36] = openData;
//
// dataList[37] = 0x08;
// dataList[38] = openData;
////////// ///////////////////////lb
}
//设备地址,由DeviceID分解得到
void getCtrDeviceIDStr(char *dataList,NSString *deviceIDStr)
{
NSArray *deviceIDs = [deviceIDStrcomponentsSeparatedByString:@"-"];
for (NSInteger i =0; i < [deviceIDs
count]; i++) {
NSString *deviceIDStr = [deviceIDsobjectAtIndex:i];
unsignedint deviceID;
[[NSScannerscannerWithString:deviceIDStr]scanHexInt:&deviceID];
if (i ==0) {
dataList[6] = (char)deviceID;
}
elseif (i ==
1) {
dataList[7] = (char)deviceID;
}
elseif (i ==
2) {
dataList[8] = (char)deviceID;
}
elseif (i ==
3) {
dataList[9] = (char)deviceID;
}
}
}
//命令流水号(8字节):由命令发起设备产生,应答设备接收后,原封不动进行回传,对命令进行对应。
void getCtrDeviceCommandSerial(char *dataList)
{
dataList[10] =0x12;
dataList[11] =0x78;
dataList[12] =0xa0;
dataList[13] =0x9c;
dataList[14] =0x00;
dataList[15] =0x00;
dataList[16] =0x00;
dataList[17] =0x00;
}
void getHeadData(char *dataList)
{ //帧头(1字节)数据:*(对应的是16进制0x2a)
dataList[0] =0x2a;
//厂家信息:(2字节)数据:HS
, H(ASCII码16进制是0x48),S(ASCII码16进制是0x53)
dataList[1] =0x48;
dataList[2] =0x53;
//版本号,终端版本号(1字节),数据:1-255
dataList[3] =0x03;
//设备类型(2字节),见表设备类型分类,数据:0001-FFFF
dataList[4] =0x00;
dataList[5] =0xfe;///////////这个和水产协议规范的不一样,水产协议是从0,1,2,3,4.......
}
//设备地址(4个字节),数据:00000000-FFFFFFFF
void getDeviceData(char *dataList){
LTUserInfo *userInfo = [LTUserInfodefaultUserInfo];
dataList[6] = userInfo.deviceFriID;//这里的deviceFriID是从loginresult的到,也就是customNO;
dataList[7] = userInfo.deviceSecID;
dataList[8] = userInfo.deviceThiID;//
dataList[9] = userInfo.deviceFouID;//机器号/池塘号
}
//[25][26]和校验码(2字节),从帧头到具体数据的校验,对数据内容的正确性进行验证。数据校验共2个字节,和校验,超过0XFFFF,溢出;
void getChecksum(char *dataList,int checkDataNum)
{
NSInteger sum =0;
for (NSInteger i =0; i < checkDataNum; i++) {
sum += dataList[i] & 0xff;
}
// NSLog(@"sum--------------%zd",sum);
dataList[checkDataNum] = (sum & 0xff00) >>8;//十进制的1062和0xff位与运算再又移8位,得到结果0x4;
dataList[checkDataNum + 1] = sum &0x00ff;//10进制的1062和0xff位与运算,得到0x26
}
//帧尾,数据:#(ASCII码16进制是0x23)
void getEndData(char *dataList,int dataNum)
{
dataList[dataNum - 1] =0x23;
}
#pragma mark -----处理各台电机控制的传感器实时返回的数据
//在readStream方法中调用的下面这个方法
- (void)resolveReceiveInfo:(char *)dataBuf BufNum:(NSInteger)bufNum
{
[selfgetReceiveAllData:dataBufBufNum:bufNum];
}
//获取所有接收到的数据
- (void)getReceiveAllData:(char *)dataBuf BufNum:(NSInteger)bufNum
{NSLog(@"标记3");
NSInteger startNum =0;
BOOL isHaveData =NO;//是否有数据的标示,此处标示没有数据
for (NSInteger i =0; i <
100; i++) {
NSInteger endNum = [selfgetReceiveEndDataNum:dataBufBufNum:bufNum
StartNum:startNum];//这个方法里面有获取实时返回的数据,并设置每一个池塘的模型中各项指标的数据
if (endNum == -1) {
NSLog(@"socket receive error");
break;
}
isHaveData = YES;
if (endNum +1 == bufNum) {
break;
}
}
if (isHaveData ==YES) {
[selfgetReceivePondDataForMainWithpondInfoModel:self.ltPondInfoModal];//回到主线程执行getReceivePondData(通过代理LTRealTimeViewController执行,刷新池塘模型的数据)
}
}
//回到主线程执行getReceivePondData(通过代理LTRealTimeViewController执行,刷新池塘模型的数据)
- (void)getReceivePondDataForMainWithpondInfoModel:(LTPondInfoModal *)ltPondInfoModal
{NSLog(@"标记6");
[selfperformSelectorOnMainThread:@selector(getReceivePondData:)withObject:nilwaitUntilDone:NO];
}
- (void)getReceivePondData:(LTPondInfoModal *)ltPondInfoModal
{
if (self.m_pDelegeate && [self.m_pDelegeaterespondsToSelector:@selector(getReceivePondData:)])
{
[self.m_pDelegeategetReceivePondData:ltPondInfoModal];
}
}
////将NSString转换成十六进制的字符串则可使用如下方式:
- (NSString *)ToHex:(uint16_t)tmpid
{
NSString *nLetterValue;
NSString *str =@"";
uint16_t ttmpig;
NSString *n1;
// for (int i = 0; i<9; i++) {
ttmpig=tmpid%16;
tmpid=tmpid/16;
switch (ttmpig)
{
case10:
nLetterValue =@"A";break;
case11:
nLetterValue =@"B";break;
case12:
nLetterValue =@"C";break;
case13:
nLetterValue =@"D";break;
case14:
nLetterValue =@"E";break;
case15:
nLetterValue =@"F";break;
default:
nLetterValue = [NSStringstringWithFormat:@"%u",ttmpig];
}
// str = [nLetterValue stringByAppendingString:str];
if (tmpid ==0) {
str=[str stringByAppendingString:[NSStringstringWithFormat:@"0%@",nLetterValue]];
return str;
}
if(tmpid >0 && tmpid<=16){
switch (tmpid)
{
case10:
n1 =@"A";break;
case11:
n1 =@"B";break;
case12:
n1 =@"C";break;
case13:
n1 =@"D";break;
case14:
n1 =@"E";break;
case15:
n1 =@"F";break;
default:
n1 = [NSStringstringWithFormat:@"%u",tmpid];
}
str = [n1 stringByAppendingString:nLetterValue];
}
// }
return str;
}
//这个方法里面有获取实时返回的数据,并设置每一个池塘的模型中各项指标的数据
- (NSInteger)getReceiveEndDataNum:(char *)dataBuf BufNum:(NSInteger)bufNum
StartNum:(NSInteger)startNum
{NSLog(@"标记4");
/**
*startNum-----0
*bufNum------返回的数据长度
*dataBuf------返回的数据字符串
*
*/
if (startNum +22 >= bufNum) {
return -1;
}
NSInteger dataNum = ((dataBuf[startNum +21] &
0xff) <<8) + (dataBuf[startNum +22] &
0xff);
NSLog(@"dataNum-----------%zd",dataNum);
////////////////////////
NSString *str=@"";
if((int)bufNum>=71){
for(int i=0;i<(int)bufNum;i++){
// NSLog(@"dataBuff-01-**%@----%zd",[NSString stringWithFormat:@"%d",i], dataBuf[i] & 0xff);
// NSString *cs01=[NSString stringWithFormat:@"%c",dataBuf[i] & 0xff];
NSString *tenToHex=[selfToHex:dataBuf[i]&
0xff];//10进制的转换成16进制
NSLog(@"dataBuff-01-**%@----%@",[NSStringstringWithFormat:@"%d",i],tenToHex);
//拼接字符串
str=[str stringByAppendingString:tenToHex];
//电机的返回状态*////////////////
NSString *electricBackstatuteFirst=[[selfToHex:dataBuf[64]&0xff]
substringToIndex:1];
NSString *electricBackstatuteSecond=[[selfToHex:dataBuf[64]&0xff]
substringFromIndex:1];
NSString *electricBackstatuteThird=[[selfToHex:dataBuf[65]&0xff]
substringToIndex:1];
NSString *electricBackstatuteForth=[[selfToHex:dataBuf[65]&0xff]
substringFromIndex:1];
NSString *electricBackstatuteFifth=[[selfToHex:dataBuf[66]&0xff]
substringToIndex:1];
NSString *electricBackstatuteSixth=[[selfToHex:dataBuf[66]&0xff]
substringFromIndex:1];
NSString *electricBackstatuteSeventh=[[selfToHex:dataBuf[67]&0xff]
substringToIndex:1];
NSString *electricBackstatuteEighth=[[selfToHex:dataBuf[67]&0xff]
substringFromIndex:1];
NSMutableArray *electricBackStaArr=[[NSMutableArrayalloc]init];
[electricBackStaArr addObject:electricBackstatuteFirst];
[electricBackStaArr addObject:electricBackstatuteSecond];
[electricBackStaArr addObject:electricBackstatuteThird];
[electricBackStaArr addObject:electricBackstatuteForth];
[electricBackStaArr addObject:electricBackstatuteFifth];
[electricBackStaArr addObject:electricBackstatuteSixth];
[electricBackStaArr addObject:electricBackstatuteSeventh];
[electricBackStaArr addObject:electricBackstatuteEighth];
self.electricBackstateArr=electricBackStaArr;
//电机的返回状态*////////////////
}
}
NSLog(@"返回的数据-%tu条--%@",bufNum,str);
if (startNum +25 + dataNum >= bufNum) {
return -1;
}
if (dataBuf[startNum +25 + dataNum] !=
0x23) {
return -1;
}
char checkBuf1 = dataBuf[startNum +18] &
0xff;
char checkBuf2 = dataBuf[startNum +19] &
0xff;
if (checkBuf1 ==0x00 && checkBuf2 ==
0x03) {
//[18]-[19]如果是0x00,0x03表示是检测数据上报
NSLog(@"标记***!");
[selfgetRealTimeData:dataBuf
StartNum:startNum];//获取实时数据,并设置每个池塘的模型中的指标数据
}
else {
NSLog(@"标记****2!");
[selfcheckDeviceOnline:dataBufStartNum:startNum];//设置在线/离线状态
}
return startNum +25 + dataNum;
}
//获取实时数据,并设置每个池塘的模型中的指标数据
- (void)getRealTimeData:(char *)dataBuf StartNum:(NSInteger)startNum
{ NSLog(@"标记5");
LTPondInfoModal *pondInfoModal = [selfgetPondInfoWithDeviceFriID:dataBuf[startNum
+6] DeviceSecID:dataBuf[startNum +7]
DeviceThiID:dataBuf[startNum +8]
DeviceFouID:dataBuf[startNum +9]];//通过返回数据的第6.7.8.9的位置字符来判断并获取池塘模型
self.ltPondInfoModal=pondInfoModal;
NSInteger dataNum = (dataBuf[startNum +21] <<
8) + dataBuf[startNum +22];
NSInteger startDataNum =23 + startNum;
NSInteger num = dataNum /5;
for (NSInteger i =0; i < num; i++) {
NSInteger dataRealTimeType = dataBuf[startDataNum];
unsignedchar dataBuf1 = dataBuf[startDataNum +1];
unsignedchar dataBuf2 = dataBuf[startDataNum +2];
unsignedchar dataBuf3 = dataBuf[startDataNum +2];
unsignedchar dataBuf4 = dataBuf[startDataNum +3];
int dataNum = ((dataBuf1 &0xff) <<
24) + ((dataBuf2 &0xff) <<
16) + ((dataBuf3 &0xff) <<
8) + (dataBuf4 &0xff);
float floatNum = *((float *)&dataNum);
if (dataRealTimeType ==1) {
pondInfoModal.doData = floatNum;
NSLog(@"-服务器-溶解氧1*******--%f",pondInfoModal.doData);
//溶氧警告设置
[selfgetDeviceWarningAerobics:pondInfoModalFloatNum:floatNum];
}
elseif (dataRealTimeType ==
2) {
pondInfoModal.dissolvedData = floatNum;
NSLog(@"--溶解氧饱和度1*******--%f",pondInfoModal.dissolvedData);
}
elseif (dataRealTimeType ==
3) {
pondInfoModal.phData = floatNum;
NSLog(@"-服务器-PH1*******--%f",pondInfoModal.phData);
}
elseif (dataRealTimeType ==
4) {
pondInfoModal.ammoniaData = floatNum;
}
elseif (dataRealTimeType ==
5) {
pondInfoModal.temperatureData = floatNum;
NSLog(@"-服务器-温度1******---%f",pondInfoModal.temperatureData);
}
elseif (dataRealTimeType ==
6) {
pondInfoModal.nitriteData = floatNum;
}
elseif (dataRealTimeType ==
7) {
pondInfoModal.levelData = floatNum;
}
elseif (dataRealTimeType ==
8) {
pondInfoModal.hydrogenSulfideData = floatNum;
}
elseif (dataRealTimeType ==
9) {
pondInfoModal.turbidityData = floatNum;
}
elseif (dataRealTimeType ==
10) {
pondInfoModal.salinityData = floatNum;
}
elseif (dataRealTimeType ==
11) {
pondInfoModal.conductivityData = floatNum;
}
elseif (dataRealTimeType ==
12) {
pondInfoModal.codData = floatNum;
}
elseif (dataRealTimeType ==
13) {
pondInfoModal.atmosphericPressureData = floatNum;
}
elseif (dataRealTimeType ==
14) {
pondInfoModal.windVelocityData = floatNum;
}
elseif (dataRealTimeType ==
15) {
pondInfoModal.windDirectionData = floatNum;
}
elseif (dataRealTimeType ==
16) {
pondInfoModal.chlorophyllData = floatNum;
}
elseif (dataRealTimeType ==
17) {
pondInfoModal.airTemperatureData = floatNum;
}
elseif (dataRealTimeType ==
18) {
pondInfoModal.atmosphericHumidityData = floatNum;
}
NSDateFormatter* formatter = [[NSDateFormatteralloc]init];
formatter.dateFormat =@"yyyy-MM-dd HH:mm:ss";
NSString *dateStr = [formatterstringFromDate:[NSDatedate]];
pondInfoModal.lastDateStr = dateStr;
startDataNum += 5;
if(pondInfoModal){//////////////
pondInfoModal.isOnline =@"在线";
pondInfoModal.electricBackStateArr=self.electricBackstateArr;
//延迟执行
dispatch_after(dispatch_time(DISPATCH_TIME_NOW,
(int64_t)(2.0 *NSEC_PER_SEC)),dispatch_get_main_queue(),
^{
//发送通知显示电机状态
[[NSNotificationCenterdefaultCenter]postNotificationName:@"feedBackState"object:niluserInfo:@{@"pondInfoModal":pondInfoModal}];
});
}else{
pondInfoModal.isOnline=@"离线";
}
}
}
//溶氧警告设置
- (void)getDeviceWarningAerobics:(LTPondInfoModal *)pondInfoModal FloatNum:(CGFloat)floatNum
{
//设置的塘口集合
LTSetAerobicsStatictics *setAerobics = [LTSetAerobicsStaticticsdefaultSetAerobicsStatictics];
NSMutableArray *setAerobicsList = setAerobics.setAerobicsList;
if(setAerobicsList.count!=0){
for(int i=0;i<[setAerobicsListcount];i++){
LTPondAerobicsInfo *pondAerobicsInfo = [setAerobicsListobjectAtIndex:i];//设置的一个塘口的数据
CGFloat upperAerobics = [pondAerobicsInfo.upperAerobicsfloatValue];
CGFloat lowerAerobics = [pondAerobicsInfo.lowerAerobicsfloatValue];
//如果pondAerobicsInfo.upperAerobics和lowerAerobics不为空,说明设置了溶氧警告,就把实时返回的溶氧值添加到警告的数组
if(![pondAerobicsInfo.upperAerobicsisEqualToString:@""]&&![pondAerobicsInfo.lowerAerobicsisEqualToString:@""]){
if ([pondAerobicsInfo.deviceIDisEqualToString:pondInfoModal.deviceID])
{
if (upperAerobics >0.0 && lowerAerobics >
0.0) {
if (floatNum > upperAerobics || floatNum < lowerAerobics) {
//设置返回的溶氧数据
[[LTAerobicsWarningStaticticsdefaultAerobicsWarningStatictics]addAerobicsWarningStatictics:floatNumDeviceID:pondInfoModal.deviceID LTSetAerobicsStaticticsArr:setAerobicsListnum:pondAerobicsInfo.pTag];
[selfplaceVoice];//溶氧警告
}
}// return;
}
}elseif([pondAerobicsInfo.upperAerobicsisEqualToString:@""]&&[pondAerobicsInfo.lowerAerobicsisEqualToString:@""]){
//如果pondAerobicsInfo.upperAerobics和lowerAerobics为空,说明没有设置溶氧警告。
}
}
}
}
//设置在线离线状态
- (void)checkDeviceOnline:(char *)dataBuf StartNum:(NSInteger)startNum
{
LTPondInfoModal *pondInfoModal = [selfgetPondInfoWithDeviceFriID:dataBuf[startNum
+6] DeviceSecID:dataBuf[startNum +7]
DeviceThiID:dataBuf[startNum +8]
DeviceFouID:dataBuf[startNum +9]];
if (pondInfoModal ==nil) {
return;
}
if ((dataBuf[startNum +18] ==
0) && (dataBuf[startNum +19] == -2)) {
// NSLog(@"%@
设备在线", pondInfoModal.deviceID);
pondInfoModal.isOnline =@"在线";
}
else
if ((dataBuf[startNum +
18] == 0) && (dataBuf[startNum +19] == -3))
{
// NSLog(@"%@
设备离线", pondInfoModal.deviceID);
pondInfoModal.isOnline =@"离线";///////////////////////
}
}
//判断并获取池塘模型
- (LTPondInfoModal *)getPondInfoWithDeviceFriID:(char)deviceFriID DeviceSecID:(char)deviceSecID
DeviceThiID:(char)deviceThiID DeviceFouID:(char)deviceFouID
{
NSMutableArray *deviceInfoList = [LTUserInfodefaultUserInfo].deviceInfoList;
for (NSInteger i =0; i < [deviceInfoList
count]; i++) {
LTDeviceInfoModal *deviceInfo = [deviceInfoListobjectAtIndex:i];
for (NSInteger j =0; j < [deviceInfo.pondListcount];
j++) {
LTPondInfoModal *pondInfoModal = [deviceInfo.pondListobjectAtIndex:j];
if ((deviceFriID == pondInfoModal.deviceFriID) && (deviceSecID == pondInfoModal.deviceSecID)
&& (deviceThiID == pondInfoModal.deviceThiID) && (deviceFouID == pondInfoModal.deviceFouID)) {
return pondInfoModal;
}
}
}
returnnil;
}
#pragma mark - 科大讯飞的语音系统
#pragma mark - 播放警报
- (void)placeVoice
{
NSLog(@"溶氧警告");
}
- (void)onStart
{
}
- (CGFloat)hexChangeFloat:(int)dataNum
{
CGFloat floatNum = *((CGFloat *)&dataNum);
return floatNum;
}
- (int)floatChangeFloat:(float)dataNum
{
int intNum = *((int *)&dataNum);
return intNum;
}
- (void)getRealTimeData1:(char *)dataBuf BufNum:(NSInteger)bufNum
{
if (bufNum <40) {
return;
}
// NSLog(@"getRealTimeData");
LTPondInfoModal *pondInfoModal =nil;
NSMutableArray *deviceInfoList = [LTUserInfodefaultUserInfo].deviceInfoList;
for (NSInteger i =0; i < [deviceInfoList
count]; i++) {
LTDeviceInfoModal *deviceInfo = [deviceInfoListobjectAtIndex:i];
for (NSInteger j =0; j < [deviceInfo.pondListcount];
j++) {
LTPondInfoModal *tmpPondInfoModal = [deviceInfo.pondListobjectAtIndex:j];
if ((dataBuf[6] == tmpPondInfoModal.deviceFriID) && (dataBuf[7]
== tmpPondInfoModal.deviceSecID) && (dataBuf[8] == tmpPondInfoModal.deviceThiID) && (dataBuf[9]
== tmpPondInfoModal.deviceFouID)) {
pondInfoModal = tmpPondInfoModal;
// NSLog(@"我要 deviceid %@", pondInfoModal.deviceID);
break;
}
}
}
NSInteger dataNum = (dataBuf[21] <<8) + dataBuf[22];
NSInteger startNum =23;
NSInteger num = dataNum /5;
for (NSInteger i =0; i < num; i++) {
NSInteger dataRealTimeType = dataBuf[startNum];
unsignedchar dataBuf1 = dataBuf[startNum +1];
unsignedchar dataBuf2 = dataBuf[startNum +2];
unsignedchar dataBuf3 = dataBuf[startNum +2];
unsignedchar dataBuf4 = dataBuf[startNum +3];
NSInteger dataNum = ((dataBuf1 &0xff) <<
24) + ((dataBuf2 &0xff) <<
16) + ((dataBuf3 &0xff) <<
8) + (dataBuf4 &0xff);
CGFloat floatNum = *((CGFloat *)&dataNum);
if (dataRealTimeType ==1) {
pondInfoModal.doData = floatNum;
}
elseif (dataRealTimeType ==
2) {
pondInfoModal.dissolvedData = floatNum;
}
elseif (dataRealTimeType ==
3) {
pondInfoModal.phData = floatNum;
}
elseif (dataRealTimeType ==
4) {
pondInfoModal.ammoniaData = floatNum;
}
elseif (dataRealTimeType ==
5) {
pondInfoModal.temperatureData = floatNum;
}
elseif (dataRealTimeType ==
6) {
pondInfoModal.nitriteData = floatNum;
}
elseif (dataRealTimeType ==
7) {
pondInfoModal.levelData = floatNum;
}
elseif (dataRealTimeType ==
8) {
pondInfoModal.hydrogenSulfideData = floatNum;
}
elseif (dataRealTimeType ==
9) {
pondInfoModal.turbidityData = floatNum;
}
elseif (dataRealTimeType ==
10) {
pondInfoModal.salinityData = floatNum;
}
elseif (dataRealTimeType ==
11) {
pondInfoModal.conductivityData = floatNum;
}
elseif (dataRealTimeType ==
12) {
pondInfoModal.codData = floatNum;
}
elseif (dataRealTimeType ==
13) {
pondInfoModal.atmosphericPressureData = floatNum;
}
elseif (dataRealTimeType ==
14) {
pondInfoModal.windVelocityData = floatNum;
}
elseif (dataRealTimeType ==
15) {
pondInfoModal.windDirectionData = floatNum;
}
elseif (dataRealTimeType ==
16) {
pondInfoModal.chlorophyllData = floatNum;
}
elseif (dataRealTimeType ==
17) {
pondInfoModal.airTemperatureData = floatNum;
}
elseif (dataRealTimeType ==
18) {
pondInfoModal.atmosphericHumidityData = floatNum;
}
startNum += 5;
}
[selfperformSelectorOnMainThread:@selector(getReceivePondDataForMainWithpondInfoModel:)withObject:nilwaitUntilDone:NO];
}
- (BOOL)isRealTimeData:(char *)dataBuf
{
char data1 = dataBuf[10];
char data2 = dataBuf[11];
char data3 = dataBuf[12];
char data4 = dataBuf[13];
char data5 = dataBuf[14];
char data6 = dataBuf[15];
char data7 = dataBuf[16];
char data8 = dataBuf[17];
if ((data1 ==18) && (data2 ==
120) && (data3 == -96) && (data4 == -100) && (data5 ==0)
&& (data6 == 0) && (data7 ==0) && (data8 ==
0)) {
returnYES;
}
returnNO;
}
@end
如果你的APP需要连接的服务器 只有IPv4地址,没有域名,可以用 getaddrinfo 来解决。下面的代码,将IPv4地址(如:192.0.2.1) 地址转换为IPv6地址(如:包含 64:ff9b::192.0.2.1 的struct sockaddr_in6 )
#include <sys/socket.h> #include <netdb.h> #include <arpa/inet.h> #include <err.h> uint8_t ipv4[4] = {192, 0, 2, 1}; struct addrinfo hints, *res, *res0; int error, s; const char *cause = NULL; char ipv4_str_buf[INET_ADDRSTRLEN] = { 0 }; const char *ipv4_str = inet_ntop(AF_INET, &ipv4, ipv4_str_buf, sizeof(ipv4_str_buf)); memset(&hints, 0, sizeof(hints)); hints.ai_family = PF_UNSPEC; hints.ai_socktype = SOCK_STREAM; hints.ai_flags = AI_DEFAULT; error = getaddrinfo(ipv4_str, "http", &hints, &res0); if (error) { errx(1, "%s", gai_strerror(error)); /*NOTREACHED*/ } s = -1; for (res = res0; res; res = res->ai_next) { s = socket(res->ai_family, res->ai_socktype, res->ai_protocol); if (s < 0) { cause = "socket"; continue; } if (connect(s, res->ai_addr, res->ai_addrlen) < 0) { cause = "connect"; close(s); s = -1; continue; } break; /* okay we got one */ } if (s < 0) { err(1, "%s", cause); /*NOTREACHED*/ } freeaddrinfo(res0);
==================
#import "LTSocket.h"
#import <netinet/in.h>
#import <unistd.h>
#include <netdb.h>
#include <sys/socket.h>
#include <sys/types.h>
#include <arpa/inet.h>
#import "LTUserInfo.h"
#import "LTAerobicsWarningStatictics.h"
#import "LTSetAerobicsStatictics.h"
#import "LTPondAerobicsInfo.h"
#include <err.h>
#include <fcntl.h>
#include<sys/ioctl.h>
#define TIME_OUT_TIME 20//connect超时时间20秒
@interface LTSocket ()
@property (assign,nonatomic)
NSInteger iFlyState;
@property(retain,nonatomic) NSTimer
*heartbeatTimer;
@end
@implementation LTSocket
- (void)dealloc
{
self.m_pDelegeate =nil;
CFRelease(m_pSocket);
m_pSocket =nil;
[m_pInitThreadrelease];
m_pInitThread =nil;
[superdealloc];
}
- (id)init
{
self = [superinit];
if (self) {
[selfcreateConnect];//LTMainViewController创建的时候实例化socket,到这一步建立连接
////从appdelegate接收的通知
[[NSNotificationCenterdefaultCenter]addObserver:selfselector:@selector(initSocket:)name:@"initSocket"object:nil];
//从溶氧控制页面接收的通知
[[NSNotificationCenterdefaultCenter]addObserver:selfselector:@selector(cancelSocket)name:@"cancelSocket"object:nil];
}
returnself;
}
//点击退出按钮后取消socket
-(void)cancelSocket{
CFSocketInvalidate(m_pSocket);
}
//锁屏后从appdelegate接收通知重新连接socket
-(void)initSocket:(NSNotification *)noti{
[selfcreateConnect];
}
- (void)stopInitThread
{
m_isReturn =YES;
[m_pInitThreadcancel];//线程取消
}
////域名解析成IP
-(NSString*)hostNameToIP{
constchar *ptr;
char **pptr;
structhostent *hptr;//存储转换的结果
char str[32];
/* 取得命令后第一个参数,即要解析的域名或主机名 */
ptr ="www.hefeileran.cn";//60.173.247.137
/* 调用gethostbyname()。调用结果都存在hptr中
*/
if( (hptr =gethostbyname(ptr) ) ==
NULL )
{
printf("gethostbyname error for host:%s\n", ptr);
return0;
/*如果调用gethostbyname发生错误,返回1 */
}
/* 将主机的规范名打出来 */
printf("official hostname:%s\n",hptr->h_name);
/* 主机可能有多个别名,将所有别名分别打出来 */
for(pptr = hptr->h_aliases; *pptr !=NULL; pptr++)
printf(" alias:%s\n",*pptr);
/* 根据地址类型,将地址打出来 */
switch(hptr->h_addrtype)
{
caseAF_INET:
caseAF_INET6:
pptr=hptr->h_addr_list;
/* 将刚才得到的所有地址都打出来。其中调用了inet_ntop()函数
*/
for(;*pptr!=NULL;pptr++)
printf("address:%s\n",inet_ntop(hptr->h_addrtype,
*pptr, str,sizeof(str)));
//********************
NSString *sss =nil;
for(pptr = hptr->h_addr_list; *pptr !=NULL; pptr++){
printf("h_addr_list:%s\n",*pptr);
constchar *s=inet_ntop(hptr->h_addrtype,*pptr,str,sizeof(str));
sss=[NSStringstringWithFormat:@"%s",s];
NSLog(@"-OC-%@-",sss);
}
return sss;
//********************
// break;
// default:
// printf("unknown address type\n");
// break;
}
return0;
}
//建立连接
- (void)createConnect
{
NSString *ipv4_or_ipv6_strs=[selfhostNameToIP];//域名转换成IP地址
NSLog(@"-ddd-%@----",ipv4_or_ipv6_strs);
structaddrinfo hints, *res, *res0;
int error, s;
// const char *cause = NULL;
constchar *ipv4_or_ipv6_str = [ipv4_or_ipv6_strscStringUsingEncoding:NSASCIIStringEncoding];//NSString转成char
*类型
// const char *ipv4_or_ipv6_str = "60.173.247.137";//or IPv6 address string is well /ip地址
// const char *ipv4_or_ipv6_str = "http://www.hefeileran.cn";
NSUInteger port =9001;//port of connecting server/端口号
memset(&hints,0,
sizeof(hints));//分配一个hints结构体,把它清零后填写需要的字段,再调用getaddrinfo,然后遍历一个链表逐个尝试每个返回地址。
hints.ai_family =PF_UNSPEC;
hints.ai_socktype =SOCK_STREAM;
hints.ai_flags =AI_DEFAULT;
int flags;
error = getaddrinfo(ipv4_or_ipv6_str,NULL, &hints, &res);//函数的返回值:成功返回0,失败返回非零的
sockets error code
if (error)//非零则失败
{
errx(1,"%s",
gai_strerror(error));
/*NOTREACHED*/
}
s = -1;
for (res = res0; res; res = res->ai_next)
{
s = socket(res->ai_family,
res->ai_socktype,
res->ai_protocol);//返回值:非负描述符成功,返回一个新的套接字描述,出错返回-1
close(s);/////////////很关键,释放占用的socket描述//////////
//socket 设置成非阻塞状态-------------很重要
flags = fcntl(s,F_GETFL,0);
fcntl(s,F_SETFL, flags |O_NONBLOCK);
//socket 设置成非阻塞状态-------------很重要
//
//socket上下文
CFSocketContext sockContext = {0,
self,
NULL,
NULL,
NULL};
//创建socket
m_pSocket =CFSocketCreate(kCFAllocatorDefault,
res->ai_family,//AF_UNSPEC不限,PF_INET,PF_INET6
res->ai_socktype,
res->ai_protocol,
kCFSocketConnectCallBack,
TCPClientConnectCallBack, //连接后的回调函数
&sockContext
);
if (s <0)
{
// cause = "socket";
continue;
}
switch(res->ai_addr->sa_family)//是IPV4还是IPV6
{
caseAF_INET://IPV4
{
structsockaddr_in *v4sa = (structsockaddr_in
*)res->ai_addr;
v4sa->sin_port =htons(port);
CFDataRef address =CFDataCreate(kCFAllocatorDefault, (UInt8
*)&v4sa,sizeof(v4sa));
// 建立连接
CFSocketConnectToAddress(m_pSocket,
address,
-1 //超时
);
CFRunLoopRef cRunRef =CFRunLoopGetCurrent();
CFRunLoopSourceRef sourceRef =CFSocketCreateRunLoopSource(kCFAllocatorDefault,m_pSocket,
0);
CFRunLoopAddSource(cRunRef,
sourceRef,
kCFRunLoopCommonModes
);
CFRelease(sourceRef);
CFRelease(address);
NSLog(@"连接成功1");
}
break;
caseAF_INET6://IPV6
{
structsockaddr_in6 *v6sa = (structsockaddr_in6
*)res->ai_addr;
v6sa->sin6_port =htons(port);
CFDataRef address6 =CFDataCreate(kCFAllocatorDefault, (UInt8
*)&v6sa,sizeof(v6sa));
//建立连接IPV6
CFSocketConnectToAddress(m_pSocket,
address6,
-1
);
CFRunLoopRef cRunRef =CFRunLoopGetCurrent();
CFRunLoopSourceRef sourceRef =CFSocketCreateRunLoopSource(kCFAllocatorDefault,m_pSocket,
0);
CFRunLoopAddSource(cRunRef,
sourceRef,
kCFRunLoopCommonModes
);
CFRelease(sourceRef);
CFRelease(address6);
NSLog(@"连接成功2");
}
break;
}
// 函数说明:connect()用来将参数sockfd的socket连至参数serv_addr指定的网络地址.结构sockaddr请参考bind().参数addrlen为sockaddr的结构长度.
//
// 返回值:成功则返回0,失败返回-1,错误原因存于errno中.
//
// 错误代码:
// 1、EBADF参数sockfd非合法socket处理代码
// 2、EFAULT参数serv_addr指针指向无法存取的内存空间
// 3、ENOTSOCK参数sockfd为一文件描述词,非socket.
// 4、EISCONN参数sockfd的socket已是连线状态
// 5、 ETIMEDOUT企图连线的操作超过限定时间仍未有响应.
// 6、ENETUNREACH无法传送数据包至指定的主机.
// 7、EAFNOSUPPORT sockaddr结构的sa_family不正确.
// 8、EALREADY socket为不可阻断且先前的连线操作还未完成.
if (connect(s, res->ai_addr, res->ai_addrlen)
< 0)//连接失败的处理
{
close(s);//关闭套接字描述
//socket 设置成非阻塞状态-------------很重要
flags = fcntl(s,F_GETFL,0);
fcntl(s,F_SETFL, flags |O_NONBLOCK);
//socket 设置成非阻塞状态-------------很重要
s = -1;
continue;
}
break;///连接成功就跳出循环
}
freeaddrinfo(res);
}
////关闭socket---无用
//- (void)closeSocket
//{
// CFSocketInvalidate(m_pSocket);
//}
//建立连接后的回调函数判断是否连接成功 (有数据返回说明没有连接成功)
static void TCPClientConnectCallBack(CFSocketRef socket,CFSocketCallBackType
type,CFDataRef address,
const void *data,void *info)
{
LTSocket *client = (LTSocket *)info;
if (data !=NULL)//有数据返回说明没有连接成功
{
NSLog(@"连接失败");
[client loginJudgeFalse:@"连接失败"];
return;
}
else
{
NSLog(@"连接成功");
// LTSocket *client = (LTSocket *)info;
[client connectSuccess];//连接成功
[client StartReadThread];//开启线程,读取数据(如果在电机控制页面点击了开关,就会有数据产生)
[client sendLoginMessage];//发送登录的信息
[client sendHeartbeat];//发送心跳检测
}
}
//连接失败
- (void)connectFail
{
if (self.m_pDelegeate && [self.m_pDelegeaterespondsToSelector:@selector(socketConnectFail)])
{
[self.m_pDelegeatesocketConnectFail];
}
}
//连接成功
- (void)connectSuccess
{
if (self.m_pDelegeate && [self.m_pDelegeaterespondsToSelector:@selector(socketConnectSuccess)])
{
[self.m_pDelegeatesocketConnectSuccess];
}
}
//开启新线程,读取数据在这里面实现的
- (void)StartReadThread
{
m_pInitThread = [[NSThreadalloc]initWithTarget:selfselector:@selector(InitThreadFunc:)object:self];
[m_pInitThreadstart];
}
//
- (void)reconnectNetWork1
{
[selfstopTimer];//关闭定时器
if ([LTUserInfodefaultUserInfo].m_isInterrupt
==NO) {
if (self.m_pDelegeate && [self.m_pDelegeaterespondsToSelector:@selector(reconnectNetWork)])
{
[self.m_pDelegeatereconnectNetWork];
}
}
[LTUserInfodefaultUserInfo].m_isInterrupt
=NO;
}
//读取数据在这里面实现
-(void)InitThreadFunc:(id)sender
{NSLog(@"标记1");
while (1) {
BOOL requestStop = [selfreadStream];//读取从服务器接收的数据(如果有数据返回YES,没有数据返回NO)
if (!requestStop)//走到这一步说明没有数据返回
{
NSLog(@"没有数据");
[m_pInitThreadcancel];//取消线程
[selfperformSelectorOnMainThread:@selector(reconnectNetWork1)withObject:nilwaitUntilDone:NO];//回到主线程执行reconnectNetWork方法
return;
}
}
}
//停止定时器
- (void)stopTimer{
if (self.heartbeatTimer) {
[self.heartbeatTimerinvalidate];//定时器失效
self.heartbeatTimer =nil;
}
}
//读取数据(读取服务器返回的数据)
- (BOOL)readStream
{
NSLog(@"标记2");
char buffer[1024];
NSAutoreleasePool *pool = [[NSAutoreleasePoolalloc]
init];
memset(&buffer,0,
sizeof(buffer));//用0覆盖前n个字节
//接收数据
ssize_t bufferSize =recv(CFSocketGetNative(m_pSocket),
buffer,sizeof(buffer),0);//recv方法返回的数据<0出错
,=0关闭连接 ,>接收到的数据大小(多少个字节)
NSLog(@"返回的数据----------------%s",buffer);
NSLog(@"bufferSize----------%zd",bufferSize);//返回的数据大小(所占的字节)
if (bufferSize <=0) {
returnNO;
}
//分析接收到的数据
//buffer是接收到的数据内容字符串;bufferSize是接收到的数据内容大小;
[selfresolveReceiveInfo:bufferBufNum:bufferSize];
memset(&buffer,0,
sizeof(buffer));
[pool release];
pool= nil;
returnYES;
}
//连接失败
- (void)loginJudgeFalse:(NSString *)pMessage
{
if (m_pSocket) {
[LTUserInfodefaultUserInfo].m_isInterrupt =YES;
CFSocketInvalidate(m_pSocket);
}
if (self.m_pDelegeate && [self.m_pDelegeaterespondsToSelector:@selector(loginJudgeFalse:)])
{
[self.m_pDelegeateloginJudgeFalse:pMessage];
}
}
//发送登录信息
- (void)sendLoginMessage {
int num =26;
char *dataList = (char *)malloc(sizeof(char)
* num);
memset(dataList,0,
sizeof(char)*(num));
getHeadData(dataList);
getDeviceData(dataList);
for (NSInteger i =10; i <
18; i++) {
dataList[i] = 0x00;
}
dataList[18] =0x00;
dataList[19] =0x01;
dataList[20] =0x00;///////
dataList[21] =0x00;
dataList[22] =0x00;
getChecksum(dataList,23);
getEndData(dataList, num);
// for (NSInteger i = 0; i < num; i++) {
//
// NSLog(@"sendLoginMessage %d", dataList[i]);
// }
send(CFSocketGetNative(m_pSocket), dataList, num,0);
free(dataList);
}
//定时器隔3秒发送心跳检测
- (void)sendHeartbeat
{
NSTimer *heartbeatTimer = [NSTimerscheduledTimerWithTimeInterval:3.0ftarget:selfselector:@selector(sendHeartbeatMessage)userInfo:nilrepeats:YES];
self.heartbeatTimer = heartbeatTimer;
}
//发送心跳检测信息
- (void)sendHeartbeatMessage
{
int num =27;
char *dataList = (char *)malloc(sizeof(char)
* num);//分配内存空间
memset(dataList,0,
sizeof(char)*(num));//将dataList中前n个字节(用
0替换并返回 dataList。
getHeadData(dataList);
getDeviceData(dataList);
dataList[10] =0x12;
dataList[11] =0x78;
dataList[12] =0xa0;
dataList[13] =0x9c;
dataList[14] =0x00;
dataList[15] =0x00;
dataList[16] =0x00;
dataList[17] =0x00;
dataList[18] =0x00;//////
dataList[19] =0x02;//////
dataList[20] =0x00;//////
dataList[21] =0x00;
dataList[22] =0x01;
dataList[23] =0x00;
getChecksum(dataList,24);
getEndData(dataList, num);
send(CFSocketGetNative(m_pSocket), dataList, num,0);
free(dataList);
// NSLog(@"发心跳包");
}
//发送控制单个电机开关的启消息
- (void)sendCtrSingleDeviceWithDeviceID:(NSString *)deviceID IsOpen:(BOOL)isOpen
PondDeviceId:(char)pondDeviceId
{
int num =28;
char *dataList = (char *)malloc(sizeof(char)
* num);
memset(dataList,0,
sizeof(char)*(num));
getHeadData(dataList);//[0]-[5],帧头(1字节)-厂家信息(2字节)-终端版本号(1字节)-设备类型(2字节)
getCtrDeviceIDStr(dataList, deviceID);//[6]-[9],设备地址(4字节)--数据:00000000-FFFFFFFF
getCtrDeviceCommandSerial(dataList);//[10]-[17]命令流水号(8字节):由命令发起设备产生,应答设备接收后,原封不动进行回传,对命令进行对应。
/**
*具体操作命令字[18]-[19],不同的设备定义了不同的命令字;
*数据:0000-ffff
这里的10表示:数据上报间隔,用两个16进制表示;
*/
dataList[18] =0x00;////////
dataList[19] =0x10;////////
/**
操作标志:(1字节)[20]
(1)00主动上报,接收端此字节用0x80应答。
(2)01查询参数,接收端此字节用0x81应答。
(3)02设置参数,接收端此字节用0x82应答。
(4)03命令执行,接收端此字节用0x83应答。
(5)04命令关闭,接收端此字节用0x84应答。
*数据:00-01
*/
dataList[20] =0x02;////////
if (isOpen) {//开关打开时发送的数据0X01;
getCtrSingleDeviceData(dataList,0x01, pondDeviceId);//获取单个控制设备数据
}
else {//开关关闭时发送的数据0X00;
getCtrSingleDeviceData(dataList,0x00, pondDeviceId);//获取单个控制设备数据
}
getChecksum(dataList,25);//[25][26]和校验码(2字节),从帧头到具体数据的校验
getEndData(dataList, num);//[27]帧尾(1字节),数据#(对应的ASCII吗值是16进制ox23)
for (NSInteger i =0; i < num; i++) {
// NSLog(@"控制设备 %d", dataList[i]);
}
/* 第一个参数指定发送端套接字描述符;
第二个参数指明一个存放应用程式要发送数据的缓冲区;
第三个参数指明实际要发送的数据的字符数;
第四个参数一般置0。*/
send(CFSocketGetNative(m_pSocket), dataList, num,0);//数据由指定
socket传给主机(服务器)
free(dataList);//释放malloc(或calloc、realloc)函数给指针变量分配的内存空间的函数
}
//发送一台机器所有电机(增氧,投饵,滴灌,风机,排污)开关的消息
- (void)sendCtrAllDeviceWithDeviceID:(NSString *)deviceID IsOpen:(BOOL)isOpen
LTPondInfoModal:(LTPondInfoModal *)ltPondInfoModal
{
//如果发送的是全开命令,已经开启的电机就不发送命令了,如果发送的是全关命令,已经关闭的电机就不发送命令了;
NSArray *electricBackStateArr=ltPondInfoModal.electricBackStateArr;
NSLog(@"--pond--%@",electricBackStateArr);
NSString *electric=ltPondInfoModal.electrics;
NSArray *electricsArr=[electriccomponentsSeparatedByString:@","];
for(int i=0;i<electricsArr.count;i++){
if((![electricBackStateArr[i]isEqualToString:@"1"]&&isOpen==YES)||(![electricBackStateArr[i]isEqualToString:@"0"]&&isOpen==NO)){
NSString *str=[NSStringstringWithFormat:@"0x0%d",i+1];
unsignedint deviceIDs;
[[NSScannerscannerWithString:str]scanHexInt:&deviceIDs];
char c=(char) deviceIDs;
// dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(2 * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{
//
// });
[selfsendCtrSingleDeviceWithDeviceID:deviceIDIsOpen:isOpen
PondDeviceId:c];//发送单个电机控制
if(electricsArr.count==7&&i==6){
//必须用GCD延迟执行,并配合socket中的线程改成非阻塞
dispatch_after(dispatch_time(DISPATCH_TIME_NOW,
(int64_t)(0.5*NSEC_PER_SEC)),dispatch_get_main_queue(),
^{
[selfsendCtrSingleDeviceWithDeviceID:deviceIDIsOpen:isOpen
PondDeviceId:0x07];
NSLog(@"第七路执行了");
});
}
if(electricsArr.count==8&&i==7){
dispatch_after(dispatch_time(DISPATCH_TIME_NOW,
(int64_t)(0.5 *NSEC_PER_SEC)),dispatch_get_main_queue(),
^{
[selfsendCtrSingleDeviceWithDeviceID:deviceIDIsOpen:isOpen
PondDeviceId:0x07];
[selfsendCtrSingleDeviceWithDeviceID:deviceIDIsOpen:isOpen
PondDeviceId:0x08];
NSLog(@"第八路执行了");
});
}
//
}
}
return;
}
//数据包长度[21]-[22]和具体的数据[23]-[24]
void getCtrSingleDeviceData(char *dataList,char openData,
char pondDeviceId)
{
/**(2字节)由不同设备之间的通信和业务,决定具体数据包长度。
*数据包长度,N字节(数据包占N个字节的长度)
*数据:N
*把N用两个字节的16进制表示;
*/
dataList[21] =0x00;
dataList[22] =0x02;
/**
*具体的数据(2字节)
*
*/
dataList[23] = pondDeviceId;//把单个的电机号赋值给他
dataList[24] = openData; //0x01表示开,0x00表示关;
}
//获取所有控制设备数据
void getCtrAllDeviceData(char *dataList,char openData)
{
dataList[21] =0x00;
dataList[22] =0x04;
dataList[23] =0x01;
dataList[24] = openData;
dataList[25] =0x02;
dataList[26] = openData;
/////// ///////////////////////lb
// dataList[27] = 0x03;
// dataList[28] = openData;
//
// dataList[29] = 0x04;
// dataList[30] = openData;
//
// dataList[31] = 0x05;
// dataList[32] = openData;
// dataList[33] = 0x06;
// dataList[34] = openData;
//
// dataList[35] = 0x07;
// dataList[36] = openData;
//
// dataList[37] = 0x08;
// dataList[38] = openData;
////////// ///////////////////////lb
}
//设备地址,由DeviceID分解得到
void getCtrDeviceIDStr(char *dataList,NSString *deviceIDStr)
{
NSArray *deviceIDs = [deviceIDStrcomponentsSeparatedByString:@"-"];
for (NSInteger i =0; i < [deviceIDs
count]; i++) {
NSString *deviceIDStr = [deviceIDsobjectAtIndex:i];
unsignedint deviceID;
[[NSScannerscannerWithString:deviceIDStr]scanHexInt:&deviceID];
if (i ==0) {
dataList[6] = (char)deviceID;
}
elseif (i ==
1) {
dataList[7] = (char)deviceID;
}
elseif (i ==
2) {
dataList[8] = (char)deviceID;
}
elseif (i ==
3) {
dataList[9] = (char)deviceID;
}
}
}
//命令流水号(8字节):由命令发起设备产生,应答设备接收后,原封不动进行回传,对命令进行对应。
void getCtrDeviceCommandSerial(char *dataList)
{
dataList[10] =0x12;
dataList[11] =0x78;
dataList[12] =0xa0;
dataList[13] =0x9c;
dataList[14] =0x00;
dataList[15] =0x00;
dataList[16] =0x00;
dataList[17] =0x00;
}
void getHeadData(char *dataList)
{ //帧头(1字节)数据:*(对应的是16进制0x2a)
dataList[0] =0x2a;
//厂家信息:(2字节)数据:HS
, H(ASCII码16进制是0x48),S(ASCII码16进制是0x53)
dataList[1] =0x48;
dataList[2] =0x53;
//版本号,终端版本号(1字节),数据:1-255
dataList[3] =0x03;
//设备类型(2字节),见表设备类型分类,数据:0001-FFFF
dataList[4] =0x00;
dataList[5] =0xfe;///////////这个和水产协议规范的不一样,水产协议是从0,1,2,3,4.......
}
//设备地址(4个字节),数据:00000000-FFFFFFFF
void getDeviceData(char *dataList){
LTUserInfo *userInfo = [LTUserInfodefaultUserInfo];
dataList[6] = userInfo.deviceFriID;//这里的deviceFriID是从loginresult的到,也就是customNO;
dataList[7] = userInfo.deviceSecID;
dataList[8] = userInfo.deviceThiID;//
dataList[9] = userInfo.deviceFouID;//机器号/池塘号
}
//[25][26]和校验码(2字节),从帧头到具体数据的校验,对数据内容的正确性进行验证。数据校验共2个字节,和校验,超过0XFFFF,溢出;
void getChecksum(char *dataList,int checkDataNum)
{
NSInteger sum =0;
for (NSInteger i =0; i < checkDataNum; i++) {
sum += dataList[i] & 0xff;
}
// NSLog(@"sum--------------%zd",sum);
dataList[checkDataNum] = (sum & 0xff00) >>8;//十进制的1062和0xff位与运算再又移8位,得到结果0x4;
dataList[checkDataNum + 1] = sum &0x00ff;//10进制的1062和0xff位与运算,得到0x26
}
//帧尾,数据:#(ASCII码16进制是0x23)
void getEndData(char *dataList,int dataNum)
{
dataList[dataNum - 1] =0x23;
}
#pragma mark -----处理各台电机控制的传感器实时返回的数据
//在readStream方法中调用的下面这个方法
- (void)resolveReceiveInfo:(char *)dataBuf BufNum:(NSInteger)bufNum
{
[selfgetReceiveAllData:dataBufBufNum:bufNum];
}
//获取所有接收到的数据
- (void)getReceiveAllData:(char *)dataBuf BufNum:(NSInteger)bufNum
{NSLog(@"标记3");
NSInteger startNum =0;
BOOL isHaveData =NO;//是否有数据的标示,此处标示没有数据
for (NSInteger i =0; i <
100; i++) {
NSInteger endNum = [selfgetReceiveEndDataNum:dataBufBufNum:bufNum
StartNum:startNum];//这个方法里面有获取实时返回的数据,并设置每一个池塘的模型中各项指标的数据
if (endNum == -1) {
NSLog(@"socket receive error");
break;
}
isHaveData = YES;
if (endNum +1 == bufNum) {
break;
}
}
if (isHaveData ==YES) {
[selfgetReceivePondDataForMainWithpondInfoModel:self.ltPondInfoModal];//回到主线程执行getReceivePondData(通过代理LTRealTimeViewController执行,刷新池塘模型的数据)
}
}
//回到主线程执行getReceivePondData(通过代理LTRealTimeViewController执行,刷新池塘模型的数据)
- (void)getReceivePondDataForMainWithpondInfoModel:(LTPondInfoModal *)ltPondInfoModal
{NSLog(@"标记6");
[selfperformSelectorOnMainThread:@selector(getReceivePondData:)withObject:nilwaitUntilDone:NO];
}
- (void)getReceivePondData:(LTPondInfoModal *)ltPondInfoModal
{
if (self.m_pDelegeate && [self.m_pDelegeaterespondsToSelector:@selector(getReceivePondData:)])
{
[self.m_pDelegeategetReceivePondData:ltPondInfoModal];
}
}
////将NSString转换成十六进制的字符串则可使用如下方式:
- (NSString *)ToHex:(uint16_t)tmpid
{
NSString *nLetterValue;
NSString *str =@"";
uint16_t ttmpig;
NSString *n1;
// for (int i = 0; i<9; i++) {
ttmpig=tmpid%16;
tmpid=tmpid/16;
switch (ttmpig)
{
case10:
nLetterValue =@"A";break;
case11:
nLetterValue =@"B";break;
case12:
nLetterValue =@"C";break;
case13:
nLetterValue =@"D";break;
case14:
nLetterValue =@"E";break;
case15:
nLetterValue =@"F";break;
default:
nLetterValue = [NSStringstringWithFormat:@"%u",ttmpig];
}
// str = [nLetterValue stringByAppendingString:str];
if (tmpid ==0) {
str=[str stringByAppendingString:[NSStringstringWithFormat:@"0%@",nLetterValue]];
return str;
}
if(tmpid >0 && tmpid<=16){
switch (tmpid)
{
case10:
n1 =@"A";break;
case11:
n1 =@"B";break;
case12:
n1 =@"C";break;
case13:
n1 =@"D";break;
case14:
n1 =@"E";break;
case15:
n1 =@"F";break;
default:
n1 = [NSStringstringWithFormat:@"%u",tmpid];
}
str = [n1 stringByAppendingString:nLetterValue];
}
// }
return str;
}
//这个方法里面有获取实时返回的数据,并设置每一个池塘的模型中各项指标的数据
- (NSInteger)getReceiveEndDataNum:(char *)dataBuf BufNum:(NSInteger)bufNum
StartNum:(NSInteger)startNum
{NSLog(@"标记4");
/**
*startNum-----0
*bufNum------返回的数据长度
*dataBuf------返回的数据字符串
*
*/
if (startNum +22 >= bufNum) {
return -1;
}
NSInteger dataNum = ((dataBuf[startNum +21] &
0xff) <<8) + (dataBuf[startNum +22] &
0xff);
NSLog(@"dataNum-----------%zd",dataNum);
////////////////////////
NSString *str=@"";
if((int)bufNum>=71){
for(int i=0;i<(int)bufNum;i++){
// NSLog(@"dataBuff-01-**%@----%zd",[NSString stringWithFormat:@"%d",i], dataBuf[i] & 0xff);
// NSString *cs01=[NSString stringWithFormat:@"%c",dataBuf[i] & 0xff];
NSString *tenToHex=[selfToHex:dataBuf[i]&
0xff];//10进制的转换成16进制
NSLog(@"dataBuff-01-**%@----%@",[NSStringstringWithFormat:@"%d",i],tenToHex);
//拼接字符串
str=[str stringByAppendingString:tenToHex];
//电机的返回状态*////////////////
NSString *electricBackstatuteFirst=[[selfToHex:dataBuf[64]&0xff]
substringToIndex:1];
NSString *electricBackstatuteSecond=[[selfToHex:dataBuf[64]&0xff]
substringFromIndex:1];
NSString *electricBackstatuteThird=[[selfToHex:dataBuf[65]&0xff]
substringToIndex:1];
NSString *electricBackstatuteForth=[[selfToHex:dataBuf[65]&0xff]
substringFromIndex:1];
NSString *electricBackstatuteFifth=[[selfToHex:dataBuf[66]&0xff]
substringToIndex:1];
NSString *electricBackstatuteSixth=[[selfToHex:dataBuf[66]&0xff]
substringFromIndex:1];
NSString *electricBackstatuteSeventh=[[selfToHex:dataBuf[67]&0xff]
substringToIndex:1];
NSString *electricBackstatuteEighth=[[selfToHex:dataBuf[67]&0xff]
substringFromIndex:1];
NSMutableArray *electricBackStaArr=[[NSMutableArrayalloc]init];
[electricBackStaArr addObject:electricBackstatuteFirst];
[electricBackStaArr addObject:electricBackstatuteSecond];
[electricBackStaArr addObject:electricBackstatuteThird];
[electricBackStaArr addObject:electricBackstatuteForth];
[electricBackStaArr addObject:electricBackstatuteFifth];
[electricBackStaArr addObject:electricBackstatuteSixth];
[electricBackStaArr addObject:electricBackstatuteSeventh];
[electricBackStaArr addObject:electricBackstatuteEighth];
self.electricBackstateArr=electricBackStaArr;
//电机的返回状态*////////////////
}
}
NSLog(@"返回的数据-%tu条--%@",bufNum,str);
if (startNum +25 + dataNum >= bufNum) {
return -1;
}
if (dataBuf[startNum +25 + dataNum] !=
0x23) {
return -1;
}
char checkBuf1 = dataBuf[startNum +18] &
0xff;
char checkBuf2 = dataBuf[startNum +19] &
0xff;
if (checkBuf1 ==0x00 && checkBuf2 ==
0x03) {
//[18]-[19]如果是0x00,0x03表示是检测数据上报
NSLog(@"标记***!");
[selfgetRealTimeData:dataBuf
StartNum:startNum];//获取实时数据,并设置每个池塘的模型中的指标数据
}
else {
NSLog(@"标记****2!");
[selfcheckDeviceOnline:dataBufStartNum:startNum];//设置在线/离线状态
}
return startNum +25 + dataNum;
}
//获取实时数据,并设置每个池塘的模型中的指标数据
- (void)getRealTimeData:(char *)dataBuf StartNum:(NSInteger)startNum
{ NSLog(@"标记5");
LTPondInfoModal *pondInfoModal = [selfgetPondInfoWithDeviceFriID:dataBuf[startNum
+6] DeviceSecID:dataBuf[startNum +7]
DeviceThiID:dataBuf[startNum +8]
DeviceFouID:dataBuf[startNum +9]];//通过返回数据的第6.7.8.9的位置字符来判断并获取池塘模型
self.ltPondInfoModal=pondInfoModal;
NSInteger dataNum = (dataBuf[startNum +21] <<
8) + dataBuf[startNum +22];
NSInteger startDataNum =23 + startNum;
NSInteger num = dataNum /5;
for (NSInteger i =0; i < num; i++) {
NSInteger dataRealTimeType = dataBuf[startDataNum];
unsignedchar dataBuf1 = dataBuf[startDataNum +1];
unsignedchar dataBuf2 = dataBuf[startDataNum +2];
unsignedchar dataBuf3 = dataBuf[startDataNum +2];
unsignedchar dataBuf4 = dataBuf[startDataNum +3];
int dataNum = ((dataBuf1 &0xff) <<
24) + ((dataBuf2 &0xff) <<
16) + ((dataBuf3 &0xff) <<
8) + (dataBuf4 &0xff);
float floatNum = *((float *)&dataNum);
if (dataRealTimeType ==1) {
pondInfoModal.doData = floatNum;
NSLog(@"-服务器-溶解氧1*******--%f",pondInfoModal.doData);
//溶氧警告设置
[selfgetDeviceWarningAerobics:pondInfoModalFloatNum:floatNum];
}
elseif (dataRealTimeType ==
2) {
pondInfoModal.dissolvedData = floatNum;
NSLog(@"--溶解氧饱和度1*******--%f",pondInfoModal.dissolvedData);
}
elseif (dataRealTimeType ==
3) {
pondInfoModal.phData = floatNum;
NSLog(@"-服务器-PH1*******--%f",pondInfoModal.phData);
}
elseif (dataRealTimeType ==
4) {
pondInfoModal.ammoniaData = floatNum;
}
elseif (dataRealTimeType ==
5) {
pondInfoModal.temperatureData = floatNum;
NSLog(@"-服务器-温度1******---%f",pondInfoModal.temperatureData);
}
elseif (dataRealTimeType ==
6) {
pondInfoModal.nitriteData = floatNum;
}
elseif (dataRealTimeType ==
7) {
pondInfoModal.levelData = floatNum;
}
elseif (dataRealTimeType ==
8) {
pondInfoModal.hydrogenSulfideData = floatNum;
}
elseif (dataRealTimeType ==
9) {
pondInfoModal.turbidityData = floatNum;
}
elseif (dataRealTimeType ==
10) {
pondInfoModal.salinityData = floatNum;
}
elseif (dataRealTimeType ==
11) {
pondInfoModal.conductivityData = floatNum;
}
elseif (dataRealTimeType ==
12) {
pondInfoModal.codData = floatNum;
}
elseif (dataRealTimeType ==
13) {
pondInfoModal.atmosphericPressureData = floatNum;
}
elseif (dataRealTimeType ==
14) {
pondInfoModal.windVelocityData = floatNum;
}
elseif (dataRealTimeType ==
15) {
pondInfoModal.windDirectionData = floatNum;
}
elseif (dataRealTimeType ==
16) {
pondInfoModal.chlorophyllData = floatNum;
}
elseif (dataRealTimeType ==
17) {
pondInfoModal.airTemperatureData = floatNum;
}
elseif (dataRealTimeType ==
18) {
pondInfoModal.atmosphericHumidityData = floatNum;
}
NSDateFormatter* formatter = [[NSDateFormatteralloc]init];
formatter.dateFormat =@"yyyy-MM-dd HH:mm:ss";
NSString *dateStr = [formatterstringFromDate:[NSDatedate]];
pondInfoModal.lastDateStr = dateStr;
startDataNum += 5;
if(pondInfoModal){//////////////
pondInfoModal.isOnline =@"在线";
pondInfoModal.electricBackStateArr=self.electricBackstateArr;
//延迟执行
dispatch_after(dispatch_time(DISPATCH_TIME_NOW,
(int64_t)(2.0 *NSEC_PER_SEC)),dispatch_get_main_queue(),
^{
//发送通知显示电机状态
[[NSNotificationCenterdefaultCenter]postNotificationName:@"feedBackState"object:niluserInfo:@{@"pondInfoModal":pondInfoModal}];
});
}else{
pondInfoModal.isOnline=@"离线";
}
}
}
//溶氧警告设置
- (void)getDeviceWarningAerobics:(LTPondInfoModal *)pondInfoModal FloatNum:(CGFloat)floatNum
{
//设置的塘口集合
LTSetAerobicsStatictics *setAerobics = [LTSetAerobicsStaticticsdefaultSetAerobicsStatictics];
NSMutableArray *setAerobicsList = setAerobics.setAerobicsList;
if(setAerobicsList.count!=0){
for(int i=0;i<[setAerobicsListcount];i++){
LTPondAerobicsInfo *pondAerobicsInfo = [setAerobicsListobjectAtIndex:i];//设置的一个塘口的数据
CGFloat upperAerobics = [pondAerobicsInfo.upperAerobicsfloatValue];
CGFloat lowerAerobics = [pondAerobicsInfo.lowerAerobicsfloatValue];
//如果pondAerobicsInfo.upperAerobics和lowerAerobics不为空,说明设置了溶氧警告,就把实时返回的溶氧值添加到警告的数组
if(![pondAerobicsInfo.upperAerobicsisEqualToString:@""]&&![pondAerobicsInfo.lowerAerobicsisEqualToString:@""]){
if ([pondAerobicsInfo.deviceIDisEqualToString:pondInfoModal.deviceID])
{
if (upperAerobics >0.0 && lowerAerobics >
0.0) {
if (floatNum > upperAerobics || floatNum < lowerAerobics) {
//设置返回的溶氧数据
[[LTAerobicsWarningStaticticsdefaultAerobicsWarningStatictics]addAerobicsWarningStatictics:floatNumDeviceID:pondInfoModal.deviceID LTSetAerobicsStaticticsArr:setAerobicsListnum:pondAerobicsInfo.pTag];
[selfplaceVoice];//溶氧警告
}
}// return;
}
}elseif([pondAerobicsInfo.upperAerobicsisEqualToString:@""]&&[pondAerobicsInfo.lowerAerobicsisEqualToString:@""]){
//如果pondAerobicsInfo.upperAerobics和lowerAerobics为空,说明没有设置溶氧警告。
}
}
}
}
//设置在线离线状态
- (void)checkDeviceOnline:(char *)dataBuf StartNum:(NSInteger)startNum
{
LTPondInfoModal *pondInfoModal = [selfgetPondInfoWithDeviceFriID:dataBuf[startNum
+6] DeviceSecID:dataBuf[startNum +7]
DeviceThiID:dataBuf[startNum +8]
DeviceFouID:dataBuf[startNum +9]];
if (pondInfoModal ==nil) {
return;
}
if ((dataBuf[startNum +18] ==
0) && (dataBuf[startNum +19] == -2)) {
// NSLog(@"%@
设备在线", pondInfoModal.deviceID);
pondInfoModal.isOnline =@"在线";
}
else
if ((dataBuf[startNum +
18] == 0) && (dataBuf[startNum +19] == -3))
{
// NSLog(@"%@
设备离线", pondInfoModal.deviceID);
pondInfoModal.isOnline =@"离线";///////////////////////
}
}
//判断并获取池塘模型
- (LTPondInfoModal *)getPondInfoWithDeviceFriID:(char)deviceFriID DeviceSecID:(char)deviceSecID
DeviceThiID:(char)deviceThiID DeviceFouID:(char)deviceFouID
{
NSMutableArray *deviceInfoList = [LTUserInfodefaultUserInfo].deviceInfoList;
for (NSInteger i =0; i < [deviceInfoList
count]; i++) {
LTDeviceInfoModal *deviceInfo = [deviceInfoListobjectAtIndex:i];
for (NSInteger j =0; j < [deviceInfo.pondListcount];
j++) {
LTPondInfoModal *pondInfoModal = [deviceInfo.pondListobjectAtIndex:j];
if ((deviceFriID == pondInfoModal.deviceFriID) && (deviceSecID == pondInfoModal.deviceSecID)
&& (deviceThiID == pondInfoModal.deviceThiID) && (deviceFouID == pondInfoModal.deviceFouID)) {
return pondInfoModal;
}
}
}
returnnil;
}
#pragma mark - 科大讯飞的语音系统
#pragma mark - 播放警报
- (void)placeVoice
{
NSLog(@"溶氧警告");
}
- (void)onStart
{
}
- (CGFloat)hexChangeFloat:(int)dataNum
{
CGFloat floatNum = *((CGFloat *)&dataNum);
return floatNum;
}
- (int)floatChangeFloat:(float)dataNum
{
int intNum = *((int *)&dataNum);
return intNum;
}
- (void)getRealTimeData1:(char *)dataBuf BufNum:(NSInteger)bufNum
{
if (bufNum <40) {
return;
}
// NSLog(@"getRealTimeData");
LTPondInfoModal *pondInfoModal =nil;
NSMutableArray *deviceInfoList = [LTUserInfodefaultUserInfo].deviceInfoList;
for (NSInteger i =0; i < [deviceInfoList
count]; i++) {
LTDeviceInfoModal *deviceInfo = [deviceInfoListobjectAtIndex:i];
for (NSInteger j =0; j < [deviceInfo.pondListcount];
j++) {
LTPondInfoModal *tmpPondInfoModal = [deviceInfo.pondListobjectAtIndex:j];
if ((dataBuf[6] == tmpPondInfoModal.deviceFriID) && (dataBuf[7]
== tmpPondInfoModal.deviceSecID) && (dataBuf[8] == tmpPondInfoModal.deviceThiID) && (dataBuf[9]
== tmpPondInfoModal.deviceFouID)) {
pondInfoModal = tmpPondInfoModal;
// NSLog(@"我要 deviceid %@", pondInfoModal.deviceID);
break;
}
}
}
NSInteger dataNum = (dataBuf[21] <<8) + dataBuf[22];
NSInteger startNum =23;
NSInteger num = dataNum /5;
for (NSInteger i =0; i < num; i++) {
NSInteger dataRealTimeType = dataBuf[startNum];
unsignedchar dataBuf1 = dataBuf[startNum +1];
unsignedchar dataBuf2 = dataBuf[startNum +2];
unsignedchar dataBuf3 = dataBuf[startNum +2];
unsignedchar dataBuf4 = dataBuf[startNum +3];
NSInteger dataNum = ((dataBuf1 &0xff) <<
24) + ((dataBuf2 &0xff) <<
16) + ((dataBuf3 &0xff) <<
8) + (dataBuf4 &0xff);
CGFloat floatNum = *((CGFloat *)&dataNum);
if (dataRealTimeType ==1) {
pondInfoModal.doData = floatNum;
}
elseif (dataRealTimeType ==
2) {
pondInfoModal.dissolvedData = floatNum;
}
elseif (dataRealTimeType ==
3) {
pondInfoModal.phData = floatNum;
}
elseif (dataRealTimeType ==
4) {
pondInfoModal.ammoniaData = floatNum;
}
elseif (dataRealTimeType ==
5) {
pondInfoModal.temperatureData = floatNum;
}
elseif (dataRealTimeType ==
6) {
pondInfoModal.nitriteData = floatNum;
}
elseif (dataRealTimeType ==
7) {
pondInfoModal.levelData = floatNum;
}
elseif (dataRealTimeType ==
8) {
pondInfoModal.hydrogenSulfideData = floatNum;
}
elseif (dataRealTimeType ==
9) {
pondInfoModal.turbidityData = floatNum;
}
elseif (dataRealTimeType ==
10) {
pondInfoModal.salinityData = floatNum;
}
elseif (dataRealTimeType ==
11) {
pondInfoModal.conductivityData = floatNum;
}
elseif (dataRealTimeType ==
12) {
pondInfoModal.codData = floatNum;
}
elseif (dataRealTimeType ==
13) {
pondInfoModal.atmosphericPressureData = floatNum;
}
elseif (dataRealTimeType ==
14) {
pondInfoModal.windVelocityData = floatNum;
}
elseif (dataRealTimeType ==
15) {
pondInfoModal.windDirectionData = floatNum;
}
elseif (dataRealTimeType ==
16) {
pondInfoModal.chlorophyllData = floatNum;
}
elseif (dataRealTimeType ==
17) {
pondInfoModal.airTemperatureData = floatNum;
}
elseif (dataRealTimeType ==
18) {
pondInfoModal.atmosphericHumidityData = floatNum;
}
startNum += 5;
}
[selfperformSelectorOnMainThread:@selector(getReceivePondDataForMainWithpondInfoModel:)withObject:nilwaitUntilDone:NO];
}
- (BOOL)isRealTimeData:(char *)dataBuf
{
char data1 = dataBuf[10];
char data2 = dataBuf[11];
char data3 = dataBuf[12];
char data4 = dataBuf[13];
char data5 = dataBuf[14];
char data6 = dataBuf[15];
char data7 = dataBuf[16];
char data8 = dataBuf[17];
if ((data1 ==18) && (data2 ==
120) && (data3 == -96) && (data4 == -100) && (data5 ==0)
&& (data6 == 0) && (data7 ==0) && (data8 ==
0)) {
returnYES;
}
returnNO;
}
@end
相关文章推荐
- iOS域名转解析为IP
- IOS转换和解析JSON数据
- iOS项目之解析HTML数据
- iOS狂暴之路---iOS中应用的数据存储方式解析
- iOS 把域名解析成IP
- iOS狂暴之路---iOS中应用的数据存储方式解析
- Megaupload 打不开解决办法(100% ok)域名和ip转换解析网站
- iOS狂暴之路---iOS中应用的数据存储方式解析
- Tomcat启动时默认打开你自己的web应用,输入域名或者IP可以直接访问项目不需要再后面加上项目名
- 1.云翼计划 大学生成长计划,学生云服务器低至9.9元 2.爆款云服务器30元/1月 3.RDS 40.8元/1月 RDS管理数据 4.阿里云DDOS高仿IP 云盾高仿IP 5.云解析然域名解析更安全
- iOS狂暴之路---iOS中应用的数据存储方式解析
- 接受第三方接口返回的json数据,解析转换成Javabean
- 手机应用在开发即时通讯项目功能时,不要使用基于socket.io的数据推送
- 服务器放在不同省份的IDC机房,数据如何同步?一个域名如何动态解析到不同IP的服务器
- 数据仓库项目中的IP转换成地区
- iOS swift项目IM实现,从长连接到数据流解析分析之Socket
- 根据域名查IP (DNS解析)
- python中socket接受数据的三种方法
- 域名/IP反解析
- 7.4 数据类型检查与转换应用实例