1. 程式人生 > >cocos2d-x的socket多執行緒通訊

cocos2d-x的socket多執行緒通訊

http://blog.csdn.net/qinning199/article/details/17569273

最近做一個聯網實時互動的遊戲,遊戲中需要使用socket保持長連線,來保證客戶端與伺服器端進行實時互動。以下貼出自己的一些程式碼:

因為socket通訊部分需要使用多執行緒,整個流程如下:

1、首先起一個執行緒,來進行socket通訊的連線

  1. int GameServer::connectThreadStart(){  
  2. //    connect(GAMESERVER, CCString::create(GAMESERVER_PORT)->intValue());
  3.     int
     errCode = 0;  
  4.     do{  
  5.         pthread_attr_t tAttr;  
  6.         errCode = pthread_attr_init(&tAttr);  
  7.         CC_BREAK_IF(errCode!=0);  
  8.         errCode = pthread_attr_setdetachstate(&tAttr, PTHREAD_CREATE_DETACHED);  
  9.         if (errCode!=0) {  
  10.             pthread_attr_destroy(&tAttr);  
  11.             break;  
  12.         }  
  13.         errCode = pthread_create(&m_gameThread, &tAttr, connectSocket, this);  
  14.     }while (0);  
  15.     return errCode;  
  16. }  


2、連線socket程式碼:

  1. void* GameServer::connectSocket(void* args)  
  2. {  
  3.     connect("192.168.1.2""3343");  
  4.     return NULL;  
  5. }  

再此處進行socket連線,如果連線成功之後,將會通知主執行緒,連線已經成功,此處我們使用了cocos2dx高階開發教程中封裝的MTNotificationQueue進行子執行緒向主執行緒的通訊,如果你不瞭解,可以自己去百度
  1. int GameServer::connect(constchar* ip, unsigned int port)  
  2. {  
  3.     CCLOG("Client begin connect IP: %s:%d ",ip,port);  
  4.     struct sockaddr_in sa;  
  5.     struct hostent* hp;  
  6.     hp = gethostbyname(ip);  
  7.     if(!hp){  
  8.         return -1;  
  9.     }  
  10.     memset(&sa, 0, sizeof(sa));  
  11.     memcpy((char*)&sa.sin_addr, hp->h_addr, hp->h_length);  
  12.     sa.sin_family = hp->h_addrtype;  
  13.     sa.sin_port = htons(port);  
  14.     m_socketHandle = socket(sa.sin_family, SOCK_STREAM, 0);  
  15.     if(m_socketHandle < 0){  
  16.         printf( "failed to create socket\n" );  
  17.         return -1;  
  18.     }  
  19.     if(::connect(m_socketHandle, (sockaddr*)&sa, sizeof(sa)) < 0){  
  20.         printf( "failed to connect socket\n" );  
  21.         ::close(m_socketHandle);  
  22.         return -1;  
  23.     }  
  24.     CCLOG("Client connect OK ! IP: %s:%d ",ip,port);  
  25.     MTNotificationQueue::sharedNotificationQueue()->postNotification("connectok", NULL);  
  26.     return 0;  
  27. }  


3、通知主執行緒之後,主執行緒將會負責開啟新的執行緒進行recv監聽,監聽伺服器下發的資料
  1. void GameServer::initReceiveThread(CCObject* obj)  
  2. {  
  3.     int errCode = 0;  
  4.     pthread_attr_t tAttr;  
  5.     errCode = pthread_attr_init(&tAttr);  
  6.     errCode = pthread_attr_setdetachstate(&tAttr, PTHREAD_CREATE_DETACHED);  
  7.     if (errCode!=0) {  
  8.         pthread_attr_destroy(&tAttr);  
  9.     }else{  
  10.         errCode = pthread_create(&m_gameThread, &tAttr, listenSocketData, this);  
  11.     }  
  12.     if(errCode == 0){  
  13.         CCLOG("Receive Thread OK!!!");  
  14.     }else{  
  15.         CCLOG("Receive Thread Error!!!!");  
  16.     }  
  17.     MTNotificationQueue::sharedNotificationQueue()->postNotification("jointable", NULL);  
  18. }  


開啟socket通訊接收函式
  1. void* GameServer::listenSocketData(void* obj)  
  2. {  
  3.     byte buffer[5];  
  4.     string contents;  
  5.     int ret = 0;  
  6.     // 先接受4位元組,獲取服務返回長度
  7.     bool rs = true;  
  8.     while(rs)  
  9.     {  
  10.         contents = "";  
  11.         ret = recv(m_socketHandle,buffer,4,0);  
  12.         // 伺服器關閉
  13.         if(ret == 0)  
  14.         {  
  15. //            CCLog("Error: server close");
  16.             rs = false;  
  17.         }  
  18.         if(ret == 4)  
  19.         {  
  20.             buffer[4]='\0';  
  21.             int packetlen = Utils::bytes2int(buffer);  
  22.             CCLOG("packetlen %d",packetlen);  
  23.             char buf[packetlen];  
  24.             int rets = 0;  
  25.             while((ret = recv(m_socketHandle,buf,packetlen-rets,0))>0)  
  26.             {  
  27.                 contents.append(buf,ret);  
  28.                 packetlen-=ret;  
  29.                 if(packetlen<=0)  
  30.                     break;  
  31.             }  
  32.             CCLog("recv content:%s\n",contents.c_str());  
  33.             CCString* str = CCString::create(Utils::getUnPackMsg(contents));  
  34.             MTNotificationQueue::sharedNotificationQueue()->postNotification("receivedata", str);  
  35.         }else {  
  36.             CCLog("Error: recv data Error %d",ret);  
  37.         }  
  38.     }  
  39.     return NULL;  
  40. }  



因為我們的cocos2dx客戶端與伺服器端約定,傳送的前四個位元組作為傳送內容的位元組長度,因此首先接收前四個位元組,至此,一個多執行緒socket程式就完成了。