来自:http://disanji.net/2011/08/12/cocoaasyncsocket%E5%AD%A6%E4%B9%A0/

CocoaAsyncSocket支持tcp和udp。其中:

  • AsyncSocket类是支持TCP的
  • AsyncUdpSocket是支持UDP的

AsyncSocket是封装了CFSocket和CFSteam的TCP/IP socket网络库。它提供了异步操作,本地cocoa类的基于delegate的完整支持。主要有以下特性:

  • 队列的非阻塞的读和写,而且可选超时。你可以调用它读取和写入,它会当完成后告知你
  • 自动的socket接收。如果你调用它接收连接,它将为每个连接启动新的实例,当然,也可以立即关闭这些连接
  • 委托(delegate)支持。错误、连接、接收、完整的读取、完整的写入、进度以及断开连接,都可以通过委托模式调用
  • 基于run loop的,而不是线程的。虽然可以在主线程或者工作线程中使用它,但你不需要这样做。它异步的调用委托方法,使用NSRunLoop。委托方法包括 socket的参数,可让你在多个实例中区分
  • 自包含在一个类中。你无需操作流或者socket,这个类帮你做了全部
  • 支持基于IPV4和IPV6的TCP流

AsyncUdpSocket是UDP/IP socket网络库,包装自CFSocket。它的工作很像TCP版本,只不过是用于处理UDP的。它包括基于非阻塞队列的发送接收操作,完整的委托支 持,基于runloop,自包含的类,以及支持IPV4和IPV6。

以下内容是根据官方网站参考:

http://code.google.com/p/cocoaasyncsocket/wiki/Reference_AsyncSocket

编写的示例。

准备工作:如何在iOS项目中使用

可按照官网链接执行:

http://code.google.com/p/cocoaasyncsocket/wiki/iPhone

基本上是两步:

  1. 将CocoaAsyncSocket项目中的.h和.m文件拖拽到自己项目的Classes目录中
  2. 添加framework:CFNetwork

编写简单的TCP连接

编写个简单的TCP连接应用。HTTP其实就是建立在TCP协议上的。这里就用向网站发起请求和获得响应来演示。

为了形象说明,先手工模拟一下HTTP。这需要用到telnet工具,这是个命令行工具,如果在命令行里敲:

C:\Users\Marshal Wu>telnet
‘telnet’ 不是内部或外部命令,也不是可运行的程序
或批处理文件。

说明你使用的是windows vista或者windows7,因为windows xp是默认安装该软件的。

我用的是Mac OSX,上面自带这个工具。如果你出现上面的问题,可参照vista下使用telnet的做法安装 telnet。

然后,可以使用这个工具发出socket信息,并接收socket返回信息。下面说一下步骤,如图:

下面用CocoaAsyncSocket来实现。

首先是要实现相关的delegate:

12345
#import <UIKit/UIKit.h>

#import "AsyncSocket.h"

@interface SocketDemosViewController : UIViewController<AsyncSocketDelegate>

然后,在实现代码中:

123456789
- (void)onSocket:(AsyncSocket *)sock didConnectToHost:(NSString *)host port:(UInt16)port{ NSLog(@"did connect to host");}

- (void)onSocket:(AsyncSocket *)sock didReadData:(NSData *)data withTag:(long)tag{ NSLog(@"did read data");NSString* message = [[[NSString alloc] initWithData:data encoding:NSUTF8StringEncoding] autorelease]; NSLog(@"message is: \n%@",message);}

AsyncSocketDelegate中的方法都是可选的。我实现了对建立连接后以及读取数据的监听。

这些监听需要创建和使用AsyncSocket实例时才能被用到。下面就是这部分代码:

12345678
- (void)viewDidLoad {[super viewDidLoad];

 AsyncSocket *socket=[[AsyncSocket alloc] initWithDelegate:self];[socket connectToHost:@"www.baidu.com" onPort:80 error:nil];

[socket readDataWithTimeout:3 tag:1];[socket writeData:[@"GET / HTTP/1.1\n\n" dataUsingEncoding:NSUTF8StringEncoding] withTimeout:3 tag:1];

我把这部分代码直接写到controller的viewDidLoad中了。

执行的日志如下:

12345678910111213
2011-07-19 17:17:46.545 SocketDemos[27120:207] did connect to host2011-07-19 17:17:46.620 SocketDemos[27120:207] did read data2011-07-19 17:17:46.621 SocketDemos[27120:207] message is:HTTP/1.1 200 OKDate: Tue, 19 Jul 2011 09:17:46 GMTServer: BWS/1.0Content-Length: 7691Content-Type: text/html;charset=gb2312Cache-Control: privateExpires: Tue, 19 Jul 2011 09:17:46 GMTSet-Cookie: BAIDUID=9389BA38262D7997D220A564154CCA87:FG=1; expires=Tue, 19-Jul-41 09:17:46 GMT; path=/; domain=.baidu.comP3P: CP=" OTI DSP COR IVA OUR IND COM "Connection: Keep-Alive

这里的HTTP响应被截断了,因为我们不是要编写真的接收HTTP响应的功能,因此这个缺陷可以忽略。

本来HTTP请求应该是由服务器端来关闭,比如使用telent访问看到的是这样的结尾:

因此,HTTP响应没有完全接收下来,服务器端未断掉连接。可以在客户端关闭连接,这样:

123
[socket readDataWithTimeout:3 tag:1];[socket writeData:[@"GET / HTTP/1.1\n\n" dataUsingEncoding:NSUTF8StringEncoding] withTimeout:3 tag:1];[socket disconnect];

另外,可以实现delegate中的这个方法:

123
- (void)onSocketDidDisconnect:(AsyncSocket *)sock{ NSLog(@"socket did disconnect");}

这样就可以在日志中监控到关闭连接的信息。

TCP连接读取指定长度的数据

socket连接,经常碰到这样的需求,读取固定长度的字节。这可以通过下面的示例实现。

还是基于HTTP连接做演示。比如取2次,每次50字节。然后停止socket。

可以这样写:

1234567891011121314
- (void)onSocketDidDisconnect:(AsyncSocket *)sock{ NSLog(@"socket did disconnect");}- (void)viewDidLoad {[super viewDidLoad];

 socket=[[AsyncSocket alloc] initWithDelegate:self];[socket connectToHost:@"www.baidu.com" onPort:80 error:nil];

 data=[[NSMutableData dataWithLength:50] retain];

[socket readDataToLength:50 withTimeout:5 tag:1];[socket readDataToLength:50 withTimeout:5 tag:2];[socket writeData:[@"GET / HTTP/1.1\n\n" dataUsingEncoding:NSUTF8StringEncoding] withTimeout:3 tag:1];

在delegate中,主要是这个方法起作用:

123456789
- (void)onSocket:(AsyncSocket *)sock didReadData:(NSData *)_data withTag:(long)tag{ NSLog(@"did read data");NSString* message = [[[NSString alloc] initWithData:_data encoding:NSUTF8StringEncoding] autorelease]; NSLog(@"message is: \n%@",message);

if (tag==2) {[socket disconnect];}}

日志类似这样:

标红色的是两次取出的字节内容。

编写服务器端Socket

编写了Echo示例,说明最简单的服务器端Socket写法。Echo就是回声,通过telnet发送什么,服务器端就返回什么。类似这样:

服务器端,需要监听客户端的连接。等待客户端发来信息。代码是这样的:

123456789101112
socket=[[AsyncSocket alloc] initWithDelegate:self];NSError *err = nil;

if ([socket acceptOnPort:4322 error:&err]) { NSLog(@"accept ok.");}else { NSLog(@"accept failed.");}

if (err) { NSLog(@"error: %@",err);}

这一步如果成功,应该只有一个日志信息:

1
2011-07-20 12:27:03.228 SocketDemos[611:707] accept ok.

这时如果有客户端与之建立连接,比如通过telnet。会依次调用AsyncSocket 的delegate的如下方法:

  • onSocket:didAcceptNewSocket: AsyncSocket创建了新的Socket用于处理和客户端的请求,如果这个新socket实例你不打算保留(retain),那么将拒绝和该客户端 连接
  • onSocket:wantsRunLoopForNewSocket:,提供线程的runloop实例给AsyncSocket,后者将使用这 个runloop执行socket通讯的操作
  • onSocketWillConnect:,将要建立连接,这时可以做一些准备工作,如果需要的话
  • onSocket:didConnectToHost:port:,这个方法是建立连接后执行的,一般会在这里调用写入或者读取socket的操 作

在Echo示例中,不打算执行多线程,也不想支持多客户端连接,而且服务器端和客户端将建立长连接。直至客户端断开连接,服务器端才释放相应的 socket。

代码如下:

12345678910111213141516171819202122232425262728293031323334353637383940414243
- (void)onSocket:(AsyncSocket *)sock didAcceptNewSocket:(AsyncSocket *)newSocket{if (!acceptSocket) { acceptSocket=[newSocket retain]; NSLog(@"did accept new socket");}}

- (NSRunLoop *)onSocket:(AsyncSocket *)sock wantsRunLoopForNewSocket:(AsyncSocket *)newSocket{ NSLog(@"wants runloop for new socket.");return [NSRunLoop currentRunLoop];}

- (BOOL)onSocketWillConnect:(AsyncSocket *)sock{ NSLog(@"will connect");return YES;}

- (void)onSocket:(AsyncSocket *)sock didConnectToHost:(NSString *)host port:(UInt16)port{ NSLog(@"did connect to host");[acceptSocket readDataWithTimeout:-1 tag:1];}

- (void)onSocket:(AsyncSocket *)sock didReadData:(NSData *)data withTag:(long)tag{ NSLog(@"did read data");NSString* message = [[[NSString alloc] initWithData:data encoding:NSUTF8StringEncoding] autorelease]; NSLog(@"message is: \n%@",message);[acceptSocket writeData:data withTimeout:2 tag:1];}

- (void)onSocket:(AsyncSocket *)sock didWriteDataWithTag:(long)tag{ NSLog(@"message did write");[acceptSocket readDataWithTimeout:-1 tag:1];}

- (void)onSocket:(AsyncSocket *)sock willDisconnectWithError:(NSError *)err{ NSLog(@"onSocket:%p willDisconnectWithError:%@", sock, err);}

- (void)onSocketDidDisconnect:(AsyncSocket *)sock{ NSLog(@"socket did disconnect");[acceptSocket release]; acceptSocket=nil;}

这里timeout设置为-1,这样就可以保持长连接状态。

编写简单的UDP应用

首先,编写发送UDP数据报的示例。这需要有个服务器端能接收到内容。用Java写了个简单的接收端:

1234567891011121314
public static void main(String[] args) throws IOException { InetSocketAddress address = new InetSocketAddress("0.0.0.0", 5555); DatagramSocket datagramSocket=new DatagramSocket(address);

 System.out.println("start udp server");

 byte[] buffer=new byte[1024];

for(;;){ DatagramPacket datagramPacket=new DatagramPacket(buffer, buffer.length); datagramSocket.receive(datagramPacket); System.out.println("receive data:"+new String(datagramPacket.getData(),0,datagramPacket.getLength()));}}

下面写发送的代码:

12345
AsyncUdpSocket *socket=[[AsyncUdpSocket alloc]initWithDelegate:self];

NSData *data=[@"Hello from iPhone" dataUsingEncoding:NSUTF8StringEncoding];[socket sendData:data toHost:@"192.168.0.165" port:5555 withTimeout:-1 tag:1];NSLog(@"send upd complete.");

执行后,在接收端成功输出如下内容:

下面,写个接收端的代码:

1234567891011
AsyncUdpSocket *socket=[[AsyncUdpSocket alloc] initWithDelegate:self];

NSError *error = nil;[socket bindToPort:5555 error:&error];

if (error) { NSLog(@"error: %@",error);}

[socket receiveWithTimeout:-1 tag:1]; NSLog(@"start udp server");

另外,至少写这个delegate方法:

12345678
- (BOOL)onUdpSocket:(AsyncUdpSocket *)sock didReceiveData:(NSData *)data withTag:(long)tag fromHost:(NSString *)host port:(UInt16)port{ NSLog(@"received data: %@",[[[NSString alloc] initWithData:data encoding:NSUTF8StringEncoding] autorelease]);return YES;}

发送端,还是用java写个测试代码:

1234567
public static void main(String[] args) throws IOException { DatagramSocket datagramSocket = new DatagramSocket(); byte[] buffer = "Hello!".getBytes(); DatagramPacket datagramPacket = new DatagramPacket(buffer, buffer.length, new InetSocketAddress("192.168.0.144", 5555)); datagramSocket.send(datagramPacket);}

在iPhone日志中:

12
2011-07-20 15:23:33.571 SocketDemos[795:707] start udp server     2011-07-20 15:23:47.395 SocketDemos[795:707] received data: Hello

收到了数据报。

使用UDP发送和接收组播

这里主要关注的是接收,一方面是需求上要求,另一方面,碰到过Android Wifi获取组播问题,担心iOS也有类似的机制。后来测试发现没有那么麻烦(打开组播锁)。

为了测试,还是用java编写了个发送UDP广播的简单代码:

123456789
public static void main(String[] args) throws IOException {int port=3333; MulticastSocket socket=new MulticastSocket(port); InetAddress address=InetAddress.getByName("239.0.0.1"); socket.joinGroup(address); byte[] data="Hello everyone.".getBytes(); DatagramPacket datagramPacket=new DatagramPacket(data,data.length,address,port); socket.send(datagramPacket); System.out.println("send ok.");

编写的iOS代码:

12345678910111213
AsyncUdpSocket *socket=[[AsyncUdpSocket alloc] initWithDelegate:self];

NSError *error = nil;[socket bindToPort:3333 error:&error];[socket enableBroadcast:YES error:&error];[socket joinMulticastGroup:@"239.0.0.1" error:&error];

if (error) { NSLog(@"error: %@",error);}

[socket receiveWithTimeout:-1 tag:1]; NSLog(@"start udp server");

delegate和上面接收普通UDP一模一样:

12345678
- (BOOL)onUdpSocket:(AsyncUdpSocket *)sock didReceiveData:(NSData *)data withTag:(long)tag fromHost:(NSString *)host port:(UInt16)port{ NSLog(@"received data: %@",[[[NSString alloc] initWithData:data encoding:NSUTF8StringEncoding] autorelease]);return YES;}

测试得到的日志:

12
2011-07-20 16:14:30.338 SocketDemos[860:707] start udp server     2011-07-20 16:14:42.829 SocketDemos[860:707] received data: Hello everyone.

说明是收到了。

发送组播和前面的UDP发送类似,只是多了要做join group的操作。这里就不多说了。

转载于:https://www.cnblogs.com/mobileworld/archive/2011/12/30/2307246.html

CocoaAsyncSocket相关推荐

  1. 即时通讯下数据粘包、断包处理实例(基于CocoaAsyncSocket)

    来源:涂耀辉 www.jianshu.com/p/2e16572c9ddc 如有好文章投稿,请点击 → 这里了解详情 前言 本文旨以实例的方式,使用CocoaAsyncSocket这个框架进行数据封包 ...

  2. tweak 项目 快速搭建CocoaAsyncSocket(建连、断开、重连、心跳、通用请求)

    前言 GitHub http请求: 每次更新数据都要向对应的端口发送一次请求,之后返回数据之后关闭连接 长连接 客户端和服务器一直连着,当有数据更新的时候,服务器会直接发给客户端,不需要客户端主动请求 ...

  3. iOS-----简易地CocoaAsyncSocket使用

    CocoaAsyncSocket使用 代理的.h文件 //GCDAsyncSocketDelegate执行代理对象#import <Foundation/Foundation.h> #im ...

  4. CocoaAsyncSocket 套接字

    CocoaAsyncSocket   套接字 https://github.com/robbiehanson/CocoaAsyncSocket Asynchronous socket networki ...

  5. iOS即时通讯进阶 - CocoaAsyncSocket源码解析(Connect篇)

    原文 前言: CocoaAsyncSocket是谷歌的开发者,基于BSD-Socket写的一个IM框架,它给Mac和iOS提供了易于使用的.强大的异步套接字库,向上封装出简单易用OC接口.省去了我们面 ...

  6. iOS即时通讯之CocoaAsyncSocket源码解析一

    申明:本文内容属于转载整理,原文连接 前言: CocoaAsyncSocket是谷歌的开发者,基于BSD-Socket写的一个IM框架,它给Mac和iOS提供了易于使用的.强大的异步套接字库,向上封装 ...

  7. iOS开发之CocoaAsyncSocket使用

    本文介绍了CocoaAsyncSocket库中GCDAsyncSocket类的使用.粘包处理以及时间延迟测试. 一.CocoaAsyncSocket介绍 CocoaAsyncSocket中主要包含两个 ...

  8. 高仿微信聊天界面:基于CocoaAsyncSocket的即时通讯实现(IM 微信)

    Github地址:https://github.com/AlanZhangQ/Alan_cocoaSocket.git,如果有用,请点star. 之前做的项目有IM部分,在考虑了环信和融云等已经比较通 ...

  9. 使用Pod 安装第三方CocoaAsyncSocket、Kingfisher

    安装好CocoaPods 环境后: 1.单独安装CocoaAsyncSocket 打开mac 终端,ls 查看当前目录文件,cd到当前工程目录,vim Podfile 按i切换到输入模式,输入内容: ...

  10. xcode 消除警告

    项目中引用大量的第三方代码时,这些代码很复杂,不要轻易去改动它,如果编译产生很多警告,该如何消除呢? 1. 最直接.最一劳永逸.最安全的方式,直接找到警告的那段代码,改为不警告.这个方式最安全. 可是 ...

最新文章

  1. TensorFlow练习9: 生成妹子图(PixelCNN)
  2. ubuntu下和开发板下播放音乐
  3. Html.Partial和Html. RenderPartial用法
  4. Java高级语法笔记-文件操作-链表的存储
  5. mmc检测到此管理单元发生一个错误_理解这八大优势,才算精通单元测试
  6. TCP协议及TCP正常连接与断开
  7. 网站设计中很重要的概念div+浮动
  8. 在C#中获取如PHP函数time()一样的时间戳
  9. oracle 删除xml记录,Oracle之xml的增删改查操作
  10. 泛微OA常用js代码块
  11. 微软笔试题《Arithmetic Puzzles》- 题解
  12. [游戏杂谈]浅谈单机游戏制作人到底应该具备什么样的能力
  13. 文通Windows CE平台车牌识别
  14. React项目中提示caniuse-lite已过时,建议更新
  15. ValueError: n_splits=n cannot be greater than the number of members in each class.
  16. mac 锤子android助手,Mac+Android好帮手 锤子SmartFinder
  17. 局部解剖学考试重点总结超级完整
  18. ueditor富文本编辑器使用百度地图自定义动态地图组件及兼容https及http协议
  19. Android Studio - 北极狐 | 2020.3.1 补丁 2 现已推出
  20. Springboot接入华为云短信平台

热门文章

  1. python科学计算之Pandas使用(一)
  2. numpy—np.random.multivariate_normal
  3. 西瓜书读书笔记4-Sigmoid函数
  4. Datawhale编程学习之二叉树和堆(5)
  5. java获取不到ipv6的网卡
  6. 微软全球MVP教你如何由程序员到CTO
  7. 二十一天学通C++之使用throw抛出异常
  8. 4.寻找两个正序数组的中位数
  9. pandas小记:pandas基本设置
  10. ado.net mysql 转义_ADO.NET数据库查询