记:iOS使用GCDAsyncSocket外部如何设置keepalive

4 篇文章 0 订阅
2 篇文章 0 订阅

问题描述:

最近在我的项目组中遇到一个问题,由于我们项目使用采用的是TCP+Protobuf来做主要通讯协议,心跳是使用udp。
服务器分为多台,各服务器负责各自的任务,比如我们账号服务器只负责与用户数据相关的任务,推送服务器负责服务器向前端通知等等。
当我们的TCP中间由于某种原因与服务器断开连接,但是服务器和客户端都没有接到断开通知,或者需要好长时间才能知道(默认的超时时间为7200s,及2个小时,重试5次),彼此之间认为链接正常,但是在这个时间点如果服务器推送一个消息我们是接不到的,所以导致了要设置keepalive的问题。

问题解决:

在socket已经链接成功代理方法中:

- (void)socket:(GCDAsyncSocket *)sock didConnectToHost:(NSString *)host port:(uint16_t)port

添加代码:

[sock performBlock:^{
            [self setKeepAliveWithSocketFD:sock.socketFD];
        }];
- (void)setKeepAliveWithSocketFD:(int)socketFD {
    int keepAlive = 1;
    int idleTime = 10;
    int intvlTime = 10;
    int cntCount = 3;
    if (setsockopt(socketFD, SOL_SOCKET, SO_KEEPALIVE, &keepAlive, sizeof(keepAlive)) < 0) {
        NSLog(@"#######################: %s", strerror(errno));
    }
    if (setsockopt(socketFD, IPPROTO_TCP, TCP_KEEPALIVE, &idleTime, sizeof(idleTime)) < 0) {
        NSLog(@"#######################: %s", strerror(errno));
    }
    if (setsockopt(socketFD, IPPROTO_TCP, TCP_KEEPINTVL, &intvlTime, sizeof(intvlTime)) < 0) {
        NSLog(@"#######################: %s", strerror(errno));
    }
    if (setsockopt(socketFD, IPPROTO_TCP, TCP_KEEPCNT, &cntCount, sizeof(cntCount)) < 0) {
        NSLog(@"#######################: %s", strerror(errno));
    }
}

各个字段解释:

keepAlive // 是否使用keepalive

idleTime // 开始首次keepalive探测前的TCP空闭时间

intvlTime // 两次keepalive探测间的时间间隔
cntCount // keepalive重试次数

如果没有error打出说明设置没问题了。

遇到的问题及思考:

当我去写这段代码时遇到了一点小问题,原因是我的粗心大意及没对GCDAsyncSocket API文档认真阅读导致的。

就是获取套接字没有在performBlock中获取。API文档:

/**
 * It's not thread-safe to access certain variables from outside the socket's internal queue.
 * 
 * For example, the socket file descriptor.
 * File descriptors are simply integers which reference an index in the per-process file table.
 * However, when one requests a new file descriptor (by opening a file or socket),
 * the file descriptor returned is guaranteed to be the lowest numbered unused descriptor.
 * So if we're not careful, the following could be possible:
 * 
 * - Thread A invokes a method which returns the socket's file descriptor.
 * - The socket is closed via the socket's internal queue on thread B.
 * - Thread C opens a file, and subsequently receives the file descriptor that was previously the socket's FD.
 * - Thread A is now accessing/altering the file instead of the socket.
 * 
 * In addition to this, other variables are not actually objects,
 * and thus cannot be retained/released or even autoreleased.
 * An example is the sslContext, of type SSLContextRef, which is actually a malloc'd struct.
 * 
 * Although there are internal variables that make it difficult to maintain thread-safety,
 * it is important to provide access to these variables
 * to ensure this class can be used in a wide array of environments.
 * This method helps to accomplish this by invoking the current block on the socket's internal queue.
 * The methods below can be invoked from within the block to access
 * those generally thread-unsafe internal variables in a thread-safe manner.
 * The given block will be invoked synchronously on the socket's internal queue.
 * 
 * If you save references to any protected variables and use them outside the block, you do so at your own peril.
**/

我不明白我获取socket套接字为什么要在GCDAsyncSocket 中的socket队列中。这个问题我会在后面研究下并补上的。或者有知道的麻烦说一下,谢谢。

希望对你有所帮助。



  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值