iOS 使用第三方库CocoaAsyncSocket进行Tcp通讯
iPhone的标准推荐CFNetwork C库编程。但是编程比较烦躁。在其它OS往往用类来封装的对Socket函数的处理。比如MFC的CAsysncSocket.在iphone也有类似于开源项目.cocoa AsyncSocket库, 官方网站: http://code.google.com/p/cocoaasyncsocket/ 它用来简化CFnetwork的调用.。
但是由于中国的长城防火墙,谷歌网站无法访问。因此,这里我是从github上下的 https://github.com/robbiehanson/CocoaAsyncSocket
AsyncSocket分为2个版本(个人理解如下)
(1)GCD版。Grand Central Dispatch (GCD)是Apple开发的一个多核编程的解决方法。 简单的说就是基于多线程。
(2)RunLoop版。就是单线程以阻塞处理事件而形成一个消息循环,执行完毕后并不退出。
目录结构如下
AsyncSocket包括TCP和UDP,通过实现委托AsyncSocketDelegate进行交互。
调用此API时需先引入CFNetWork.framework。(网上有的说需要加入该框架,但是为在 iOS9 XCode7beta 中不添加亦可正常运行)
如果是实现GCD版本,则需要将GCD文件夹中的4个文件加入项目
这里只实现GCD版本的Tcp,Udp类似,实现代码如下
1、Main.storyboard
2、ConnectionDef
//
// ConnectDef.h
// AsyncSocketDemo
//
// Created by 555chy on 6/22/16.
// Copyright © 2016 555chy. All rights reserved.
//
#ifndef ConnectDef_h
#define ConnectDef_h
#define DEF_STR_ENCODING NSUTF8StringEncoding
//连接超时时间为60秒
#define CONNECT_TIMEOUT 60
#define READ_TIMEOUT -1
//发送数据超时时间为60秒
#define WRITE_TIMEOUT 60
#define SERVER_QUEUE "tcpServerQueue"
#define CLIENT_QUEUE "tcpClientQueue"
#define SERVER_ADDRESS @"127.0.0.1"
#define SERVER_PORT 12345
#endif /* ConnectDef_h */
2、TcpServer.h
//
// TcpServer.h
// AsyncSocketDemo
//
// Created by 555chy on 6/21/16.
// Copyright © 2016 555chy. All rights reserved.
//
#import <Foundation/Foundation.h>
#import "GCDAsyncSocket.h"
#import "ConnectionDef.h"
@interface TcpServer : NSObject <GCDAsyncSocketDelegate> {
GCDAsyncSocket *serverSocket;
NSMutableArray *clientArray;
long readTag;
long writeTag;
}
-(long)getReadTag;
-(long)getWriteTag;
-(void)createTcpSocket:(const char *)queueName acceptOnPort:(uint16_t)port;
-(void)socket:(GCDAsyncSocket *)sock didAcceptNewSocket:(GCDAsyncSocket *)newSocket;
-(void)socket:(GCDAsyncSocket *)sock didReadData:(NSData *)data withTag:(long)tag;
-(void)socket:(GCDAsyncSocket *)sock didWriteDataWithTag:(long)tag;
-(void)socket:(GCDAsyncSocket *)sock writeString:(NSString *)str withTag:(long)tag;
-(void)broadcastStr:(NSString *)str;
-(void)socketDidDisconnect:(GCDAsyncSocket *)sock withError:(NSError *)err;
@end
3、TcpServer.m
//
// TcpServer.m
// AsyncSocketDemo
//
// Created by 555chy on 6/21/16.
// Copyright © 2016 555chy. All rights reserved.
//
#import "TcpServer.h"
@implementation TcpServer
-(long)getReadTag {
return readTag++;
}
-(long)getWriteTag {
return writeTag++;
}
-(void)createTcpSocket:(const char *)queueName acceptOnPort:(uint16_t)port {
clientArray = [NSMutableArray array];
dispatch_queue_t dispatchQueue = dispatch_queue_create(queueName, NULL);
serverSocket = [[GCDAsyncSocket alloc] initWithDelegate:self delegateQueue:dispatchQueue];
[serverSocket acceptOnPort:port error:nil];
readTag = 0;
writeTag = 0;
}
-(void)socket:(GCDAsyncSocket *)sock didAcceptNewSocket:(GCDAsyncSocket *)newSocket {
NSString* ip = [newSocket connectedHost];
uint16_t port = [newSocket connectedPort];
NSLog(@"server didAcceptNewSocket [%@:%d]", ip, port);
[clientArray addObject:newSocket];
//一直等待readSocket的消息(tag是一个标记类似于tcp数据包中的序列号)
[newSocket readDataWithTimeout:READ_TIMEOUT tag:[self getReadTag]];
}
-(void)socket:(GCDAsyncSocket *)sock didReadData:(NSData *)data withTag:(long)tag {
NSString *ip = [sock connectedHost];
uint16_t port = [sock connectedPort];
NSString *str = [[NSString alloc] initWithData:data encoding:DEF_STR_ENCODING];
NSLog(@"server didReadData [%@:%d] %@", ip, port, str);
//再次接收数据,因为这个方法只接收一次
[sock readDataWithTimeout:READ_TIMEOUT tag:[self getReadTag]];
}
-(void)socket:(GCDAsyncSocket *)sock didWriteDataWithTag:(long)tag {
NSString *ip = [sock connectedHost];
uint16_t port = [sock connectedPort];
NSLog(@"server didWriteDataWithTag [%@:%d]", ip, port);
}
-(void)socket:(GCDAsyncSocket *)sock writeString:(NSString *)str withTag:(long)tag {
NSData *data = [str dataUsingEncoding:DEF_STR_ENCODING];
[sock writeData:data withTimeout:WRITE_TIMEOUT tag:[self getWriteTag]];
}
-(void)broadcastStr:(NSString *)str {
for(GCDAsyncSocket *sock in clientArray) {
[self socket:sock writeString:str withTag:[self getWriteTag]];
}
}
-(void)socketDidDisconnect:(GCDAsyncSocket *)sock withError:(NSError *)err {
NSString *ip = [sock connectedHost];
uint16_t port = [sock connectedPort];
NSLog(@"server socketDidDisconnect [%@:%d]", ip, port);
[clientArray removeObject:sock];
}
@end
4、TcpClient.h
//
// TcpClient.h
// AsyncSocketDemo
//
// Created by 555chy on 6/21/16.
// Copyright © 2016 555chy. All rights reserved.
//
#import <Foundation/Foundation.h>
#import "GCDAsyncSocket.h"
#import "ConnectionDef.h"
@interface TcpClient : NSObject<GCDAsyncSocketDelegate> {
GCDAsyncSocket *clientSocket;
long readTag;
long writeTag;
}
-(long)getReadTag;
-(long)getWriteTag;
-(void)createTcpSocket:(const char *)queueName connectToHost:(NSString *) host onPort:(uint16_t)port;
-(void)socket:(GCDAsyncSocket *)sock didConnectToHost:(NSString *)host port:(uint16_t)port;
-(void)socket:(GCDAsyncSocket *)sock didReadData:(NSData *)data withTag:(long)tag;
-(void)socket:(GCDAsyncSocket *)sock didWriteDataWithTag:(long)tag;
-(void)writeString:(NSString *)str withTag:(long)tag;
-(void)socketDidDisconnect:(GCDAsyncSocket *)sock withError:(NSError *)err;
@end
5、TcpClient.m
//
// TcpClient.m
// AsyncSocketDemo
//
// Created by 555chy on 6/21/16.
// Copyright © 2016 555chy. All rights reserved.
//
#import "TcpClient.h"
@implementation TcpClient
-(long)getReadTag {
return readTag++;
}
-(long)getWriteTag {
return writeTag++;
}
-(void)createTcpSocket:(const char *)queueName connectToHost:(NSString *) host onPort:(uint16_t)port {
dispatch_queue_t dispatchQueue = dispatch_queue_create(queueName, NULL);
clientSocket = [[GCDAsyncSocket alloc] initWithDelegate:self delegateQueue:dispatchQueue];
[clientSocket connectToHost:host onPort:port withTimeout:CONNECT_TIMEOUT error:nil];
}
-(void)socket:(GCDAsyncSocket *)sock didConnectToHost:(NSString *)host port:(uint16_t)port {
NSLog(@"client didConnectToHost [%@:%d]", host, port);
[sock readDataWithTimeout:READ_TIMEOUT tag:[self getReadTag]];
}
-(void)socket:(GCDAsyncSocket *)sock didReadData:(NSData *)data withTag:(long)tag {
NSString *ip = [sock connectedHost];
uint16_t port = [sock connectedPort];
NSString *str = [[NSString alloc] initWithData:data encoding:DEF_STR_ENCODING];
NSLog(@"client didReadData [%@:%d] %@", ip, port, str);
}
-(void)socket:(GCDAsyncSocket *)sock didWriteDataWithTag:(long)tag {
NSString *ip = [sock connectedHost];
uint16_t port = [sock connectedPort];
NSLog(@"client didWriteDataWithTag [%@:%d]", ip, port);
}
-(void)writeString:(NSString *)str withTag:(long)tag {
NSData *data = [str dataUsingEncoding:DEF_STR_ENCODING];
[clientSocket writeData:data withTimeout:WRITE_TIMEOUT tag:[self getWriteTag]];
}
-(void)socketDidDisconnect:(GCDAsyncSocket *)sock withError:(NSError *)err {
NSString *ip = [sock connectedHost];
uint16_t port = [sock connectedPort];
NSLog(@"client socketDidDisconnect [%@:%d]", ip, port);
//可以在这边实现断线重连机制
}
@end
7、ViewController.h
//
// ViewController.h
// AsyncSocketDemo
//
// Created by 555chy on 6/21/16.
// Copyright © 2016 555chy. All rights reserved.
//
#import <UIKit/UIKit.h>
#import "TcpServer.h"
#import "TcpClient.h"
#import "ConnectionDef.h"
@interface ViewController : UIViewController
@property (nonatomic, retain) TcpServer *tcpServer;
@property (nonatomic, retain) TcpClient *tcpClient;
@property (weak, nonatomic) IBOutlet UITextField *serverSendTextField;
@property (strong, nonatomic) IBOutlet UIView *serverSendButton;
@property (weak, nonatomic) IBOutlet UITextField *clientSendTextField;
@property (weak, nonatomic) IBOutlet UIButton *clientSendButton;
- (IBAction)serverSendButtonClick:(id)sender;
- (IBAction)clientSendButtonClick:(id)sender;
@end
8、ViewController.m
//
// ViewController.m
// AsyncSocketDemo
//
// Created by 555chy on 6/21/16.
// Copyright © 2016 555chy. All rights reserved.
//
#import "ViewController.h"
@interface ViewController ()
@end
@implementation ViewController
- (void)viewDidLoad {
[super viewDidLoad];
// Do any additional setup after loading the view, typically from a nib.
_tcpServer = [[TcpServer alloc] init];
_tcpClient = [[TcpClient alloc] init];
[_tcpServer createTcpSocket:SERVER_QUEUE acceptOnPort:SERVER_PORT];
[_tcpClient createTcpSocket:CLIENT_QUEUE connectToHost:SERVER_ADDRESS onPort:SERVER_PORT];
}
- (void)didReceiveMemoryWarning {
[super didReceiveMemoryWarning];
// Dispose of any resources that can be recreated.
}
- (IBAction)serverSendButtonClick:(id)sender {
[_tcpServer broadcastStr:_serverSendTextField.text];
}
- (IBAction)clientSendButtonClick:(id)sender {
[_tcpClient writeString:_clientSendTextField.text withTag:[_tcpClient getWriteTag]];
}
@end
实际效果图如下
相关文章
- 《iOS应用逆向工程:分析与实战》
- IOS Swift语言开发 tableView的重用以及自cell的自适应高度
- NSRegularExpression iOS自带的正则表达式
- iOS中打包.a静态库
- iOS开发UI篇—ios应用数据存储方式(归档)
- IOS用CGContextRef画各种图形(文字、圆、直线、弧线、矩形、扇形、椭圆、三角形、圆角矩形、贝塞尔曲线、图片)
- WWDC2022看点之 iOS 16 上可以启用与关闭开发者模式
- sql server.ios怎么安装
- 随手记之TCP Keepalive笔记-tcp_keepalive_timer
- iOS开发数据库篇—FMDB简单介绍
- IOS_ios逆向工程-静态分析
- IOS GCD 使用(三)单例模式
- XMPP协议实现即时通讯底层书写 (二)-- IOS XMPPFramework Demo+分析
- weex在iOS环境加载本地图片的方法
- ios开发下的点透处理