在上一篇文章中。我们通过编写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

【iOS与EV3混合机器人编程系列之四】iOS_WiFi_EV3_Library 剖析之中的一个:WiFi UDP和TCP的更多相关文章

  1. 【iOS与EV3混合机器人编程系列之三】编写EV3 Port Viewer 应用监測EV3port数据

    在前两篇文章中,我们对iOS与EV3混合机器人编程做了一个主要的设想.而且介绍了要完毕项目所需的软硬件准备和知识准备. 那么在今天这一篇文章中,我们将直接真正開始项目实践. ==第一个项目: EV3 ...

  2. 【iOS与EV3混合机器人编程系列之中的一个】iOS要干嘛?EV3能够更酷!

    乐高Mindstorm EV3智能机器人(下面简称EV3)自从在2013年的CES(Consumer Electronics Show美国消费电子展)上展出之后,就吸引了全球广大机器人爱好者的眼球!E ...

  3. 【iOS与EV3混合机器人编程一系列五个】iOS_WiFi_EV3_Library 解剖连接EV3

    在上一篇文章中.我们解说了怎样用开源码库CocoaAsyncSocket来实现iOS上的UDP和TCP数据通信.那么在本文中.我们将介绍在CocoaAsyncSocket的基础怎样使用UDP和TCP连 ...

  4. .NET 4 并行(多核)编程系列之四 Task的休眠

    原文:.NET 4 并行(多核)编程系列之四 Task的休眠 .NET 4 并行(多核)编程系列之四 Task的休眠 前言:之前的几篇文章断断续续的介绍了Task的一些功能:创建,取消.本篇介绍Tas ...

  5. TCP/IP网络编程系列之四(初级)

    TCP/IP网络编程系列之四-基于TCP的服务端/客户端 理解TCP和UDP 根据数据传输方式的不同,基于网络协议的套接字一般分为TCP和UDP套接字.因为TCP套接字是面向连接的,因此又称为基于流的 ...

  6. Python高级网络编程系列之终极篇---自己实现一个Web框架

    通过前面几个小节的学习,现在我们想要把之前学到的知识点给串联起来,实现一个很小型的Web框架.虽然很小,但是用到的知识点都是比较多的.如Socket编程,装饰器传参在实际项目中如何使用.通过这一节的学 ...

  7. python编程系列---多个装饰器装饰一个函数的执行流程

    首先看一个例子 ''' 多个装饰器装饰一个函数 ''' # 定义第一个装饰器 def set_func1(func): def wrapper1(*args,**kwargs): print('装饰内 ...

  8. .NET 4.0 任务和并行编程系列

    8天玩转并行开发 8天玩转并行开发——第一天 Parallel的使用 8天玩转并行开发——第二天 Task的使用 8天玩转并行开发——第三天 plinq的使用 8天玩转并行开发——第四天 同步机制(上 ...

  9. .NET 4 并行(多核)编程系列之一入门介绍

    .NET 4 并行(多核)编程系列之一入门介绍 本系列文章将会对.NET 4中的并行编程技术(也称之为多核编程技术)以及应用作全面的介绍. 本篇文章的议题如下:  1. 并行编程和多线程编程的区别.  ...

随机推荐

  1. 登录Tomcat控制台

    在http://localhost:8080界面中,右上角有三个按纽对应着三个控制台:Server Status控制台,Manager App控制台和Host Manager控制台.Server St ...

  2. windows Server2012 之 IIS8.0配置安装完整教程

    IIS8.0是windows Server2012自带的服务器管理系统,和以往不同,IIS8.0安装和操作都比较简单,界面很简洁,安装也很迅速.今天我们重点完整的演示下Internet Informa ...

  3. Redis 数据结构之简单动态字符串SDS

    几个概念1:key对象 数据库存储键值对的键,总是一个字符串对象.2:value对象 数据库存储键值对的值,可以是字符串对象,list对象,hash对象,set对象,sorted set对象.    ...

  4. iOS 调用音乐播放以及视频播放器

    音乐播放 NSString *path = [[NSBundle mainBundle] pathForResource:@"预谋" ofType:@"mp3" ...

  5. Vue 作用域插槽

    使用场景:复用子组件的slot,又可以使slot的内容不一样. <!DOCTYPE html> <html lang="zh"> <head> ...

  6. RS:推荐系统中的数据稀疏和冷启动问题

    如何在没有大量用户数据的情况下设计个性化推荐系统并且让用户对推荐结果满意从而愿意使用推荐系统,就是冷启动问题. 冷启动问题主要分为三类: (1) 用户冷启动:如何给新用户做个性化推荐的问题,新用户刚使 ...

  7. echart初体验 动态加载数据

    <!DOCTYPE html> <html> <head> <meta charset="utf-8" /> <title&g ...

  8. C++ opencv高速样例学习——读图显示

    1.关键函数 1. 读入图片 imread(图片或位置,显示格式)默觉得:IMREAD_COLOR 显示格式: IMREAD_UNCHANGED =-1    // 8bit, color or no ...

  9. django学习笔记【002】创建第一个django app

    2.3.3 1.创建一个名叫polls的app python3. manage.py startapp polls tree mysite/ mysite/ ├── db.sqlite3 ├── ma ...

  10. unity, 什么时候用静态类,什么时候用单例

    如果没有成员变量,或者成员变量都是常量,则用静态类. 如果有成员变量,则用单例.(以便让成员变量有初始化机会). //静态类 public class CmyFuncs{ public float m ...