Raknet實現的簡單服務器與客戶端的交互


1. 首先下載Raknet的源代碼,我用的是4.0的,不是最新的,解壓后編譯DLL工程,編譯完成后進入解壓的根目錄下,進入Lib文件夾下找到RakNet_DLL_Debug_Win32.dll,  RakNet_DLL_Debug_Win32.lib這兩個庫文件,並將其關聯到工程中。

2. 將解壓目錄下Source文件夾下的資源也管理到你的工程中

進行完上面兩步就將網絡庫配置完成,下面便開始服務器端與客戶端的程序編寫

// 服務器端程序

#include <string>
#include <sstream>  
#include <iostream>
#include "raknet/RakPeerInterface.h"
#include "raknet/RakNetTypes.h"
#include "raknet/MessageIdentifiers.h" // RakNet自定義消息枚舉定義處 
#include "raknet/BitStream.h"  // RakNet消息包的Bit數據流 

#define MAX_CLIENTS 10
#define SERVER_PORT 60000
enum ChatMessagesDefine  
{// 自定義消息枚舉值,消息ID  
    MSG_CHATWORD = ID_USER_PACKET_ENUM + 1,   // 消息ID從RakNet定義的最后一個枚舉開始  
};  

// 服務器端程序
int _tmain(int argc, _TCHAR* argv[])
{
    // 給服務器端創建一個實例  
    RakNet::RakPeerInterface* pPeer = RakNet::RakPeerInterface::GetInstance();   
    if ( NULL == pPeer )  
    {  
        std::cout << "RakNet::RakPeerInterface::GetInstance() Error!" << std::endl << std::endl;  
        return -1;  
    }  
    else  
    {  
        std::cout << "--------- MyServer Init Success -----------" << std::endl << std::endl;  
    }  

    RakNet::Packet* pPacket;
    std::cout << "Start Server ......" << std::endl << std::endl;  
    //啟動服務器  
    pPeer->Startup( MAX_CLIENTS, &RakNet::SocketDescriptor( SERVER_PORT, 0 ), 1 );  

    //設置最大鏈接數  
    pPeer->SetMaximumIncomingConnections( MAX_CLIENTS );  

    //////////////////////////////////////////////////////////////////////////  
    while ( 1 )  
    {  
        for ( pPacket = pPeer->Receive(); pPacket; pPeer->DeallocatePacket( pPacket ), pPacket = pPeer->Receive() )  
        {  
            switch ( pPacket->data[0] )  
            {  
            case ID_REMOTE_DISCONNECTION_NOTIFICATION:  
                std::cout << "Another client has disconnected !" << std::endl;  
                break;  
            case ID_REMOTE_CONNECTION_LOST:  
                std::cout << "Another client has lost the connection !" << std::endl;  
                break;  
            case ID_REMOTE_NEW_INCOMING_CONNECTION:  
                std::cout << "Another client has connected !" << std::endl;  
                break;  

            case ID_CONNECTION_REQUEST_ACCEPTED: //  
                //{  
                //    std::cout << "Our connection request has been accepted !" << std::endl;  

                //    RakNet::BitStream bsOut;  
                //    bsOut.Write( ( RakNet::MessageID )MSG_CHATWORD );  
                //    bsOut.Write("Hello world");  
                //    pPeer->Send( &bsOut, HIGH_PRIORITY, RELIABLE_ORDERED, 0, pPacket->systemAddress, false );  
                //}  
                break; 

            case ID_NEW_INCOMING_CONNECTION:  
                {  
                    std::cout << "Our connection request has been accepted !" << std::endl;  

                    RakNet::BitStream bsOut;  
                    bsOut.Write( ( RakNet::MessageID )MSG_CHATWORD );  
                    bsOut.Write("Hello world ! I'm successed ! Congratulations !");  
                    pPeer->Send( &bsOut, HIGH_PRIORITY, RELIABLE_ORDERED, 0, pPacket->systemAddress, false );  
                }  
                std::cout << "A connection is incoming !" << std::endl;  
                break;  
            case ID_NO_FREE_INCOMING_CONNECTIONS:  
                std::cout << "The server is full !" << std::endl;  
                break;  
            case ID_DISCONNECTION_NOTIFICATION:  
                std::cout << "A client has disconnected !" << std::endl;  
                break;  
            case ID_CONNECTION_LOST:  
                std::cout << "A client lost the connection !" << std::endl;  
                break;  

                //用戶自定義數據包  
            case MSG_CHATWORD:  
                {  
                    RakNet::RakString rs;  
                    RakNet::BitStream bsIn( pPacket->data, pPacket->length, false );  
                    bsIn.IgnoreBytes( sizeof(RakNet::MessageID) );   
                    bsIn.Read( rs );  //提取字符串           
                    std::istringstream input_str(rs.C_String()); //存入字符串流  
                    double v, h;  
                    input_str >> v >> h; //提取想要的變量  
                    std::cout << v << "  " << h << std::endl; //打印結果  
                }  
                break;  

            default:  
                std::cout << "Message with identifier %i has arrived !" << pPacket->data[ 0 ] << std::endl;  
                break;  
            }  
        }  
    }  

    //////////////////////////////////////////////////////////////////////////  
    RakNet::RakPeerInterface::DestroyInstance( pPeer );  


    /*
    //創建一個實例
    RakNet::RakPeerInterface *server = RakNet::RakPeerInterface::GetInstance();

    //創建套接字描述,也就是指定一個通信端口(UDP無監聽)
    RakNet::SocketDescriptor socketDescriptor;
    socketDescriptor.port = 30050;

    //啟動服務器端
    bool b = server->Startup(2, &socketDescriptor, 1 )== RakNet::RAKNET_STARTED;

    //如果沒有報錯,服務端啟動成功了。
    RakAssert(b);

    if ( b )
    {
        printf( "服務器啟動成功!\n\n等待客戶端的請求......\n\n" );
    }
    else 
    {
        printf( "服務器啟動失敗!\n\n請重新啟動服務器!\n\n" );
    }

    //設置最大連接數(此連接並不等同TCP的連接!),這一步必須設置,否則會出現客戶端調用Connect失敗
    server->SetMaximumIncomingConnections(2);

    //接下來就是處理數據發送接收的部分了
    while( 1 )
    {
        RakNet::Packet * packet = server->Receive();
        if( packet )
        {
            switch( packet->data[0] ) 
            {
                //用戶自定義數據包的接收處理,此處顯示接到的數據包內容。其他消息的處理可以同樣用case語句
                case ID_USER_PACKET_ENUM:
                    printf("接收到自定義數據,內容: %s\n\n", packet->data );
                    break;
                default:
                    break;
            }
        }
    }
    */
    return 0;
}

// 客戶端程序

#include <string>
#include <sstream>  
#include <iostream>

#include "raknet/RakPeerInterface.h"
#include "raknet/RakNetTypes.h"
#include "raknet/MessageIdentifiers.h"
#include "raknet/BitStream.h"

#define MAX_CLIENTS 10  
#define SERVER_PORT 60000  

enum ChatMessagesDefine  
{// 自定義消息枚舉值,消息ID  
    MSG_CHATWORD = ID_USER_PACKET_ENUM + 1,        // 消息ID從RakNet定義的最后一個枚舉開始  
};  

// 客戶端程序
int _tmain(int argc, _TCHAR* argv[])
{
    double v = 1000.023;   
    double h = 10023.23;  
    RakNet::RakPeerInterface *peer = RakNet::RakPeerInterface::GetInstance();  

    RakNet::SocketDescriptor sd;  
    peer->Startup(1, &sd, 1);  

    // 作為客戶端連接,連接到主機ip地址和端口號  
    peer->Connect("127.0.0.1", SERVER_PORT, 0, 0);  
    

    float k = 0;  
    int i = 0;     
    for ( i = 0; i < 10; i++ )  
    {  
        // 給主機發送數據  
        RakNet::BitStream bsOut;  
        bsOut.Write( (RakNet::MessageID)MSG_CHATWORD );  
        std::ostringstream format_messege;  
        format_messege << v++ << " " << h++;  // 輸入信息到字符串流,用空格隔開,此處為飛行器速度高度V, h為double型      
        //      bsOut.Write("hello"); 
        std::string ss = format_messege.str(); // str()返回的是臨時對象
        bsOut.Write( ss.c_str() );  
        peer->Send( &bsOut, HIGH_PRIORITY, RELIABLE_ORDERED, 0, RakNet::UNASSIGNED_SYSTEM_ADDRESS, true );  
        Sleep( 500 );  
    }

    RakNet::Packet * packet;
    while( 1 ) 
    {
        packet = peer->Receive();
        if( packet )
        {
            // 當接收到的消息的第一個字節的數據為 ID_CONNECTION_REQUEST_ACCEPTED 才表示服務端接受了連接請求!!!
            if( packet->data[0] == MSG_CHATWORD )
            {
                RakNet::RakString rs;
                RakNet::BitStream bsIn( packet->data, packet->length, false );
                bsIn.IgnoreBytes(sizeof(RakNet::MessageID));
                bsIn.Read( rs );
                printf("server return = %s", rs.C_String() );
            }
        }
    }

    //斷開連接,這個會給對方發送一個消息,告訴它要斷開連接了。  
    peer->Shutdown( 300 );   

    RakNet::RakPeerInterface::DestroyInstance(peer);  

    /*
    RakNet::RakPeerInterface *client = RakNet::RakPeerInterface::GetInstance();

    RakNet::SocketDescriptor socketDescriptor;
    socketDescriptor.port = 0;

    client->Startup(1, &socketDescriptor, 1 );

    // 客戶端連接服務端,判斷返回值和RakNet::CONNECTION_ATTEMPT_STARTED是否相等,
    // 相等只是代表請求投遞成功,並不意味着服務端接收了連接請求
    bool rs = ( client->Connect("127.0.0.1", 30050, NULL, 0, 0) == RakNet::CONNECTION_ATTEMPT_STARTED );

    // 數據包
    RakNet::Packet *packet;

    bool bIsConn = false;

    // 循環接收來自服務端的消息
    while(1)
    {
        packet = client->Receive();
        if( packet )
        {
            // 當接收到的消息的第一個字節的數據為 ID_CONNECTION_REQUEST_ACCEPTED 才表示服務端接受了連接請求!!!
            if( packet->data[0] == ID_CONNECTION_REQUEST_ACCEPTED )
            {
                bIsConn = true;
                printf("服務器端受理了客戶端的請求!\n\n");

                char flag = (char)ID_USER_PACKET_ENUM;
                char buffer[ ] = "這是來自客戶端的消息";
                buffer[ 0 ] = flag;

                //連接ok后發送一個字符串到服務端
                uint32_t sendrs = client->Send( (const char*)buffer, 
                                                strlen(buffer)+1, 
                                                HIGH_PRIORITY, 
                                                RELIABLE_ORDERED, 
                                                0,
                                                RakNet::UNASSIGNED_SYSTEM_ADDRESS,
                                                true );
                printf("服務器端返回來的消息: %d\n",sendrs);
            }

            //如果沒有連接成功,則繼續連接,直到服務端返回的信息告訴我們連接成功了
            if( !bIsConn )
            {
                printf("連接服務器失敗!\n");
                client->Connect("127.0.0.1", 30050, NULL, 0, 0);
            }
        }
    }
    */
    system( "pause");
    return 0;
}

ps: 下面是將網絡庫關聯到你的工程中

1.右鍵工程--》屬性--》c/c++ --》常規--》"附加包含目錄",將源文件和上面的兩個文件包含進去

2.右鍵工程--》屬性--》鏈接器 --》常規--》"附加包含目錄",將源文件和上面的兩個文件包含進去

3.右鍵工程--》屬性--》鏈接器 --》輸入--》"附加依賴項",添加 RakNet_DLL_Debug_Win32.lib 庫

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM