Socket 开发看这一篇就够了

之所以有这篇文章是因为,毕设啊毕设。怼了大半个月。恶补了计算机网络相关的知识和相关的内容,现在已经过去快一个月了,再不记下来的话,估计就真的会忘记。况且 Blog 已经那么久不更新了,心思全在玩上了┑( ̄Д  ̄)┍。

Don’t BB show me the Code.So here is the url of code

Socket 究竟是个什么东西

Socket 俗称 套接字。嗯。套接字。Socket 是对 TCP/IP 协议族的一种封装,是应用层与TCP/IP协议族通信的中间软件抽象层。

画外音:你特么倒是说人话啊!!(╯‵□′)╯︵┻━

如果你想简单的理解点:那么我告诉你实际上就像你喝特仑苏的时候(喂喂喂,特仑苏记得给广告费啊),我们都需要用习惯在牛奶瓶上面戳个洞。如果我们把牛奶比作我们的电脑,那么被戳破的洞就是端口 (Port) ,透明的管子就可以作为 Socket,而白色的管子,也就是我们伸到嘴里面的就是对外的数据传输链路了。(怎么突然间就污了起来,司机,我要下车!!!

如果你想要更加深入的理解。那么你需要了解 OSI 七层协议和 TCP/IP 五层网络架构。你说你不懂?大丈夫。丢你一份计算机网络的基础知识只要你搜关键字就可以快速定位到你想要的知识点了。

既然你已经知道了这两个点,那我们就可以愉快的交流了。实际上 Socket 可以理解为在 TCP/IP 之上,在应用层以下,处于两者之间。位于会话层(OSI 的 Session 层),你可以在 Socket 上面实现你想要实现的自定义协议。同时因为这东西介于应用层和传输层之间,用户可以使用这一层进行数据的中转,从而方便对于数据的二次处理。

既然能中转数据,那就很有用了。你可以根据你自己的需求完成数据的各种添加和删除,或者某些协议的实现了。

画外音:那这么厉害的东西要怎么使用呢?

Socket使用

因为 Socket 这个概念始于 Linux,所以很多语言都可以实现。(强行扯到 Linux)

但是无论用什么语言进行处理,但是他的实现方式都是一样的。一般各种语言中的Socket 都会提供下面几个 API:

  • socket() 创建套接字
  • bind() 分配套接字地址
  • listen() 等待连接请求
  • accept() 允许连接请求
  • read()/write() 数据交换
  • close() 关闭连接

首先我们在我们本地使用 socket() 创建一个套接字,然后用 bind() 将它绑定到对应的端口。然后将 listen() 接口开始监听对应的端口,然后我们调用accept()函数进行接收。然后调用 read() 读取远端的数据。然后再调用 write() 来进行数据的写入。最后等到所有的内容结束后再次调用 close()关闭对应的 socket。调用顺序去如下:

link

当然,因为 Socket 是最底层的,作为一个 iOS 开发,苹果提供给我们的接口都是使用 C 的 API,这对于快速编码很不友好。所以 CocoaAsyncSocket 应运而生。我们可以通过这个三方库快速产出一个我们想要的 App。

SOCKS 5 的实现 —— Socket 的具体实现

为了更有目的性的实现 SOCKS 5 协议的App。所以 Demo 中我们就通过使用 CocoaAsyncSocket 来完成一个简单的代理软件。

关于如何使用 CocoaAsyncSocket 这个三方库,可以直接看他的源码,他通过 delegate,对所有 Socket 接收信息的情况进行回调。方便使用方进行调用,而且他的命名方式十分清楚,所以基本上一看就知道什么时候调用。

什么是SOCKS 5协议

SOCKS 5 可能大家会有点陌生,但是既然你们能看到这篇文章,那么 SS 应该是不陌生的。我们就从 SS 来描述。SS 是 基于 SOCKS 5 协议,再在上面进行一层封装而形成的一个协议。你可以把 SS 理解为 Socks 5 的一个进化版。那么 SOCKS 5 能做什么我想大家心里也有数了。



那么这个东西具体是怎么实现的呢?

协议既然称作为协议,那么也就是两端约定俗称的一个东西。就像你说中文,我也说中文。这样我们默认交流的时候,我们俩都说中文,我们彼此都能明白彼此想表达啥事情。不仅仅是 SOCKS 协议,包括 TCP/IP 协议,HTTP 协议……而在网路协议中,每一层我们都可以看成通过数据流(也就是字节码)进行描述。

那么具体要怎么描述 Socks 5 呢?根据 RFC 1928 规范我们可以了解到。

对于 TCP 协议的请求如下:

  1. 尝试与服务器的 1080 接口进行tcp连接。
  2. 向服务器发送 05 00 01。(第一位为 SOCKS 版本号,第二位为认证方式,第三位代表第二位的长度)
  3. 服务端接收了客户端的请求,然后对请求进行解析,根据第三位查看第二位是否被支持,如果支持,那么返回 05 00,第一位为 SOCKS 版本,第二位为接下去接收认证的方式。
  4. 如果第二位为0 ,那么直接开始进行请求。否则进行身份验证。
  5. 由于身份验证方式有多重,在此不再赘述。
  6. 当完成了验证之后,客户端发送一个需要请求的目标地址的报头,报头包含了版本号连接方式(是Connect还是Bind)请求地址类型(ipv4 还是 ipv6 还是域名的形式)``请求的地址(根据类型决定),请求的端口
  7. 当服务器获得了之后,尝试对目的服务器进行请求,请求结束返回对应的请求报文。报文包含了请求头请求情况(是否成功链接)绑定的服务器和端口(如果前面是需要进行绑定的情况)
  8. 如果连接成功就可以进行数据的传输。剩下的和协议就没有关系了。

对于 UDP 协议的请求与 TCP 相似就是在完成发送验证之后,在发送目标地址的请求过程中,连接方式UDP,然后开 UDP 独有的设置:

  1. 同时在服务器端接收到 UDP 请求。
    • 如果不行,那么不进行任何操作。
    • 如果可行,那么在服务器新开一个接口,然后在回复的报文中带上创建的端口号。
  2. 根据客户端发过来的请求,根据请求地址整合出一个请求列表,从而方便将从远端收到的内容返回给对应的服务器。
  3. 请求里面一般为 00 00 00 01 70 5F F0 3C 1F 40 +实体数据。00 00 00 01(表示地址类型) 之后的为IP地址 + 端口号。00 00 00 03(表示域名地址)