天天看點

【C/S通信互動之Socket篇】Cocos2dx(Client)使用BSD Socket與Mina(Server)手機網遊通信架構!

實對于此篇算是對于這段時間網絡研究的一個總結。

對于手遊網絡通信的互動,一般情況下,Socket長連接配接直接使用Mina架構即可,對于Http短連接配接使用Servlet 入口即可(那麼對于後期将陸續更新Servlet博文)

那麼本篇主要介紹Socket長連接配接,當然與此配對的跨平台通信則選擇了BSD Socket,當然還有其他的,這裡隻說BSD Socket;

對于BSD Socket不是很熟悉的請自行google學習下,Himi需要提醒大家的是BSD Socket不是第三方類庫,而是UNIX/Linux系統中通用的網絡接口;

首先連接配接到Server端,這裡Himi簡單封裝一個函數提供大家使用;

     導入   #include <netdb.h>

兩個參數:1:IP位址  2:端口

其中有個socket成員變量:

int socketHandle = 0;

int HSocket::connect(const char* ip, unsigned short port){   

    struct sockaddr_in sa; 

    struct hostent* hp; 

    hp = gethostbyname(ip); 

    if(!hp){ 

        return -1; 

    } 

    memset(&sa, 0, sizeof(sa)); 

    memcpy((char*)&sa.sin_addr, hp->h_addr, hp->h_length); 

    sa.sin_family = hp->h_addrtype; 

    sa.sin_port = htons(port); 

    socketHandle = socket(sa.sin_family, SOCK_STREAM, 0); 

    if(socketHandle < 0){ 

        printf( "failed to create socket\n" ); 

    if(::connect(socketHandle, (sockaddr*)&sa, sizeof(sa)) < 0){ 

        printf( "failed to connect socket\n" ); 

        ::close(socketHandle); 

    CCLOG("Client connect OK ! IP: %s:%d ",ip,port); 

    return 0; 

兩點注意:

1. 對于bsd socket 的  ::connect()函數進行連接配接伺服器的時候會阻塞你的主線程,是以将Himi封裝好的connect()函數在另一個線程調用則是一個好的處理方式;否則一旦網絡比較差,你的遊戲就假死ing~ 悲劇;

    2. 對于線程我們直接使用 pThread 就可以了,那麼這裡Himi就給一個建立線程的例子吧:

定義一個線程成員變量:

pthread_t threadHimi;

然後Himi也為大家封裝一個函數:

int HSocket::threadStart(){ 

    int errCode = 0; 

    do{ 

        pthread_attr_t tAttr; 

        errCode = pthread_attr_init(&tAttr); 

        CC_BREAK_IF(errCode!=0) 

        errCode = pthread_attr_setdetachstate(&tAttr, PTHREAD_CREATE_DETACHED); 

        if (errCode!=0) { 

            pthread_attr_destroy(&tAttr); 

            break; 

        } 

        errCode = pthread_create(&threadHimi, &tAttr, thread_function, this); 

    }while (0); 

    return errCode; 

1)建立線程其實就是pthread_create()函數,但是上面這個函數其他内容則主要為你建立的線程設定為分離式;這裡 thread_function 是個函數;童鞋們對于pthread不太熟悉的請自行百度和google;

2)當然這裡Himi要提醒大家,pthread是c庫,不是c++庫,它要求是全局函數,是以得static的!

那麼連接配接到Server端之後我們就應該關心, BSD Socket  對于資料的發送和接收!

1.發送: send 函數:

           send(socketHandle,buffer,length,0)

socketHandle :  你已經連接配接的socket

buffer:發送的緩存資料

length:資料長度

2. 接收: recv 函數:

           recv(socketHandle, p, length, 0)

socketHandle  :  你已經連接配接的socket

p : 存放資料的容器

length:擷取伺服器資料的長度;

 注意:          

      1. 對于recv 函數的其中參數 length長度,大家務必要仔細,很清楚伺服器應該發來的資料長度,因為一旦recv函數執行,那麼不從Server端讀取出length長度就不會罷休的!

     2.  如果你的Server端是Java的,那麼要注意大端 ,小端的問題!Java屬于大端模式,c++屬于小端模式;(對于大小端不熟悉的,也請自行google,這裡仍舊不贅述) 是以:               Client->recv到資料後->資料轉換成小端               Client->send資料時->資料轉換成大端      這樣才能保證Java伺服器與cocos2dx的Client端正常互動;

-----上面一直在介紹Client端的知識,那麼下面簡單說下Server端Mina的相關知識吧------

其實對于Mina架構而言,功能強大使用簡單,我們不需要關心通信,而隻是需要關心資料的處理;當然對于資料的處理在Mina中最主要的就是取決于自定義的Decode 和 Encode,編碼解碼;

一般情況下定義好通信的資料結構,是比較關鍵的一點;

1. 比如一般資料都有資料頭的概念,其中資料頭用來辨別目前通信的資料的版本,辨別和真實資料的長度等等。(至于如何設計這個看大家自己的想法了);

2. 資料結構中更不能少的肯定還是協定号!根據協定号,用戶端和伺服器才能做同一件事情;

3. 當然其中我們還會使用MD5 或者 CRC等進行資料較驗等,對于MD5和CRC校驗不太熟悉的也請自行google = =。

定義好資料結構後,如同Client端與Server簽訂了合同,彼此遵循此結構進行互動;

Server端對于收發資料的處理其實在Mina中比較容易,通過Himi的Mina博文也可以清晰容易的懂得;但是如何能讓伺服器根據協定号找到對應的編碼解碼類去處理那麼才是重點;Himi這裡隻簡單提醒你建立一個抽象類;

OK,關于資料的存放,當然Himi這裡使用的Hibernate 的Annotation映射到Mysql中。比較輕松愉快~

      其實Himi以上說的雖然不是很詳細,比如Client端對于Server端資料的細節處理等等;但是大概的手機網遊架構和大家需要去掌握的知識點基本都沒有遺漏,隻要童鞋們對于文章中的所有知識點都了如指掌,OK。你Socket C/S手遊架構即可開工;

下面Himi放出一張近來對于Server端的成績圖:

(Client 端:cocos2dx  /  Server端:Mina)

Client  特點: 當伺服器端有資料發送給Client端,Client端自動将收到的資料索引到對應等待資料的類中;

Server 特點: 當用戶端有資料發送Server端,Server端 能自動識别找到對應的編碼解碼類;

<a href="http://www.himigame.com/wp-content/uploads/2012/02/12.png"></a>

本文轉自 xiaominghimi 51CTO部落格,原文連結:http://blog.51cto.com/xiaominghimi/969793,如需轉載請自行聯系原作者