WebSocket無法連接服務器時Simulator Crash

環境:OSX 10.12.4
版本:ccc 1.4.2

使用WebSocket連接 ws://127.0.0.1/ ,但是服務器未開啟時,模擬器直接崩潰

測試代碼如下…


let ws = new WebSocket( "ws://127.0.0.1:8080");
ws.onopen = function() { cc.log( '[ws] connected' ); };
ws.onmessage = function (evt)
{
   var msg = evt.data;
   cc.log( '[ws] received: ' + msg );
};
ws.onerror = function( evt ) { cc.log( '[ws] Error,' , JSON.stringify( evt ) ); };
ws.onclose = function() { cc.log( '[ws] Disconnected.' ) };

let retrySend = function()
{

   cc.log( '[ws] 開始判斷...' )
   if( ws && cc.sys.isObjectValid(ws) )
   {
      cc.log( '[ws] 有效的樣子, readyState: ' + ws.readyState );
      setTimeout( retrySend, 1000 );
   }
   else
   {
      cc.log( '[ws] 無法連接..' )
      setTimeout( retrySend, 1000 );
   }
}

retrySend();


看起來是只要判斷到 ws.readyState 就會Crash掉
想請問這個有方法可以解決嗎?

補充完整 Log


Process:               Simulator [17742]
Path:                  /Applications/Cocos/CocosCreator.app/Contents/Resources/cocos2d-x/simulator/mac/Simulator.app/Contents/MacOS/Simulator
Identifier:            com.cocos.apps.simulator
Version:               20170328
Code Type:             X86-64 (Native)
Parent Process:        CocosCreator [17340]
Responsible:           Simulator [17742]
User ID:               502

Date/Time:             2017-04-13 04:11:04.720 +0800
OS Version:            Mac OS X 10.12.4 (16E195)
Report Version:        12
Anonymous UUID:        A63A48F2-C3F2-BC34-A950-852176B784D0

Sleep/Wake UUID:       328007F5-D34B-4358-8100-80097AAA97E1

Time Awake Since Boot: 54000 seconds
Time Since Wake:       3500 seconds

System Integrity Protection: disabled

Crashed Thread:        0  Dispatch queue: com.apple.main-thread

Exception Type:        EXC_CRASH (SIGABRT)
Exception Codes:       0x0000000000000000, 0x0000000000000000
Exception Note:        EXC_CORPSE_NOTIFY

Application Specific Information:
abort() called
terminating with uncaught exception of type std::__1::system_error: mutex lock failed: Invalid argument

Thread 0 Crashed:: Dispatch queue: com.apple.main-thread
0   libsystem_kernel.dylib            0x00007fffa7c62d42 __pthread_kill + 10
1   libsystem_pthread.dylib           0x00007fffa7d505bf pthread_kill + 90
2   libsystem_c.dylib                 0x00007fffa7bc8420 abort + 129
3   libc++abi.dylib                   0x00007fffa671e84a abort_message + 266
4   libc++abi.dylib                   0x00007fffa6743c37 default_terminate_handler() + 243
5   libobjc.A.dylib                   0x00007fffa7251713 _objc_terminate() + 124
6   libc++abi.dylib                   0x00007fffa6740d69 std::__terminate(void (*)()) + 8
7   libc++abi.dylib                   0x00007fffa67407de __cxa_throw + 121
8   libc++.1.dylib                    0x00007fffa670e445 std::__1::__throw_system_error(int, char const*) + 77
9   com.cocos.apps.simulator          0x0000000102f6bfdd 0x1017bc000 + 24838109
10  com.cocos.apps.simulator          0x0000000101809ddd 0x1017bc000 + 318941
11  com.cocos.apps.simulator          0x000000010231fe70 0x1017bc000 + 11943536

Thread 1:
0   libsystem_kernel.dylib            0x00007fffa7c6344e __workq_kernreturn + 10
1   libsystem_pthread.dylib           0x00007fffa7d4d695 _pthread_wqthread + 1426
2   libsystem_pthread.dylib           0x00007fffa7d4d0f1 start_wqthread + 13

Thread 2:
0   libsystem_kernel.dylib            0x00007fffa7c6344e __workq_kernreturn + 10
1   libsystem_pthread.dylib           0x00007fffa7d4d695 _pthread_wqthread + 1426
2   libsystem_pthread.dylib           0x00007fffa7d4d0f1 start_wqthread + 13

Thread 3:
0   libsystem_kernel.dylib            0x00007fffa7c6344e __workq_kernreturn + 10
1   libsystem_pthread.dylib           0x00007fffa7d4d695 _pthread_wqthread + 1426
2   libsystem_pthread.dylib           0x00007fffa7d4d0f1 start_wqthread + 13

Thread 4:: com.apple.NSEventThread
0   libsystem_kernel.dylib            0x00007fffa7c5b34a mach_msg_trap + 10
1   libsystem_kernel.dylib            0x00007fffa7c5a797 mach_msg + 55
2   com.apple.CoreFoundation          0x00007fff923d24e4 __CFRunLoopServiceMachPort + 212
3   com.apple.CoreFoundation          0x00007fff923d1971 __CFRunLoopRun + 1361
4   com.apple.CoreFoundation          0x00007fff923d11c4 CFRunLoopRunSpecific + 420
5   com.apple.AppKit                  0x00007fff9001b2d2 _NSEventThread + 205
6   libsystem_pthread.dylib           0x00007fffa7d4d9af _pthread_body + 180
7   libsystem_pthread.dylib           0x00007fffa7d4d8fb _pthread_start + 286
8   libsystem_pthread.dylib           0x00007fffa7d4d101 thread_start + 13

Thread 5:
0   libsystem_kernel.dylib            0x00007fffa7c620c2 __accept + 10
1   com.cocos.apps.simulator          0x00000001021bf044 0x1017bc000 + 10498116
2   com.cocos.apps.simulator          0x00000001021cd02c void* std::__1::__thread_proxy<std::__1::tuple<void (*)(unsigned int), unsigned int> >(void*) + 428
3   libsystem_pthread.dylib           0x00007fffa7d4d9af _pthread_body + 180
4   libsystem_pthread.dylib           0x00007fffa7d4d8fb _pthread_start + 286
5   libsystem_pthread.dylib           0x00007fffa7d4d101 thread_start + 13

Thread 6:
0   libsystem_kernel.dylib            0x00007fffa7c6344e __workq_kernreturn + 10
1   libsystem_pthread.dylib           0x00007fffa7d4d695 _pthread_wqthread + 1426
2   libsystem_pthread.dylib           0x00007fffa7d4d0f1 start_wqthread + 13

Thread 7:
0   libsystem_kernel.dylib            0x00007fffa7c6344e __workq_kernreturn + 10
1   libsystem_pthread.dylib           0x00007fffa7d4d695 _pthread_wqthread + 1426
2   libsystem_pthread.dylib           0x00007fffa7d4d0f1 start_wqthread + 13

Thread 8:
0   libsystem_kernel.dylib            0x00007fffa7c6344e __workq_kernreturn + 10
1   libsystem_pthread.dylib           0x00007fffa7d4d502 _pthread_wqthread + 1023
2   libsystem_pthread.dylib           0x00007fffa7d4d0f1 start_wqthread + 13

Thread 9:

Thread 10:
0   libsystem_kernel.dylib            0x00007fffa7c62bf2 __psynch_cvwait + 10
1   libsystem_pthread.dylib           0x00007fffa7d4e86e _pthread_cond_wait + 712
2   libc++.1.dylib                    0x00007fffa66cd4cd std::__1::condition_variable::wait(std::__1::unique_lock<std::__1::mutex>&) + 47
3   com.cocos.apps.simulator          0x0000000102e71b66 0x1017bc000 + 23812966
4   com.cocos.apps.simulator          0x0000000102e809f4 void* std::__1::__thread_proxy<std::__1::tuple<void (cocos2d::TextureCache::*)(), cocos2d::TextureCache*> >(void*) + 532
5   libsystem_pthread.dylib           0x00007fffa7d4d9af _pthread_body + 180
6   libsystem_pthread.dylib           0x00007fffa7d4d8fb _pthread_start + 286
7   libsystem_pthread.dylib           0x00007fffa7d4d101 thread_start + 13

Thread 0 crashed with X86 Thread State (64-bit):
  rax: 0x0000000000000000  rbx: 0x0000000000000006  rcx: 0x00007fff5e43e2d8  rdx: 0x0000000000000000
  rdi: 0x0000000000000307  rsi: 0x0000000000000006  rbp: 0x00007fff5e43e300  rsp: 0x00007fff5e43e2d8
   r8: 0x00007fffa7bf1650   r9: 0x00007fffa7bb3a50  r10: 0x0000000008000000  r11: 0x0000000000000206
  r12: 0x00007fff5e43e460  r13: 0x0000000000000030  r14: 0x00007fffb0a463c0  r15: 0x0000000000000008
  rip: 0x00007fffa7c62d42  rfl: 0x0000000000000206  cr2: 0x00007fffb0a28128
  
Logical CPU:     0
Error Code:      0x02000148
Trap Number:     133

補充一下額外遇到的狀況,
若把上面的代碼,修改如下…

//在error時將ws對象設置為null
ws.onerror = function( evt )
{
    ws = null;
}

//在retrySend中,重新建立ws
let retrySend = function()
{
   cc.log( '[ws] 開始判斷...' )
   if( ws && cc.sys.isObjectValid(ws) )
   {
      cc.log( '[ws] 有效的樣子, readyState: ' + ws.readyState );
      setTimeout( retrySend, 1000 );
   }
   else
   {
      cc.log( '[ws] 無法連接...重新建立ws...' );
      ws = new WebSocket( "ws://127.0.0.1:8080");
      setTimeout( retrySend, 1000 );
   }
}

改成以上這樣的話,在Simulator中就不會Crash了,

但是,在Android真機上,
會造成 當遊戲進入後台 cc.game.on( EVENT_HIDE, function(){ cc.game.pause(); } );
就沒有辦法再回到回遊戲裡,最後整個遊戲就Crash了

@dumganhar 大神,能幫忙看看嗎?

如果服务端未打开websocket服务器,会触发onerror和onclose回调,只要这两个回调被调用了,就不应该再继续使用之前new出来的WebSocket实例了。第二种使用方式是正确的。

1赞

謝謝 @dumganhar 大神的回覆,

了解,我會改成第二種寫法,

那麼請教當程序進入後台之後,WebSocket 還會在背景運作嗎?

測試時的狀選,一直讓WebSocket重試,
然後當屏幕暗了一陣子之後,再打開手機,畫面就會一直是黑的,直到崩潰。

有什麼樣的寫法可以避免這種問題嗎?

进入后台后是否有触发onerror或者onclose事件?如果有,切换前台后,也不能在用之前的ws实例的。需要重新new一个。

1赞

了解了,再次謝謝大神

我會改成在Hide時先銷毀ws對象
Show的時候再重建,
並且也監看onerror和onclose事件,

謝謝 :slight_smile: