一. Socket 基础知识
-
Socket 的位置
首先上一张图, 让你知道 Socket 的位置。
什么是 Socket?
Socket 又称"套接字",是系统提供的用于网络通信的方法。 它的本质并不是协议, 而是一个调用接口(API)。 通过 Socket , 我们才能使用 TCP/IP 协议。
Socket描述了一个IP、PORT对。 它简化了程序员的操作, 知道对方的IP以及PORT就可以给对方发送消息, 再由服务器端来处理发送的这些消息。 所以,Socket一定包含了通信的双方, 即客户端(Client)与服务端(server)。
套接字(socket)是网络通信过程中端点的抽象表示,包含进行网络通信必须的五种信息:连接使用的协议,本地主机的IP地址,本地进程的协议端口,远地主机的IP地址,远地进程的协议端口。为什么设计 Socket ?
应用层通过传输层进行数据通信时,TCP会遇到同时为多个应用程序进程提供并发服务的问题。多个TCP连接或多个应用程序进程可能需要通过同一个 TCP协议端口传输数据。为了区别不同的应用程序进程和连接,许多计算机操作系统为应用程序与TCP/IP协议交互提供了套接字(Socket)接口。应用层可以和传输层通过Socket接口,区分来自不同应用程序进程或网络连接的通信,实现数据传输的并发服务。-
如何进行 Socket 连接?
建立Socket连接至少需要一对套接字,其中一个运行于客户端,称为ClientSocket; 另一个运行于服务器端,称为ServerSocket。
套接字之间的连接过程分为三个步骤:- 服务器监听:服务器端套接字并不定位具体的客户端套接字,而是处于等待连接的状态,实时监控网络状态,等待客户端的连接请求
- 客户端请求:客户端的套接字提出连接请求,要连接到目标服务器端的套接字。为此,客户端的套接字必须首先描述它要连接的服务器的套接字,指出服务器端套接字的地址和端口号,然后就向服务器端套接字提出连接请求
- 连接确认:当服务器端的套接字监听到或者说接收到客户端的套接字的连接请求时,就响应客户端套接字的请求,建立一个新的线程,把服务器端套接字的描述发给客户端,一旦客户端确认了此描述,双方就正式建立连接。而服务器端套接字继续处于监听状态,继续接收其他客户端套接字的连接请求
-
Socket 支持的传输层协议
Socket可以支持不同的传输层协议(TCP或UDP),当使用TCP协议进行连接时,该Socket连接就是一个TCP连接,UDP连接同理。-
TCP客户端-服务器端设计框架
- UDP客户端-服务器端设计框架
-
二. iOS Socket
基本了解
首先, 要实现 Socket , 可以用 TCP, 也可以用 UDP ,根据功能来选择。 在 iOS 中,可以使用 C 语言编写, 也可以用 OC 编写。 在篇尾有相关资料可供参考。
总的来说, 自己实现的话, 会很麻烦。 如果有志于此的同学, 可以自己实现一遍; 如果只是工作中用到, 可以选用第三方库。
第三方库中比较好的是 CocoaAsyncSocket。 下面对它进行一下简单介绍。-
CocoaAsyncSocket介绍
官方推荐使用基于GCD 的GCDAsyncSocket 代替基于 NSRunLoop 的AsyncSocket;以下笔记默认是使用的GCDAsyncSocket.
-
初始化GCDAsyncSocket
- GCDAsyncSocket虽然基于 GCD ,但是使用了标准的代理模式,但是需要设置好线程来执行所有的代理回调。
- 支持高并发,同时线程安全。
- 使用时必须设置 delegate 和 delegate 的线程。
- socket 的线程是可选的;可以为空,那样 GCDAsyncSocket 会自动创建一个专属于它的线程;如果你选择提供一个 socket 队列,那么这个队列一定不能是并发队列。
- delegate 的线程和socket 的线程可以一样。
连接(Connecting)
这是连接 Socket 的方法之一。 如果interface不指定的话,就是默认的 interface ;如果 timeout 不指定的话,默认是0.
- (BOOL)connectToHost:(NSString *)host
onPort:(uint16_t)port
viaInterface:(NSString *)interface
withTimeout:(NSTimeInterval)timeout
error:(NSError **)errPtr;断开连接(Disconnecting)
- (void)disconnect;
- (void)disconnectAfterReading;
- (void)disconnectAfterWriting;
- (void)disconnectAfterReadingAndWriting;
如果你在断开连接后不再连接,推荐调用下列方法:
[asyncSocket setDelegate:nil];
[asyncSocket disconnect];
[asyncSocket release];
如果你想在断开连接后续连,推荐这样调用:
[asyncSocket setDelegate:nil];
[asyncSocket disconnect];
[asyncSocket setDelegate:self];
[asyncSocket connect...];-
诊断状态(Diagnostics)
@property (atomic, readonly) BOOL isDisconnected;
@property (atomic, readonly) BOOL isConnected;@property (atomic, readonly) NSString *connectedHost; @property (atomic, readonly) uint16_t connectedPort; @property (atomic, readonly) NSURL *connectedUrl; @property (atomic, readonly) NSString *localHost; @property (atomic, readonly) uint16_t localPort; @property (atomic, readonly) NSData *connectedAddress; @property (atomic, readonly) NSData *localAddress; @property (atomic, readonly) BOOL isIPv4; @property (atomic, readonly) BOOL isIPv6; @property (atomic, readonly) BOOL isSecure;
读(Reading)
-
写(Writing)
- (void)writeData:(NSData *)data withTimeout:(NSTimeInterval)timeout tag:(long)tag;- (float)progressOfWriteReturningTag:(long *)tagPtr bytesDone:(NSUInteger *)donePtr total:(NSUInteger *)totalPtr;
-
GCDAsyncSocketDelegate
- 连接成功后的回调
- (void)socket:(GCDAsyncSocket *)sock didConnectToHost:(NSString *)host port:(uint16_t)port; - 断开连接后的回调
- (void)socketDidDisconnect:(GCDAsyncSocket *)sock withError:(NSError *)err;
- 连接成功后的回调
三. 参考资料
见链接。