zoukankan      html  css  js  c++  java
  • 【iOS与EV3混合机器人编程系列之四】iOS_WiFi_EV3_Library 剖析之中的一个:WiFi UDP和TCP

    在上一篇文章中。我们通过编写EV3 Port Viewer项目实现了iOS监測EV3的实时端口数据。

    程序最核心的部分就是我们的开源码库iOS_WiFi_EV3_Library。

    那么,在本文中,我们将具体介绍我们这个库的编写。为了完毕这个库,本人參考了网上许多资料,主要包括EV3的源码,win版本号的代码库以及Monobrick相关以及网上的各种资料,在此就不一一列举了。

    因为水平有限,本代码库还存在各种问题,望使用的读者见谅。

    大家也能够在这个基础之上自己进行改造完好。


    为了具体说明代码库的实现。这里我们从需求分析,设计到实现介绍整个库从无到有的过程。

    ==需求分析:代码库要实现的功能==
    从我们的第一篇文章中。我们已经对iOS和EV3的结合方式做了具体的介绍。

    从中,我们能够总结出。我们要编写的代码库须要实现下面功能:

    1)拥有一个连接界面来搜索并连接WiFi局域网内的EV3设备。
    2)实时接收EV3的端口数据而且能很方便地对数据进行处理。

    3)能够发送直接命令(Direct Command)到EV3实现对EV3的实时控制。

    (EV3的源码中内置两种命令格式:命令Command和直接命令Direct Comand,使用直接命令则EV3能够直接响应。无需在EV3上进行不论什么的编程,大家能够參考我之前写的Hacking EV3系列文章,那些文章主要讲通过使用开源库btstack来实现用蓝牙来连接EV3。因为要使用btstack须要对iOS设备进行越狱,因此最后选择弃用而使用WiFi。这也是本项目的重要工作之中的一个)


    简单一点说就是要实现EV3的wifi连接,发送和接收功能。仅仅要实现了这三个核心功能,那么我们就能够用iOS来控制EV3。

    ==WiFi连接的方法==
    假设是iOS设备之间的无线数据通信,我们能够直接使用iOS的高级框架MultiConnectivity.Framework来实现。可是如今我们要通过iOS来连接一个非iOS设备,我们就仅仅能使用iOS底层的API了。

    根本就方式就是使用UDP和TCP来进行数据通信。

    这部分功能相应的API为CFNetwork。这是一个比較底层的C代码的框架。

    我们能够选择直接使用CFNetwork来编写,但这势必会很复杂和困难。还好。我们还有第二种选择,那就是使用网上的开源库CocoaAsyncSocket。这个开源库使用iOS的GCD在Objective C的层次又一次封装了UDP和TCP传输的功能。使得编写UDP和TCP传输的应用变得很方便。

    因此,我们就採用了CocoaAsyncSocket来实现UDP和TCP的传输。


    ==CocoaAsyncSocket的使用==

    大家能够从网上下载这个开源库:https://github.com/robbiehanson/CocoaAsyncSocket

    我们仅仅须要使用库中的四个文件:
    GCDAsyncSocket.h         // 实现TCP传输
    GCDAsyncSocket.m
    GCDAsyncUdpSocket.h // 实现UDP传输
    GCDAsyncUdpSocket.m

    1.UDP的使用
    Step 1:创建实例instance
    UDP的使用通过GCDAsyncUdpSocket这个类来实现。

    因此要使用UDP,我们首先得创建一个GCDAsyncUdpSocket类的实例。

    比方这里我们创建一个实例命名为udpSocket:

    dispatch_queue_t udpSocketQueue = dispatch_queue_create("com.manmanlai.updSocketQueue", DISPATCH_QUEUE_CONCURRENT);
            
            self.udpSocket = [[GCDAsyncUdpSocket alloc] initWithDelegate:self delegateQueue:udpSocketQueue];

    说明一下这个类包括delegate方法(依靠delegate方法来接收处理数据)以及须要定义一个特定的并行Queue来使用。
    Step 2:连接UDP到特定端口
    这里我们使用这个类中的方法:
    1)连接API:bindToPort:error:
    2)接收数据API:beginReceiving:
    3)关闭API:close
    因此,依据这个API我们能够编写一个Method来開始UDP和停止UDP

    - (void)startUdpSocket
    {
        NSError *error = nil;
        
        if (![self.udpSocket bindToPort:UDP_PORT error:&error])
        {
            NSLog(@"Error starting server (bind): %@", error);
            return;
        }
        if (![self.udpSocket beginReceiving:&error])
        {
            [self.udpSocket close];
            
            NSLog(@"Error starting server (recv): %@", error);
            return;
        }
        
        NSLog(@"Udp Echo server started on port %hu", [self.udpSocket localPort]);
    }



    - (void)stopUdpSocket
    {
        [self.udpSocket close];
    }

    Step 3:接收UDP数据
    通过delegate方法

    - (void)udpSocket:(GCDAsyncUdpSocket *)sock didReceiveData:(NSData *)data
          fromAddress:(NSData *)address
    withFilterContext:(id)filterContext

    接收数据
    具体数据怎样处理之后再谈。

    Step 4:发送UDP数据
    - (void)sendData:(NSData *)data toAddress:(NSData *)remoteAddr withTimeout:(NSTimeInterval)timeout tag:(long)tag

    以上是UDP的使用,接下来介绍TCP的使用

    2、TCP的使用
    Step 1:创建实例instance

    和UDP的创建方式一样。仅仅只是改成GCDAsyncSocket类。
    dispatch_queue_t tcpSocketQueue = dispatch_queue_create("com.manmanlai.tcpSocketQueue", DISPATCH_QUEUE_CONCURRENT);
                GCDAsyncSocket *tcpSocket = [[GCDAsyncSocket alloc] initWithDelegate:self delegateQueue:tcpSocketQueue];

    Step 2:连接TCP

    连接TCP的API例如以下:
    -(BOOL)connectToHost:(NSString*)host onPort:(uint16_t)port error:(NSError **)errPtr

    在使用中,例如以下所看到的:
    NSError *error = nil;
        if (![tcpSocket connectToHost:device.address
                                    onPort:5555
                                     error:&error])
        {
            NSLog(@"Error connecting: %@", error);
            
        } else {
            NSLog(@“Connected");
    }

    Step 3:发送TCP数据
    -(void)writeData:(NSData *)data withTimeout:(NSTimeInterval)timeout tag:(long)tag

    Step 4:接收数据
    - (void)readDataWithTimeout:(NSTimeInterval)timeout tag:(long)tag

    Step 5:数据处理
    通过Delegate方法实现,包括下面几个:
    // TCP socket已连接
    (void)socket:(GCDAsyncSocket *)sock didConnectToHost:(NSString *)host port:(UInt16)port
    // TCP socket已断开
    (void)socketDidDisconnect:(GCDAsyncSocket *)sock withError:(NSError *)err
    // TCP socket已写入数据
    (void)socket:(GCDAsyncSocket *)sock didWriteDataWithTag:(long)tag
    // TCP socket已发送数据
    - (void)socket:(GCDAsyncSocket *)sock didReadData:(NSData *)data withTag:(long)tag

    以上便是UDP和TCP的用法,能够看到是很的简单明了的。

    下一篇文章中。我们将介绍怎样使用CocoaAsyncSocket来具体连接我们的EV3机器人,敬请期待!

    【本文为原创文章。版权全部,转载请注明出处。谢谢!songrotek@qq.com





  • 相关阅读:
    为蓝桥杯准备
    Java里子类调用父类构造方法问题
    boost库的Singleton的实现以及static成员的初始化问题
    VS2005调试小记
    <转载>程序员每天该做的事
    vs2005, 2008 使用了未初始化的msg变量
    转载 vs2005 快捷键大全
    VS2005右键点击转到定义后出现“未定义符号”的提示及其解决
    软件工程配置规范(VC2005) 第二版(转载)
    匆忙赶路的时候别忘了适时停下来回头看看
  • 原文地址:https://www.cnblogs.com/liguangsunls/p/7289256.html
Copyright © 2011-2022 走看看