Socket之iOS项目中的socket应用/IPV6 转换/域名转IP/解析socket接受的数据/心跳包

来源:互联网 发布:淘宝优惠券推广软件 编辑:程序博客网 时间:2024/05/17 03:24

使用系统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()用来将参数sockfdsocket连至参数serv_addr指定的网络地址.结构sockaddr请参考bind().参数addrlensockaddr的结构长度.

        //

        //        返回值:成功则返回0,失败返回-1,错误原因存于errno.

        //

        //        错误代码:

        //        1EBADF参数sockfd非合法socket处理代码

        //        2EFAULT参数serv_addr指针指向无法存取的内存空间

        //        3ENOTSOCK参数sockfd为一文件描述词,socket.

        //        4EISCONN参数sockfdsocket已是连线状态

        //        5   ETIMEDOUT企图连线的操作超过限定时间仍未有响应.

        //        6ENETUNREACH无法传送数据包至指定的主机.

        //        7EAFNOSUPPORT sockaddr结构的sa_family不正确.

        //        8EALREADY 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

     100主动上报,接收端此字节用0x80应答。

     201查询参数,接收端此字节用0x81应答。

     302设置参数,接收端此字节用0x82应答。

     403命令执行,接收端此字节用0x83应答。

     504命令关闭,接收端此字节用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(callocrealloc)函数给指针变量分配的内存空间的函数

    

}


//发送一台机器所有电机(增氧,投饵,滴灌,风机,排污)开关的消息


- (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:isOpenPondDeviceId: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:isOpenPondDeviceId: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:isOpenPondDeviceId:0x07];

                [selfsendCtrSingleDeviceWithDeviceID:deviceIDIsOpen:isOpenPondDeviceId: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 < [deviceIDscount]; 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 , HASCII16进制是0x48),SASCII16进制是0x53

    dataList[1] =0x48;

    dataList[2] =0x53;

    //版本号,终端版本号(1字节),数据:1-255

    dataList[3] =0x03;

    //设备类型(2字节),见表设备类型分类,数据:0001-FFFF

    dataList[4] =0x00;

    dataList[5] =0xfe;///////////这个和水产协议规范的不一样,水产协议是从01234.......

}


//设备地址(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;//十进制的10620xff位与运算再又移8位,得到结果0x4

    dataList[checkDataNum + 1] = sum &0x00ff;//10进制的10620xff位与运算,得到0x26

}


//帧尾,数据:#(ASCII16进制是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:bufNumStartNum: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:dataBufStartNum: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.upperAerobicslowerAerobics不为空,说明设置了溶氧警告,就把实时返回的溶氧值添加到警告的数组

            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.upperAerobicslowerAerobics为空,说明没有设置溶氧警告。

                

            }

        }

    }

}


//设置在线离线状态

- (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 < [deviceInfoListcount]; 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 < [deviceInfoListcount]; 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



0 0