<iOS 实践>关于在 iOS Socket 的一些记录(杂记)

首先需要了解 Socket 的一些基本知识, 然后看了一下官方的 API.

这次由于要构建一个调试工具, 先选用的是 robbiehanson/CocoaAsyncSocket 这个框架, 先对而言上手很快, 且使用简单.

要实现的需求是要在手机端搭建一个 Socket 接收端, 同时也需要发送数据.

但是第一个坎就没有过去, 当在手机上(iOS 11.2.2)实现服务端时, 无法接收外界传入的数据(使用 UDP 情况下, TCP 下亦然).

为了验证, 故切换为 TCP, 然后用 MAC 实现一个服务端, 手机连接进去一切正常, 情况如下:

把服务端放到 MAC 上, 完全相同的 Socket 服务端代码条件下, 指定了如下图的 APP 功能, 则可以正常连接(TCP):


image.png

这里是手机端的输出:

尝试连接
已连接到: 192.168.199.127:9002

这里是 MAC 电脑上的输出:

已启动监听
已监听到连接并建立连接.
newSocket's localHost: 192.168.199.127
newSocket's connectedHost: 192.168.199.116

如果上面的勾勾不打的话, 会提示绑定端口错误.

但是在 iOS 工程上, 真没有找到和这个勾勾类似的东西...

再去参考一下 swisspol/GCDWebServer, 为什么它可以让服务器在手机上运行起来呢, 而且可以指定端口? 证明并非是 IP 的关系. 所以这里就进入到它的源码里面去看看.

发现两个的实现原理都不一样, GCDWebServer 是基于 bonjour 的.

莫非是 iOS 直接就禁止了监听外界的 Socket 请求? 找了网上很久也没找到可以在 iOS 上构建 Socket 服务端到底可行否? 且完全没有找到任何地方有在 iOS 上建立 Socket 服务端的案例, 所以最好的办法还是从头开始仔细看看官方文档...

好吧, 网上有说用 multi peer connectivity framework 来实现的, 下面就来看看. 有时候一条路走不通, 就换种思路继续做呗...

先看了一下这篇文章, 里面说到它是Bonjour 的继承者, 然后看了一下内容, 貌似还是只有苹果平台可用...

文末提到 Websocket, 可用尝试一下...

但最终发现全部的例子中, 如果用 TCP 的情况下, 都是把手机作为客户端的. 如果用 UDP 的话手机和其他地方就是两个对等的点了.

故继续看官方文档, 先看 Networking Overview 启发一下思路, 然后是 Networking Programming Topics...

参考官文里面的一句:

There are only two APIs that provide the ability to listen for incoming network connections: the Core Foundation socket API and the POSIX (BSD) socket API. Higher-level APIs cannot be used for accepting incoming connections.

即目前只有两套 API 提供了监听网络连接请求的能力, 一套是 Core Foundation socket API, 另外一套是 POSIX 的 Socket API. 高层的 API 无法被用来 accepting 进入的连接.

use NSStream for remote connections and CFSocket for listening

使用 NSStream 来建立远程连接, 而用 CFSocket 来监听及 accepting 进入的连接.(详见上述Networking Programming Topics 中的 Do Not Use NSSocketPort (OS X) or NSFileHandle for General Socket Communication)

之前直接建立了一个可工作的客户端, 下面就来跟着官文建立一个可监听外界连接请求的服务端.

文档中需要的 <sys/socket.h> 在 swift 4 中默认就已经引入进去了的, 貌似 <netinet/in.h> 也是一样.

在 swift 官网上有一句说的是:

BSD sockets are a common pain point for Swift interoperability. Swift 3.0 exposes the difficultly in doing this correcly. Fortunately, Quinn “The Eskimo!” has provided these helpful wrappers.

下面提供了一个 Socket 扩展, 详见这个链接, 便于使用.

但为何两个 iPhone 之间的 Socket 通信这么蛋疼? 在苹果官方论坛找到了这样一个问答: iOS 10.2 socket issue, 这里说到了两个 iPhone 之间的 Socket 通信受阻并非是由系统造成的, 可能是由于 wifi 等外部原因造成的(比如本地的 wifi 阻止了 iOS 设备间的 STA TO STA 通信, STA 即 station, 它相当于 wifi 中的客户端设备), 在里面推荐了一篇关于入门文章Wi-Fi Fundamentals.

由于要彻底解决 wifi 导致的通信受阻问题, 就需要首先了解 wifi 中的一些东西, 根据上面的文章, 慢慢看.

术语表:

  • STA (station) : wifi 中的客户端设备
  • AP (access point): 指的是运行 Wi-Fi 网络的硬件设备. 关于这里定义的 Wifi 网络的详细信息在后面会讲.
  • SSID (Service Set Identifier): It’s the user-visible network identifier string that you see throughout the system.
  • BSSID (Basic Service Set Identifier): This defines a single Wi-Fi network at the Wi-Fi level. It’s identified by the MAC address of the AP, something that’s generally not user visible.

wifi 实现了如下两类广播:

  • Unicasts
  • Broadcasts(Multicasts)

不过最后最主要的还是在文章末尾提到一个检测 STA--->AP, AP--->STA 的包传输跟踪方法, 详见Getting a Packet Trace.

这里是一些 MAC 上可用的网络调试工具列表.

先把 iPhone 的整个网络栈映射到 MAC 上, 然后通过网络调试工具来查看通信内容:

The RVI represents the entire networking stack of the iOS device

具体操作:

  1. 用 USB 连接手机和 MAC 电脑.
  2. 为设备创建一个 RVI(remote virtual interface, 远程虚拟接口, iOS 5 以上版本才有) , 通过 RVI, 可以在 MAC 上使用抓包工具来追踪 iPhone 上的网络通信.
    # 使用如下命令可以查看当前所有的网络接口:
    ifconfig -l
    # 这个命令执行后显示如下
    lo0 gif0 stf0 en0 en1 p2p0 fw0 ppp0 utun0
    # 获取设备的 UUID(在 itunes 里就看得到), 然后用如下命令建立 RVI, 命令参数即UUID:
    rvictl -s 74bd53c647548234ddcef0ee3abee616005051ed
    # 此时再用 ifconfig -l 查看的话, 会发现多了一个网络接口, 多出来的 rvi0 就是新建的:
    ifconfig -l
    lo0 gif0 stf0 en0 en1 p2p0 fw0 ppp0 utun0 rvi0
    
  3. 有了上述的接口名称 rvi0, 就可以通过抓包工具对该接口进行抓包(下面只是演示):
    sudo tcpdump -i rvi0 -A
    
  4. 如果是想移除 RVI, 则执行如下命令:
    # 其中参数值是设备的 UUID
    rvictl -x 74bd53c647548234ddcef0ee3abee616005051ed
    

另外有一个 CPA 工具, 来分析看包到底到了手机端没有.

tcpdump 也是个好东西, 可以学学它的用法, 具体可以参考这篇官文.

下面的测试使用的是如下命令来执行的 tcpdump:

# ip 地址为想要监听的host, 从该 host 发送的包, 或发向该 host 的包都会被抓取.
sudo tcpdump host 192.168.199.116 -i rvi1

但在测试的时候有一个问题:
两台手机, 一台 iPhone6P, 一台 iPhone 6, 然后在 Xcode 中写了两个示例工程, 一个工程只是通过
UDP 协议利用 Socket 发送数据, 另外一个工程的作用是接收通过 UDP 协议发送的过来的数据.

  1. 当使用 6 来向 6P 发送数据, 无法发送.
  2. 当使用 6P 来向 6 发送数据, 一切正常.
  3. 使用 tcpdump 查看, 实际上每次发送的时候数据包都是过去了的(抓取接收方的包是接收到了的, 发送方也是发送了的).

数据包在两种情况下都是顺利被发送和接收到了的, 但为什么一个手机在上层无法接收, 另外一个可以接收呢?

苹果在 10.2 之后可能对网络功能进行了修改? 但两个手机的系统都是 11.2.2 , 为什么同样的发送和接收代码, 在两台 iPhone 上面还会有不同的反应?

上面遇到的问题就无法解答了, 望看到的朋友能够给予帮助, 万分感谢!

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 199,711评论 5 468
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 83,932评论 2 376
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 146,770评论 0 330
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 53,799评论 1 271
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 62,697评论 5 359
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,069评论 1 276
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 37,535评论 3 390
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,200评论 0 254
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 40,353评论 1 294
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,290评论 2 317
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,331评论 1 329
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,020评论 3 315
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 38,610评论 3 303
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,694评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 30,927评论 1 255
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 42,330评论 2 346
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 41,904评论 2 341