GCDAsyncSocket 尝试通过不同端口连接服务器的解决方案
2016-12-07 15:34
453 查看
原先的设计是通过hostname和port来建立连接的:
[_asyncSocket connectToHost:hostname onPort:_host_port error:&err]
但是有这么一种情况,就是服务端有时候会把port改变掉,比如说它本来约定是用8001的,但是有时候进程被意外杀死之后,8001这个port就申请不到了,只好用8002这个端口,那么在客户端是不知道的,因此要求客户端在连接服务器时,先尝试用8001去连接,假如连接不成功,则改为用8002去连接。
这里面有一个难题,就是在GCDAsyncSocket的connectToHost这个方法里,不能马上知道成功或者失败,因为它的执行是非阻塞的,它通常会先返回成功,即使将来它会连不上,那么它连不上时会不会通过别的delegation来通知用户呢?
为了这个问题,特别研究了一下它里面的实现流程:
在
- (void)closeWithError:(NSError *)error
这个方法里面有:
从这里可以看到,当连接失败时,它会呼叫
这个代理方法的,因此解决的方案就出来了,可以实现这个方法,然后再在里面重新用新的端口来建立连接
-(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];
}
}
经过试验,这样的方式是可行的。
[_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];
}
}
经过试验,这样的方式是可行的。
相关文章推荐
- GCDAsyncSocket不通过服务器进行客户端间直接连接—iOS移动开发
- 单IP通过不同端口访问不同服务器
- Socket编程服务器和客户端(多个客户端可以同时连接一个服务器的同一端口)
- GCDAsyncUdpSocket 组播监听端口接收数据
- 关于socket通信的理解,socket连接通过IP+端口号的方式,那么如果两个服务器端的应用在同一台机器上,并且位于同一个tomcat容器下,那么岂不是两个服务器都收到了客户端发送的信息
- FL2440 通过Socket使开发板作为服务器支持多个客户端连接并与之通信,可通过命令获取当前温度。
- Android通过socket连接服务器(PC)
- 不同服务器上的Java项目文件同步 解决方案(socket 、http)
- SMTP 服务器要求安全连接或客户端未通过身份验证的各个解决方案(C#)
- WP8.1通过StreamSocket连接C++服务器
- Swift开发:GCDAsyncSocket通信之TCP服务器
- Socket编程服务器和客户端(多个客户端可以同时连接一个服务器的同一端口)
- socket的连接(三次握手)和关闭过程(四次握手)与服务器各种关闭对客户端的不同影响
- ssh命令通过制定端口连接远程服务器
- Socket编程服务器和客户端(多个客户端可以同时连接一个服务器的同一端口)
- SOCKET通过代理连接服务器
- SMTP 服务器要求安全连接或客户端未通过身份验证的各个解决方案(C#)
- python的socket连接端口:代替telnet检测服务器端口
- iOS 通过GCDAsyncSocket建立tcp链接
- SOCKET通过代理连接服务器