GCDAsyncSocket 尝试通过不同端口连接服务器的解决方案

原先的设计是通过hostname和port来建立连接的:

[_asyncSocket connectToHost:hostname onPort:_host_port error:&err]

但是有这么一种情况,就是服务端有时候会把port改变掉,比如说它本来约定是用8001的,但是有时候进程被意外杀死之后,8001这个port就申请不到了,只好用8002这个端口,那么在客户端是不知道的,因此要求客户端在连接服务器时,先尝试用8001去连接,假如连接不成功,则改为用8002去连接。

这里面有一个难题,就是在GCDAsyncSocket的connectToHost这个方法里,不能马上知道成功或者失败,因为它的执行是非阻塞的,它通常会先返回成功,即使将来它会连不上,那么它连不上时会不会通过别的delegation来通知用户呢?

为了这个问题,特别研究了一下它里面的实现流程:

- (void)closeWithError:(NSError *)error

这个方法里面有:
// If the client has passed the connect/accept method, then the connection has at least begun.
	// Notify delegate that it is now ending.
	BOOL shouldCallDelegate = (flags & kSocketStarted) ? YES : NO;
	BOOL isDeallocating = (flags & kDealloc) ? YES : NO;
	
	// Clear stored socket info and all flags (config remains as is)
	socketFDBytesAvailable = 0;
	flags = 0;
	sslWriteCachedLength = 0;
	
	if (shouldCallDelegate)
	{
		__strong id theDelegate = delegate;
		__strong id theSelf = isDeallocating ? nil : self;
		
		if (delegateQueue && [theDelegate respondsToSelector: @selector(socketDidDisconnect:withError:)])
		{
			dispatch_async(delegateQueue, ^{ @autoreleasepool {
				
				[theDelegate socketDidDisconnect:theSelf withError:error];
			}});
		}	
	}


从这里可以看到,当连接失败时,它会呼叫
socketDidDisconnect:withError:

这个代理方法的,因此解决的方案就出来了,可以实现这个方法,然后再在里面重新用新的端口来建立连接

-(void)socketDidDisconnect:(GCDAsyncSocket *)sock withError:(NSError *)err
{
    
    
    NSLog(@"socketDidDisconnect port:%d:%@",[sock localPort],err);
    
    为了谨慎起见,只处理错误号为61的情况
    if (err.code == 61) { //hu:handle port change to 8002
        NSLog(@"connection refused");
        _host_port = 8002;
        [self connectServer];
    }
}

经过试验,这样的方式是可行的。




发布了74 篇原创文章 · 获赞 12 · 访问量 12万+
展开阅读全文

oc中,我用GCDAsyncSocket连上了socket,但是无法往服务器发送数据

01-04

#import "GCDSocketManager.h" #import "GCDAsyncSocket.h" #define SocketHost @"61.191.45.94" #define SocketPort 8091 @interface GCDSocketManager()<GCDAsyncSocketDelegate> //握手次数 @property(nonatomic,assign) NSInteger pushCount; //断开重连定时器 @property(nonatomic,strong) NSTimer *timer; //重连次数 @property(nonatomic,assign) NSInteger reconnectCount; @end @implementation GCDSocketManager //全局访问点 + (instancetype)sharedSocketManager { static GCDSocketManager *_instance = nil; static dispatch_once_t onceToken; dispatch_once(&onceToken, ^{ _instance = [[self alloc] init]; }); return _instance; } //可以在这里做一些初始化操作 - (instancetype)init { self == [super init]; if (self) { self.socket = [[GCDAsyncSocket alloc]initWithDelegate:self delegateQueue:dispatch_get_main_queue()]; } return self; } #pragma mark 请求连接 //连接 - (void)connectToServer { self.pushCount = 0; self.socket = [[GCDAsyncSocket alloc] initWithDelegate:self delegateQueue:dispatch_get_main_queue()]; NSError *error = nil; // [self.socket connectToHost:SocketHost onPort:SocketPort error:&error]; [self.socket connectToHost:SocketHost onPort:SocketPort error:&error]; if (error) { NSLog(@"SocketConnectError:%@",error); } } #pragma mark 连接成功 //连接成功的回调 - (void)socket:(GCDAsyncSocket *)sock didConnectToHost:(NSString *)host port:(uint16_t)port { NSLog(@"socket连接成功"); [self sendDataToServer]; } //连接成功后向服务器发送数据 - (void)sendDataToServer { NSString *jsonData = @"kUOhLq1vFfPqzx5WtcJr0ZWmZ89uM9KEx4bthINy3HL2QD8oLjBGXhVv2gAlDjfwtTp0HrwnGLYxAloJ+ABzqzIS2OBG6MwDJLwQmJVPajgcNZhLZKFzmdvWbo+7HR+hSN2Co4DQRQfUm2n8HsDjAyNVUgpmO39NJ4XY085oGPE/dHkq/t5Y7A=="; NSData *cmdData = [jsonData dataUsingEncoding:NSUTF8StringEncoding]; NSLog(@"socket发送数据--->%@",cmdData); //发送 [self.socket writeData:cmdData withTimeout:-1 tag:0]; //读取数据 [self.socket readDataWithTimeout:-1 tag:100]; } //连接成功向服务器发送数据后,服务器会有响应 - (void)socket:(GCDAsyncSocket *)sock didReadData:(NSData *)data withTag:(long)tag { NSString *msg = [[NSString alloc] initWithData:data encoding:NSUTF8StringEncoding]; NSLog(@"收到的数据-->%@",msg); [self.socket readDataWithTimeout:-1 tag:200]; //服务器推送次数 self.pushCount++; //在这里进行校验操作,情况分为成功和失败两种,成功的操作一般都是拉取数据 } #pragma mark 连接失败 //连接失败的回调 - (void)socketDidDisconnect:(GCDAsyncSocket *)sock withError:(NSError *)err { NSLog(@"Socket连接失败"); self.pushCount = 0; NSUserDefaults *userDefaults = [NSUserDefaults standardUserDefaults]; NSString *currentStatu = [userDefaults valueForKey:@"Statu"]; //程序在前台才进行重连 if ([currentStatu isEqualToString:@"foreground"]) { //重连次数 self.reconnectCount++; //如果连接失败 累加1秒重新连接 减少服务器压力 NSTimer *timer = [NSTimer scheduledTimerWithTimeInterval:1.0 * self.reconnectCount target:self selector:@selector(reconnectServer) userInfo:nil repeats:NO]; self.timer = timer; } } //如果连接失败,5秒后重新连接 - (void)reconnectServer { self.pushCount = 0; self.reconnectCount = 0; //连接失败重新连接 NSError *error = nil; [self.socket connectToHost:SocketHost onPort:SocketPort error:&error]; if (error) { NSLog(@"SocektConnectError:%@",error); } } #pragma mark 断开连接 //切断连接 - (void)cutOffSocket { NSLog(@"socket断开连接"); self.pushCount = 0; self.reconnectCount = 0; [self.timer invalidate]; self.timer = nil; [self.socket disconnect]; } @end sendDataToServer中我调用writeData给服务器发送数据无法发送 问答

没有更多推荐了,返回首页

©️2019 CSDN 皮肤主题: 精致技术 设计师: CSDN官方博客

分享到微信朋友圈

×

扫一扫,手机浏览