zoukankan      html  css  js  c++  java
  • 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( "服务器启动成功!
    
    等待客户端的请求......
    
    " );
        }
        else 
        {
            printf( "服务器启动失败!
    
    请重新启动服务器!
    
    " );
        }
    
        //设置最大连接数(此连接并不等同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
    
    ", 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("服务器端受理了客户端的请求!
    
    ");
    
                    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
    ",sendrs);
                }
    
                //如果没有连接成功,则继续连接,直到服务端返回的信息告诉我们连接成功了
                if( !bIsConn )
                {
                    printf("连接服务器失败!
    ");
                    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 库

  • 相关阅读:
    网络中有三种通讯模式:单播、广播、组播(多播)
    chmod命令
    linux bash 命令重定向和多命令执行
    linux中管道符“|”的作用
    web测试常用的 linux 命令
    集群主要分成三大类 (高可用集群, 负载均衡集群,科学计算集群)
    iOS 监测电话呼入
    iOS NSUserDefaults [setValue:forKey:] [setObject:forKey:] <Objc> setValue(_,forKey:) set(_,forKey) <Swift 3>
    iOS 将navigationItem.titleView设置为自定义UISearchBar (Ficow实例讲解)
    iOS 加载Viewcontroller的几种方法
  • 原文地址:https://www.cnblogs.com/alenoscar/p/4354628.html
Copyright © 2011-2022 走看看