iOS开发 socket, 全局socket
因为项目的要求是全局的socket, 哪里都有可能使用到socket去发消息, 所以我把socket写在了单利里面
项目用的是 pod 'CocoaAsyncSocket' 三方库, 是异步的, 如果没有cocopods 那就去guthub下载一个
特别需要注意一点, 如果服务器一下连着发了好几条数据, 消息会阻塞. 明确来说是大部分的文章在发出一条数据之后只调用了一次[sock readDataWithTimeout:-1 tag:0]; 这个方法去手动接收. 类似于发一条才能收一条这种概念,所以我在每收到一条数据处理完后再次调用一次这个方法
1.建立单例类 (单利还不会的,那真的要去好好查了, 这里的单例可能说的不太详细)
.h文件
#import <Foundation/Foundation.h>
//导入头文件
#import "GCDAsyncSocket.h"
//遵循代理
@interface Singleton : NSObject<GCDAsyncSocketDelegate>
//全局socket
@property(nonatomic,strong) GCDAsyncSocket *socket;
//单例创建方法
//此类方法, 不管调用多少次. 都只会使用一个, 单利请谨慎使用
+(Singleton *)shareSingleton;
//socket连接
- (void)connectToServerWithHost:(NSString *)host AndPort:(int)port;
//socket发送消息
- (void)sendMassageWithData:(NSString *)data;
@end
.m文件
static Singleton * shareS = nil;
//单例实现方法
+ (Singleton *)shareSingleton{
if (shareS == nil) {
shareS = [[Singleton alloc]init];
}
return shareS;
}
//实现.h连接方法
- (void)connectToServerWithHost:(NSString *)host AndPort:(int)port{
//这个方法在下面 , host 是后台给的服务器地址, port是端口
[self StartLiveBtnWithHost:host AndPort:port];
}
//实现发送消息方法
- (void)sendMassageWithData:(NSString *)str{
//这个方法是CocoaAsyncSocket 的方法, str是其他地方调用的时候传来, 注意: 如果后台对socket消息有不同的要求,那么要沟通好, 比如消息头,消息体之类的
NSData * data = [str dataUsingEncoding:NSUTF8StringEncoding];
[self.socket writeData:data withTimeout:1 tag:200];
}
#pragma mark 建立Socket连接
- (void)StartLiveBtnWithHost:(NSString *)host AndPort:(int )port{
NSLog(@"建立长连接");
//getProperIPWithAddress 是针对ipv6后, 做的处理 , 别急, 在下面
NSString * ipaddr = [self getProperIPWithAddress:host port:port];
//创建一个socket对象
GCDAsyncSocket * socket = [[GCDAsyncSocket alloc] initWithDelegate:self delegateQueue:dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0)];
//连接
NSError *error = nil;
[socket connectToHost:ipaddr onPort:port error:&error];
self.socket = socket;
if (error) {
NSLog(@"%@",error);
}
}
//针对ipv6网络环境下适配,ipv4环境直接使用原来的地址
- (NSString *)getProperIPWithAddress:(NSString *)ipAddr port:(UInt32)port
{
NSError *addresseError = nil;
NSArray *addresseArray = [GCDAsyncSocket lookupHost:ipAddr
port:port
error:&addresseError];
if (addresseError) {
NSLog(@"");
}
NSString *ipv6Addr = [[NSString alloc]init];
for (NSData *addrData in addresseArray) {
if ([GCDAsyncSocket isIPv6Address:addrData]) {
ipv6Addr = [GCDAsyncSocket hostFromAddress:addrData];
}
}
if (ipv6Addr.length == 0) {
ipv6Addr = ipAddr;
}
return ipv6Addr;
}
#pragma mark 连接成功
-(void)socket:(GCDAsyncSocket *)sock didConnectToHost:(NSString *)host port:(uint16_t)port{
NSLog(@"%s",__func__);
//只要走了这个代理方法, 就说明连接已经成功
NSLog(@"连接成功");
}
#pragma mark 断开连接
-(void)socketDidDisconnect:(GCDAsyncSocket *)sock withError:(NSError *)err{
//这里有两种情况,网络不畅时间太长连接失败, 或者用户退出正常断开, 我这里做了断开提示用户,并且相应的断线重连
if (err) {
NSLog(@"连接失败");
[self.socket disconnect];
//弹出提示框;
UIAlertController *alert = [UIAlertController alertControllerWithTitle:@"提示" message:@"网络不畅断开连接,请检查重新连接" preferredStyle: UIAlertControllerStyleAlert];
UIAlertAction * action1 = [UIAlertAction actionWithTitle:@"取消" style:UIAlertActionStyleDefault handler:^(UIAlertAction * _Nonnull action) {
}];
UIAlertAction * action2 = [UIAlertAction actionWithTitle:@"确定" style:UIAlertActionStyleDefault handler:^(UIAlertAction * _Nonnull action) {
//这里就是重新调一下socket连接的方法, 以及一些其他操作,根据自己的需求来
[HttpRequest ReconnectOnloss];
}];
[alert addAction:action1];
[alert addAction:action2];
//弹出提示框;
[[self appRootViewController] presentViewController:alert animated:true completion:nil];
}
}else{
NSLog(@"正常断开");
[self.timer invalidate];
[self.socket disconnect];
UIAlertController *alert = [UIAlertController alertControllerWithTitle:@"提示" message:@"网络不畅断开连接,请检查重新连接" preferredStyle: UIAlertControllerStyleAlert];
UIAlertAction * action1 = [UIAlertAction actionWithTitle:@"取消" style:UIAlertActionStyleDefault handler:^(UIAlertAction * _Nonnull action) {
}];
UIAlertAction * action2 = [UIAlertAction actionWithTitle:@"确定" style:UIAlertActionStyleDefault handler:^(UIAlertAction * _Nonnull action) {
//这里就是重新调一下socket连接的方法, 以及一些其他操作,根据自己的需求来
[HttpRequest ReconnectOnloss];
}];
[alert addAction:action1];
[alert addAction:action2];
//弹出提示框;
[[self appRootViewController] presentViewController:alert animated:true completion:nil];
}
}
#pragma mark 数据发送成功
-(void)socket:(GCDAsyncSocket *)sock didWriteDataWithTag:(long)tag{
NSLog(@"%s",__func__);
//发送完数据手动读取,-1不设置超时
[sock readDataWithTimeout:-1 tag:0];
}
#pragma mark 读取数据
-(void)socket:(GCDAsyncSocket *)sock didReadData:(NSData *)data withTag:(long)tag{
//这里的data,就是实时收到的后台发来的消息, 如果服务器用了各种方式的加密, 还需要跟后台人员及时沟通
NSLog(@"-------------data:%@",data);
NSString *receiverStr = [[NSString alloc] initWithData:data encoding:NSUTF8StringEncoding];
NSLog(@"--------------%@",receiverStr);
//在这里,或者在你的消息处理类里面调用, 这样就不用发, 也可以实时一直收到数据
[sock readDataWithTimeout:-1 tag:0];
}
--------------------------------------------------------------------------------
//顺便加上调用发消息
//如果在单例里面发
[self sendMassageWithData:[NSString stringWithFormat:@"8014,%@",dic[@"mRoleID"]]];
//如果在其他类发
[[Singleton shareSingleton] sendMassageWithData:[NSString stringWithFormat:@"8014,%@",dic[@"mRoleID"]]];
//如果有哪里不对的地方请多多包涵,共同研究, 可能有些括号不全之类的.
iOS开发 socket, 全局socket的更多相关文章
- iOS开发网络篇—Socket编程
一.网络各个协议:TCP/IP.SOCKET.HTTP等 网络七层由下往上分别为物理层.数据链路层.网络层.传输层.会话层.表示层和应用层. 其中物理层.数据链路层和网络层通常被称作媒体层,是网络工程 ...
- iOS:iOS开发非常全的三方库、插件等等
iOS开发非常全的三方库.插件等等 github排名:https://github.com/trending, github搜索:https://github.com/search. 此文章转自git ...
- iOS开发之资料收集
github排名:https://github.com/trending, github搜索:https://github.com/search. 此文章转自github:https://github ...
- iOS开发 非常全的三方库、插件、大牛博客等等
UI 下拉刷新 EGOTableViewPullRefresh- 最早的下拉刷新控件. SVPullToRefresh- 下拉刷新控件. MJRefresh- 仅需一行代码就可以为UITableVie ...
- iOS - 开发类库
开发类库 UI 项目名称 项目信息 1.MJRefresh 仅需一行代码就可以为UITableView或者CollectionView加上下拉刷新或者上拉刷新功能.可以自定义上下拉刷新的文字说明. ...
- iOS开发--iOS及Mac开源项目和学习资料
文/零距离仰望星空(简书作者)原文链接:http://www.jianshu.com/p/f6cdbc8192ba著作权归作者所有,转载请联系作者获得授权,并标注“简书作者”. 原文出处:codecl ...
- iOS开发常用第三方库
UI 动画 网络相关 Model 其他 数据库 缓存处理 PDF 图像浏览及处理 摄像照相视频音频处理 响应式框架 消息相关 版本新API的Demo 代码安全与密码 测试及调试 AppleWatch ...
- iOS开发之即时通讯之Socket(AsyncSocket)
1.AsyncSocket介绍 如果需要在项目中像QQ微信一样做到即时通讯,必须使用socket通讯. iOS中Socket编程的方式: BSD Socket: BSD Socket 是UNIX系统中 ...
- iOS 网络编程:socket
@import url(http://i.cnblogs.com/Load.ashx?type=style&file=SyntaxHighlighter.css);@import url(/c ...
随机推荐
- 微信小程序入门之构建一个简单TODOS应用
最近开始了解微信小程序,虽然小程序已经出了很久了,刚出的那段时间很火,看到很多关于小程序的技术文章,不过现在似乎没那么火了,anyway,我们还是可以学习下的. 一.了解微信小程序 1.理念:小程序开 ...
- ObjC中的AOP--面向切面编程
上篇博客我们类比着Java的Spring框架中的依赖注入的实现方式,也试着使用Objective-C来写了一下OC中的依赖注入的实现方式.当然,我们是使用的PList文件来加载的依赖注入时用到的依赖关 ...
- css 超出隐藏显示...
<!DOCTYPE html><html> <head> <meta charset="UTF-8"> <title>& ...
- switch 在什么时候可以不写default
var point = (2,17) switch point { //case (var x,17): // print("x = \(x)") case (var x,v ...
- WPF 动态生成DataGrid及动态绑定解决方案
一.场景 有过WPF项目经验的朋友可能都知道,如果一个DataGrid要绑定静态的数据是非常的简单的(所谓静态是指绑定的数据源的类型是静态的),如下图所示,想要显示产品数据,只需绑定到一个产品列表即可 ...
- 【转】Lucene.NET详细使用与优化详解
1 lucene简介1.1 什么是luceneLucene是一个全文搜索框架,而不是应用产品.因此它并不像www.baidu.com 或者google Desktop那么拿来就能用,它只是提供了一种工 ...
- UWP--集合绑定数据
使用 ObservableCollection 列表控件主要是 ListBox.ListView.GridView 等. 为列表控件绑定数据不再是为 DataContext 属性赋值,应该使用列表 ...
- c#进程之间对象传递方法
1. 起源 KV项目下载底层重构升级决定采用独立进程进行Media下载处理,以能做到模块复用之目的,因此涉及到了独立进程间的数据传递问题. 目前进程间数据传递,多用WM_COPYDATA.共享dll. ...
- BFS-基础简单的算法
前言 有时候,当你并不了解很多高级算法的时候,搜索不失为一种解决问题的好方法,而且很多高级算法有或多或少的会用到搜索或者搜索的思想.可见,搜索是一个基础并且必须要掌握的算法. 在这篇文章中,会对BFS ...
- GCC命令
一. 常用编译命令选项 源程序test.c 1. 无选项编译链接用法:#gcc test.c作用:将test.c预处理.汇编.编译并链接形成可执行文件.这里未指定输出文件,默认输出为a.out. 2. ...