connect永远阻塞线程及解决方案

本文描述了iOS9系统下应用在前后台切换过程中遇到的网络快速闪断问题,导致connect操作永久阻塞线程。通过记录连接时间来检测长连接是否被阻塞,并提供了一种临时解决方案。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

手机升级到ios9后这两天测试发现应用前后台切换并且网络快速闪断出现2次connect永远阻塞线程的问题。

在远程连接服务器前后收到网络异常通知,导致connect永远阻塞,进而线程阻塞。当然在进行连接前要判断是否有网络,若没有连接就别去连接了,当然若你连接时网络正常,在connect连接响应返回前网络异常了,就会出现被永远阻塞吧!
最好的解决方案是干掉这个僵死的线程。用了很多方法杀不死ios的阻塞线程。

暂时的解决方案:若发现长连接线程永远就另一个长连接线程。毕竟connect永远阻塞极少见。
发现connect永远阻塞的情况,可以通过在连接时存储当前时间。
连接函数响应时设置为0,当用户操作或获取到位置信息时发现这个全局时间非0并且和当前时间的差达到100秒时说明长连接线程永远阻塞了。

connect函数将激发TCP的三次握手过程,在连接建立成功或者出错时返回,出错可能是下列这种情况:
若TCP客户没有收到SYN分节的响应,则返回ETIMEOUT错误,,举例来说,调用connect函数时,4.4BSD内核发送一个SYN,若无响应6s后再发送一个,若仍然无响应则等待24s后再发送一个,若等待了75s仍未响应则返回本错误。

            //将打开的socket设为非阻塞的,可以用fcntl(socket, F_SETFL, O_NDELAY)完成, 若网络有问题会75秒返回结果
            fcntl((int)socket, F_SETFL, O_NDELAY);
//            if ((NotReachable == [self getNetworkStatus]) || (ReachableUnknown == [self getNetworkStatus]))
//            {
//                 sleep(3);
//                break;
//            }
            _connectTime = (long long)[[NSDate date] timeIntervalSince1970];
            FLDDLogDebug(@"_connectTime = %lld\n", _connectTime);
            if((NotReachable == [self getNetworkStatus]) || (ReachableUnknown == [self getNetworkStatus]))
            {
                close(server_sock_fd);
                self.socketConnectStat = SOCKECT_CONNECT_ABNORMAL;
                curDate = [NSDate date];
                nowTime = (long long)[curDate timeIntervalSince1970];
                frontHearTime = nowTime;
                sleep(3);
                 _connectTime = 0;
                goto SKIP;
            }

//            nowTime = (long)[[NSDate date] timeIntervalSince1970];

            int i = connect(server_sock_fd, (struct sockaddr *)&server_addr, sizeof(struct sockaddr_in));
            FLDDLogDebug(@"connect after _connectTime = %lld\n", (long long)[[NSDate date] timeIntervalSince1970]);
            _connectTime = 0;

长连接被永远被阻塞的日志:

015/10/19 12:08:36:127  SingleAsyncSocket.m:__40-[SingleAsyncSocket creatPushConnection]_block_invoke:1574 Debug:i= 0
2015/10/19 12:08:36:127  SingleAsyncSocket.m:__40-[SingleAsyncSocket creatPushConnection]_block_invoke:1579 Debug:ret2= 2
2015/10/19 12:08:36:127  SingleAsyncSocket.m:__40-[SingleAsyncSocket creatPushConnection]_block_invoke:1590 Debug:select 出错!
2015/10/19 12:08:36:127  SingleAsyncSocket.m:__40-[SingleAsyncSocket creatPushConnection]_block_invoke:1072 Debug:SKIP fd= 15
2015/10/19 12:08:36:127  Singleton.m:-[Singleton getLoginOrderStat]:224 Debug:函数
2015/10/19 12:08:36:130  SingleAsyncSocket.m:__40-[SingleAsyncSocket creatPushConnection]_block_invoke:1154 Debug:socket sucess 
2015/10/19 12:08:36:130  SingleAsyncSocket.m:__40-[SingleAsyncSocket creatPushConnection]_block_invoke:1155 Debug:g_fd= 9
2015/10/19 12:08:36:130  SingleAsyncSocket.m:__40-[SingleAsyncSocket creatPushConnection]_block_invoke:1160 Debug:main loop 
2015/10/19 12:08:36:131  Singleton.m:-[Singleton getLoginOrderStat]:224 Debug:函数
2015/10/19 12:08:36:131  SingleAsyncSocket.m:-[SingleAsyncSocket getNetworkStatus]:53 Debug:函数
2015/10/19 12:08:36:312  AppDelegate.m:-[AppDelegate applicationWillEnterForeground:]:426 Debug:函数
2015/10/19 12:08:36:313  Singleton.m:-[Singleton setBackgroundFlag:]:1001 Debug:函数
2015/10/19 12:08:36:313  SingleAsyncSocket.m:-[SingleAsyncSocket checkNetWork]:37 Debug:函数
2015/10/19 12:08:36:326  mainViewController.m:-[mainViewController ActiveRotationAnimationFromBackground]:813 Debug:函数
2015/10/19 12:08:36:326  NoticeCarView.m:-[NoticeCarView roteanmation]:31 Debug:函数
2015/10/19 12:08:36:360  SingleAsyncSocket.m:-[SingleAsyncSocket reachabilityDidChanged:]:945 Debug:函数
2015/10/19 12:08:36:360  SingleAsyncSocket.m:-[SingleAsyncSocket setNetworkStatus:]:59 Debug:函数
2015/10/19 12:08:36:360  SingleAsyncSocket.m:-[SingleAsyncSocket reachabilityDidChanged:]:949 Debug:handleNetChanged
2015/10/19 12:08:36:360  SingleAsyncSocket.m:-[SingleAsyncSocket reachabilityDidChanged:]:953 Info:收到网络异常通知,没有网络! 网络状态:0
2015/10/19 12:08:36:360  StartOrderViewController.m:-[StartOrderViewController reachabilityNotNet:]:137 Debug:函数
2015/10/19 12:08:36:360  mainViewController.m:-[mainViewController reachabilityNotNet:]:327 Debug:函数
2015/10/19 12:08:36:410  mainViewController.m:-[mainViewController mapView:didUpdateUserLocation:updatingLocation:]:1340 Debug:userLocation.coordinate latitude: 30.208424, longitude:120.219590, horizontalAccuracy:65.000000, speed:-1.000000
2015/10/19 12:08:36:512  mainViewController.m:-[mainViewController mapView:didUpdateUserLocation:updatingLocation:]:1340 Debug:userLocation.coordinate latitude: 30.206766, longitude:120.217200, horizontalAccuracy:1414.000000, speed:-1.000000
2015/10/19 12:08:36:726  mainViewController.m:-[mainViewController mapView:didUpdateUserLocation:updatingLocation:]:1340 Debug:userLocation.coordinate latitude: 30.208904, longitude:120.218935, horizontalAccuracy:65.000000, speed:-1.000000
2015/10/19 12:08:37:373  AppDelegate.m:-[AppDelegate applicationDidBecomeActive:]:444 Debug:函数
2015/10/19 12:08:37:373  AppDelegate.m:-[AppDelegate startSdkWith:appKey:appSecret:]:538 Debug:函数
2015/10/19 12:08:44:476  AppDelegate.m:-[AppDelegate applicationDidEnterBackground:]:416 Debug:函数
2015/10/19 12:08:44:478  Singleton.m:-[Singleton setBackgroundFlag:]:1001 Debug:函数
2015/10/19 12:08:44:478  Singleton.m:-[Singleton clearBackgroundChangeTime]:1029 Debug:函数
2015/10/19 12:08:49:513  mainViewController.m:-[mainViewController mapView:didUpdateUserLocation:updatingLocation:]:1340 Debug:userLocation.coordinate latitude: 30.209027, longitude:120.218747, horizontalAccuracy:65.000000, speed:-1.000000
2015/10/19 12:08:52:439  SingleAsyncSocket.m:-[SingleAsyncSocket reachabilityDidChanged:]:945 Debug:函数
2015/10/19 12:08:52:439  SingleAsyncSocket.m:-[SingleAsyncSocket setNetworkStatus:]:59 Debug:函数
2015/10/19 12:08:52:439  SingleAsyncSocket.m:-[SingleAsyncSocket reachabilityDidChanged:]:949 Debug:handleNetChanged
2015/10/19 12:08:52:440  SingleAsyncSocket.m:-[SingleAsyncSocket reachabilityDidChanged:]:959 Debug:收到网络正常通知。 网络状态:1
2015/10/19 12:08:52:440  StartOrderViewController.m:-[StartOrderViewController reachabilityRecove:]:151 Debug:函数
2015/10/19 12:08:52:440  mainViewController.m:-[mainViewController reachabilityRecove:]:336 Debug:函数
2015/10/19 12:08:52:576  SingleAsyncSocket.m:-[SingleAsyncSocket reachabilityDidChanged:]:945 Debug:函数
2015/10/19 12:08:52:576  SingleAsyncSocket.m:-[SingleAsyncSocket setNetworkStatus:]:59 Debug:函数
2015/10/19 12:08:52:577  SingleAsyncSocket.m:-[SingleAsyncSocket reachabilityDidChanged:]:949 Debug:handleNetChanged
2015/10/19 12:08:52:577  SingleAsyncSocket.m:-[SingleAsyncSocket reachabilityDidChanged:]:959 Debug:收到网络正常通知。 网络状态:1
2015/10/19 12:08:52:577  StartOrderViewController.m:-[StartOrderViewController reachabilityRecove:]:151 Debug:函数
2015/10/19 12:08:52:577  mainViewController.m:-[mainViewController reachabilityRecove:]:336 Debug:函数
2015/10/19 12:08:55:978  AppDelegate.m:-[AppDelegate applicationWillEnterForeground:]:426 Debug:函数
2015/10/19 12:08:55:978  Singleton.m:-[Singleton setBackgroundFlag:]:1001 Debug:函数
2015/10/19 12:08:55:978  SingleAsyncSocket.m:-[SingleAsyncSocket checkNetWork]:37 Debug:函数
2015/10/19 12:08:55:991  mainViewController.m:-[mainViewController ActiveRotationAnimationFromBackground]:813 Debug:函数
2015/10/19 12:08:55:991  NoticeCarView.m:-[NoticeCarView roteanmation]:31 Debug:函数
2015/10/19 12:08:56:017  SingleAsyncSocket.m:-[SingleAsyncSocket reachabilityDidChanged:]:945 Debug:函数
2015/10/19 12:08:56:018  SingleAsyncSocket.m:-[SingleAsyncSocket setNetworkStatus:]:59 Debug:函数
2015/10/19 12:08:56:018  SingleAsyncSocket.m:-[SingleAsyncSocket reachabilityDidChanged:]:949 Debug:handleNetChanged
2015/10/19 12:08:56:018  SingleAsyncSocket.m:-[SingleAsyncSocket reachabilityDidChanged:]:959 Debug:收到网络正常通知。 网络状态:1
2015/10/19 12:08:56:018  StartOrderViewController.m:-[StartOrderViewController reachabilityRecove:]:151 Debug:函数
2015/10/19 12:08:56:018  mainViewController.m:-[mainViewController reachabilityRecove:]:336 Debug:函数
2015/10/19 12:08:56:051  SingleAsyncSocket.m:-[SingleAsyncSocket reachabilityDidChanged:]:945 Debug:函数
2015/10/19 12:08:56:051  SingleAsyncSocket.m:-[SingleAsyncSocket setNetworkStatus:]:59 Debug:函数
2015/10/19 12:08:56:051  SingleAsyncSocket.m:-[SingleAsyncSocket reachabilityDidChanged:]:949 Debug:handleNetChanged
2015/10/19 12:08:56:051  SingleAsyncSocket.m:-[SingleAsyncSocket reachabilityDidChanged:]:959 Debug:收到网络正常通知。 网络状态:1
2015/10/19 12:08:56:051  StartOrderViewController.m:-[StartOrderViewController reachabilityRecove:]:151 Debug:函数
2015/10/19 12:08:56:051  mainViewController.m:-[mainViewController reachabilityRecove:]:336 Debug:函数
2015/10/19 12:08:57:177  AppDelegate.m:-[AppDelegate applicationDidBecomeActive:]:444 Debug:函数
2015/10/19 12:08:57:177  AppDelegate.m:-[AppDelegate startSdkWith:appKey:appSecret:]:538 Debug:函数
2015/10/19 12:08:59:252  mainViewController.m:-[mainViewController mapView:didUpdateUserLocation:updatingLocation:]:1340 Debug:userLocation.coordinate latitude: 30.209522, longitude:120.218383, horizontalAccuracy:126.952225, speed:-1.000000
2015/10/19 12:09:06:976  AppDelegate.m:-[AppDelegate applicationDidEnterBackground:]:416 Debug:函数
2015/10/19 12:09:06:976  Singleton.m:-[Singleton setBackgroundFlag:]:1001 Debug:函数
2015/10/19 12:09:06:976  Singleton.m:-[Singleton clearBackgroundChangeTime]:1029 Debug:函数
2015/10/19 12:09:08:164  mainViewController.m:-[mainViewController mapView:didUpdateUserLocation:updatingLocation:]:1340 Debug:userLocation.coordinate latitude: 30.209256, longitude:120.218757, horizontalAccuracy:165.000000, speed:-1.000000
2015/10/19 12:09:10:590  mainViewController.m:-[mainViewController mapView:didUpdateUserLocation:updatingLocation:]:1340 Debug:userLocation.coordinate latitude: 30.209046, longitude:120.218733, horizontalAccuracy:65.000000, speed:-1.000000
2015/10/19 12:09:26:551  mainViewController.m:-[mainViewController mapView:didUpdateUserLocation:updatingLocation:]:1340 Debug:userLocation.coordinate latitude: 30.208799, longitude:120.218951, horizontalAccuracy:65.000000, speed:-1.000000
2015/10/19 12:10:05:491  mainViewController.m:-[mainViewController mapView:didUpdateUserLocation:updatingLocation:]:1340 Debug:userLocation.coordinate latitude: 30.208579, longitude:120.218952, horizontalAccuracy:65.000000, speed:-1.000000
2015/10/19 12:10:18:377  mainViewController.m:-[mainViewController mapView:didUpdateUserLocation:updatingLocation:]:1340 Debug:userLocation.coordinate latitude: 30.208350, longitude:120.219238, horizontalAccuracy:65.000000, speed:-1.000000
2015/10/19 12:10:24:871  mainViewController.m:-[mainViewController mapView:didUpdateUserLocation:updatingLocation:]:1340 Debug:userLocation.coordinate latitude: 30.208137, longitude:120.219243, horizontalAccuracy:65.000000, speed:-1.000000
2015/10/19 12:10:37:797  mainViewController.m:-[mainViewController mapView:didUpdateUserLocation:updatingLocation:]:1340 Debug:userLocation.coordinate latitude: 30.208284, longitude:120.219028, horizontalAccuracy:65.000000, speed:-1.000000
2015/10/19 12:10:50:739  mainViewController.m:-[mainViewController mapView:didUpdateUserLocation:updatingLocation:]:1340 Debug:userLocation.coordinate latitude: 30.208358, longitude:120.219260, horizontalAccuracy:65.000000, speed:-1.000000
2015/10/19 12:10:52:030  AppDelegate.m:-[AppDelegate applicationWillEnterForeground:]:426 Debug:函数
2015/10/19 12:10:52:030  Singleton.m:-[Singleton setBackgroundFlag:]:1001 Debug:函数
<think>嗯,用户在使用WebSocket客户端的时候遇到了recv阻塞线程的问题,该怎么解决呢?首先,我需要回忆一下WebSocket的基本工作原理。WebSocket是一种全双工通信协议,客户端和服务器建立连接后可以互相发送数据。recv方法通常是用来接收数据的,但默认情况下是阻塞的,也就是说如果没有数据到达,序会一直停在那里等待,导致线程无法继续执行其他任务。 那用户为什么会遇到这个问题呢?可能的情况有很多。比如,用户可能在主线程中直接调用了recv,导致界面住或者序无法响应其他操作。这时候,用户需要一种方法来处理这种阻塞,让序能够同时处理其他任务或者及时响应用户输入。 接下来,我需要思考有哪些常见的解决方案。首先,多线程是一个常见的方法。把recv放在一个单独的线程里运行,这样主线程就不会被阻塞。不过,多线程可能会引入线程同步的问题,比如数据共享和资源竞争,需要小心处理。 然后是异步IO,比如Python中的asyncio库。使用异步的方式可以在单线程中处理多个任务,recv变成非阻塞的,通过事件循环来管理。这种方法更高效,但需要代码结构符合异步编的模式,可能需要对现有代码进行较大的修改。 设置超时也是一个办法。WebSocket库通常允许设置超时时间,这样recv在指定时间内没有收到数据就会抛出异常,从而避免无限阻塞。不过,这需要处理超时异常,并且可能无法及时收到数据,需要根据具体场景调整超时时间。 另外,检查连接状态也很重要。如果连接已经断开,recv可能会一直阻塞,所以需要在调用recv之前确认连接是否仍然有效。这可以通过捕获异常或者定期发送心跳包来维持连接。 具体到Python的websockets库,用户可能需要使用异步的接收方式,比如await websocket.recv(),这样在等待数据时不会阻塞事件循环。如果用户没有使用异步框架,可能需要考虑切换到异步模式,或者结合多线程来处理。 还需要考虑其他因素,比如网络稳定性。如果网络不好,数据接收延迟高,可能需要更的超时时间或者重连机制。此外,处理接收数据的方式也很重要,比如将数据放入队列供其他线程处理,或者使用回调函数来处理收到的消息。 用户可能还不太清楚这些方法的具体实现步骤,所以需要给出示例代码。比如,多线程的例子中,展示如何启动一个线程专门负责接收数据,主线程继续执行其他任务。异步的例子中,展示如何使用async和await来非阻塞地接收数据。 另外,可能有一些注意事项需要提醒用户。比如,线程安全的问题,在多个线程中操作同一个WebSocket连接时需要加锁;资源释放的问题,当连接关闭时,确保线程正确退出,避免资源泄漏;以及异常处理的重要性,确保任何可能的错误都被捕获并妥善处理,防止序崩溃。 总结一下,解决recv阻塞线程的问题主要有四种方法:多线程、异步IO、设置超时和检查连接状态。根据用户的具体应用场景和现有的代码结构,选择最合适的方法。同时,结合示例代码和注意事项,帮助用户更好地理解和实施解决方案。</think>好的,关于WebSocket客户端的`recv`阻塞线程问题,以下是分步解决方案: --- ### 问题分析 WebSocket的`recv()`方法默认会阻塞当前线程,直到接收到数据或连接关闭。若需同时处理其他任务(如UI响应、网络心跳等),需解决阻塞问题。 --- ### 解决方法 #### 1. **多线程模式** 将阻塞操作放在独立线程中,主线程不受影响。 ```python import threading import websockets def receive_thread(ws): while True: try: data = ws.recv() # 阻塞在此处 print("Received:", data) except websockets.exceptions.ConnectionClosed: break # 主线程中启动接收线程 async def main(): async with websockets.connect("ws://example.com") as ws: thread = threading.Thread(target=receive_thread, args=(ws,)) thread.start() # 主线程继续执行其他任务... ``` **注意事项**: - 需处理线程退出条件(如连接关闭时终止循环)。 - 多线程共享WebSocket对象时需加锁(如`threading.Lock`)。 --- #### 2. **异步IO模式(推荐)** 使用异步框架(如Python的`asyncio`),通过协阻塞等待数据。 ```python import asyncio import websockets async def listen(): async with websockets.connect("ws://example.com") as ws: while True: try: data = await ws.recv() # 异步等待,不阻塞事件循环 print("Received:", data) except websockets.exceptions.ConnectionClosed: break # 启动异步事件循环 asyncio.get_event_loop().run_until_complete(listen()) ``` **优势**: - 单线程处理多任务,资源占用更低。 - 天然避免线程同步问题。 --- #### 3. **设置接收超时** 通过设置超时时间,强制`recv()`在指定时间后抛出超时异常。 ```python import websockets async def receive_with_timeout(ws, timeout=5): try: data = await asyncio.wait_for(ws.recv(), timeout) print("Received:", data) except asyncio.TimeoutError: print("等待超时,继续其他操作...") ``` **适用场景**: - 需周期性检查其他任务(如发送心跳包)。 --- #### 4. **连接状态检查** 在调用`recv()`前,检查连接是否已关闭。 ```python async def listen(): async with websockets.connect("ws://example.com") as ws: while not ws.closed: try: data = await ws.recv() print("Received:", data) except websockets.exceptions.ConnectionClosed: break ``` --- ### 关键注意事项 1. **线程安全**:多线程操作同一WebSocket时,需通过锁机制避免竞争。 2. **资源释放**:连接关闭后,确保线程或协正确退出。 3. **异常处理**:捕获`ConnectionClosed`异常,避免因服务器断开导致序崩溃。 4. **心跳机制**:时间空闲时,定期发送Ping/Pong帧维持连接。 --- ### 总结 | 方法 | 适用场景 | 复杂度 | |-----------|---------------------------|-----| | 多线程 | 同步代码、简单逻辑 | 中 | | 异步IO | 高并发、需同时处理多任务 | 高 | | 设置超时 | 需周期性执行其他操作 | 低 | | 状态检查 | 避免无效等待 | 低 | 根据实际需求选择方案:异步模式性能最优,多线程更易集成到现有同步代码中。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值