您的位置:首页 > 移动开发 > IOS开发

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 )

#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
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: