cocos2dx socket 通信

本文由qinning199原创,转载请注明:http://www.cocos2dx.net/?p=167


最近做一个联网实时交互的游戏,游戏中需要使用socket保持长连接,来保证客户端与服务器端进行实时交互。以下贴出自己的一些代码:

因为socket通信部分需要使用多线程,整个流程如下:

1、首先起一个线程,来进行socket通信的连接

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


2、连接socket代码:


[cpp]  view plain copy
  1. void* GameServer::connectSocket(void* args)  
  2. {  
  3.     connect("192.168.1.2""3343");  
  4.     return NULL;  
  5. }  

再此处进行socket连接,如果连接成功之后,将会通知主线程,连接已经成功,此处我们使用了cocos2dx高级开发教程中封装的MTNotificationQueue进行子线程向主线程的通信,如果你不了解,可以自己去百度

[cpp]  view plain copy
  1. int GameServer::connect(const char* 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.       
  7.     hp = gethostbyname(ip);  
  8.     if(!hp){  
  9.         return -1;  
  10.     }  
  11.     memset(&sa, 0, sizeof(sa));  
  12.     memcpy((char*)&sa.sin_addr, hp->h_addr, hp->h_length);  
  13.     sa.sin_family = hp->h_addrtype;  
  14.     sa.sin_port = htons(port);  
  15.       
  16.     m_socketHandle = socket(sa.sin_family, SOCK_STREAM, 0);  
  17.       
  18.     if(m_socketHandle < 0){  
  19.         printf( "failed to create socket\n" );  
  20.         return -1;  
  21.     }  
  22.     if(::connect(m_socketHandle, (sockaddr*)&sa, sizeof(sa)) < 0){  
  23.         printf( "failed to connect socket\n" );  
  24.         ::close(m_socketHandle);  
  25.         return -1;  
  26.     }  
  27.       
  28.     CCLOG("Client connect OK ! IP: %s:%d ",ip,port);  
  29.   
  30.     MTNotificationQueue::sharedNotificationQueue()->postNotification("connectok", NULL);  
  31.     return 0;  
  32. }  


3、通知主线程之后,主线程将会负责开启新的线程进行recv监听,监听服务器下发的数据

[cpp]  view plain copy
  1. void GameServer::initReceiveThread(CCObject* obj)  
  2. {  
  3.     int errCode = 0;  
  4.     pthread_attr_t tAttr;  
  5.     errCode = pthread_attr_init(&tAttr);  
  6.       
  7.     errCode = pthread_attr_setdetachstate(&tAttr, PTHREAD_CREATE_DETACHED);  
  8.       
  9.     if (errCode!=0) {  
  10.         pthread_attr_destroy(&tAttr);  
  11.     }else{  
  12.         errCode = pthread_create(&m_gameThread, &tAttr, listenSocketData, this);  
  13.     }  
  14.     if(errCode == 0){  
  15.         CCLOG("Receive Thread OK!!!");  
  16.     }else{  
  17.         CCLOG("Receive Thread Error!!!!");  
  18.     }  
  19.       
  20.     MTNotificationQueue::sharedNotificationQueue()->postNotification("jointable", NULL);  
  21. }  


开启socket通信接收函数

[cpp]  view plain copy
  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程序就完成了。

你可能感兴趣的:(cocos2dx socket 通信)