C# Udp協議 RakNet C-Sharp

RakNet

RakNet是一個基於UDP網絡傳輸協議的C++網絡庫,允許程序員在他們自己的程序中實現高效的網絡傳輸服務。通常情況下用於遊戲.

 

個人編程環境 vs2017 /net4.5.1/C#

dll 引用

用到兩個文件:RakNetDotNet.dll 和 RakNet.dll

RakNet庫  https://github.com/OculusVR/RakNet

c#包裝:https://github.com/RainsSoft/RakNet-C-Sharp-binding-project

c#包裝項目名稱: RakNet-C-Sharp-binding-project-master
    0.RakNet.dll 有兩個 x86 和x64 版本 編譯調試時要區分
    1.RakNetDotNet.dll 和 RakNet.dll 放到項目文件夾裏
    2,Solution Explorer => 右鍵 References  => add References => Browse => RakNetDotNet.dll => ok button
  //  3.RakNet.dll 拖到 Solution Explorer 窗口的=>項目名字上
    4.調試或者編譯運行時,先複製 RakNet.dll和RakNetDotNet.dll 文件 到 exe文件夾內

自己的封裝

通過我的自己的封裝一下.

Send方法中沒有ip地址參數的,都是發給默認連接中的第一個

 connect 後,通過建立一個線程 後臺執行 Rev ,不停解包 Packet

用包(Packet)的第一個字節(byte)表明包的類型(DefaultMessageIDTypes),而1個字節(byte)最多表示256種不同的狀態
byte byte_ = Packet.data[0];
DefaultMessageIDTypes type =   (DefaultMessageIDTypes)byte_;

寫入的時候       

BitStream bitStream = new BitStream();
bitStream.Write((byte)DefaultMessageIDTypes);
bitStream.Write(message);
Send(bitStream, PacketPriority.HIGH_PRIORITY, PacketReliability.RELIABLE_ORDERED, (char)0, SystemAddress地址, true);

讀取

BitStream receiveBitStream;
receiveBitStream.Reset();
receiveBitStream.Write(date.p.data, date.p.length);
receiveBitStream.IgnoreBytes(1);
receiveBitStream.Read(out date.message); 

 

server

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading;
using RakNet;
public class RakNetServe
{
    public RakNetClient_Date date;
    private RakNetServe() { }
    public RakNetServe(string serverPort)
    {
        date.serverPort = serverPort;
    }
    public void Init_Date()
    {
        date.ServeIp = "0"; //不需要
        date.Rumpelstiltskin = "Rumpelstiltskin"; //Password
        date.socketFamily = 2; // use IPv6 =  23,Ipv4 =2
        date.MAXIMUM_NUMBER_OF_INTERNAL_IDS = 10;
        date.rss = new RakNetStatistics();
        date.server = RakPeerInterface.GetInstance();
        date.server.SetIncomingPassword(date.Rumpelstiltskin, date.Rumpelstiltskin.Length);
        date.server.SetTimeoutTime(30000, RakNet.RakNet.UNASSIGNED_SYSTEM_ADDRESS);
        date.server.SetMaximumIncomingConnections(4);
        //  System.Threading.Thread.Sleep(1000);
        date.server.SetOccasionalPing(true);
        date.server.SetUnreliableTimeout(1000);
        date.isServer = true;
        date.p = new Packet();
        date.receiveBitStream = new BitStream();
        date.clientID = RakNet.RakNet.UNASSIGNED_SYSTEM_ADDRESS;
        date.isCONNECTION_ATTEMPT_STARTED = true;
        date.socketDescriptor = new SocketDescriptor(Convert.ToUInt16(date.serverPort), date.ServeIp);
        date.socketDescriptor.port = Convert.ToUInt16(date.serverPort);
        date.socketDescriptor.socketFamily = date.socketFamily;
        date.isInit = true;
    }
    public void Ban(string ip)
    {
        Console.WriteLine("'Enter IP to ban.  You can use * as a wildcard");
        date.server.AddToBanList(ip);
        Console.WriteLine("IP " + ip + " added to ban list.");
    }
    public void Kick()
    {
        date.server.CloseConnection(date.clientID, true, 0);
    }
    public List<SystemAddress> GetConnectionList()
    {
        SystemAddress[] systems = new SystemAddress[10];
        ushort numCons = 10;
        date.server.GetConnectionList(out systems, ref numCons);
        for (int i = 0; i < numCons; i++)
        {
            Console.WriteLine((i + 1).ToString() + ". " + systems[i].ToString(true));
        }
        return systems.ToList();
    }
    public void Close()
    {
        date.Rev_Thread?.Abort();
        date.server?.Shutdown(300);
        RakPeerInterface.DestroyInstance(date.server);
        date.isConnectFuncRuned = false;
        date.isInit = false;
        date.currDebugString = ("server close");
    }
    public void Send(string message)
    {
        date.server.Send(message, message.Length + 1, PacketPriority.HIGH_PRIORITY, PacketReliability.RELIABLE_ORDERED, (char)0, RakNet.RakNet.UNASSIGNED_SYSTEM_ADDRESS, true);
        date.currDebugString = "\r\nTo:" + date.server.GetExternalID(RakNet.RakNet.UNASSIGNED_SYSTEM_ADDRESS) + "|" + "\r\nSend:" + message + "\r\n" + date.currTime;
    }
    public void Send(BitStream bitStream)
    {
        date.message = Encoding.UTF8.GetString(bitStream.GetData().ToList().Skip(1).ToArray());
        date.server.Send(bitStream, PacketPriority.HIGH_PRIORITY, PacketReliability.RELIABLE_ORDERED, (char)0, RakNet.RakNet.UNASSIGNED_SYSTEM_ADDRESS, true);
        date.currDebugString = "\r\nTo:" + date.server.GetExternalID(RakNet.RakNet.UNASSIGNED_SYSTEM_ADDRESS) + "|" + "\r\nSend:" + date.message + "\r\n" + date.currTime;
    }
    public void Send(string message,SystemAddress systemAddress)
    {
        date.server.Send(message, message.Length + 1, PacketPriority.HIGH_PRIORITY, PacketReliability.RELIABLE_ORDERED, (char)0, date.server.GetExternalID(systemAddress), true);
        date.currDebugString = "\r\nTo:" + date.server.GetExternalID(systemAddress) + "\r\nSend:" + message + "\r\n" + date.currTime;
    }
    public void Send(string message, SystemAddress systemAddress, DefaultMessageIDTypes type)
    {
        BitStream bitStream = new BitStream();
        bitStream.Write((byte)type);
        bitStream.Write(message);
        date.server.Send(bitStream, PacketPriority.HIGH_PRIORITY, PacketReliability.RELIABLE_ORDERED, (char)0, date.server.GetExternalID(systemAddress), true);
        date.currDebugString = "\r\nTo:" + date.server.GetExternalID(systemAddress) + "\r\nSend:" + message + "\r\n" + date.currTime;
    }
    /// <summary>
    /// 發送指定類型的數據包
    /// </summary>
    /// <param name="message"></param>
    /// <param name="type"></param>
    public void Send(string message, DefaultMessageIDTypes type)
    {
        BitStream bitStream = new BitStream();
        bitStream.Write((byte)type);
        bitStream.Write(message);
        Send(bitStream);
    }
    /// <summary>
    /// 統計信息
    /// </summary>
    public string Stat()
    {
        date. rss = date.server.GetStatistics(date.server.GetSystemAddressFromIndex(0));
        RakNet.RakNet.StatisticsToString(date.rss, out date.message, 2);
        date.currDebugString = date.message;
        return date.message;
        /*
        Actual bytes per second sent         0
        Actual bytes per second received     0
        Message bytes per second sent        0
        Message bytes per second resent      0
        Message bytes per second pushed      0
        Message bytes per second returned    0
        Message bytes per second ignored     0
        Total bytes sent                     0
        Total bytes received                 0
        Total message bytes sent             0
        Total message bytes resent           0
        Total message bytes pushed           0
        Total message bytes returned         0
        Total message bytes ignored          0
        Messages in send buffer, by priority 0,0,0,0
        Bytes in send buffer, by priority    0,0,0,0
        Messages in resend buffer            0
        Bytes in resend buffer               0
        Current packetloss                   0.0 %
        Average packetloss                   0.0 %
        Elapsed connection time in seconds   24542
        */
    }
    public void Connect()
    {
        if (date.isInit == false)
        {
            Init_Date();
        }
        date.startupResult = date.server.Startup(4, date.socketDescriptor, 1);
        //maxConnections 遊戲的最大玩家數
        //創建一個或多個sockets,這個使用socketDescriptors參數描述的變量
        if (date.startupResult != StartupResult.RAKNET_STARTED)
        {
            date.currDebugString = "Error starting server";
        }
        date.currDebugString = "server starting ...";
        date.currDebugString = "Listen ... Port: [" + date.serverPort + "]";
        for (int i = 0; i < date.server.GetNumberOfAddresses(); i++)
        {
            SystemAddress sa = date.server.GetInternalID(RakNet.RakNet.UNASSIGNED_SYSTEM_ADDRESS, i);
            date.currDebugString = (i + 1).ToString() + ". " + sa.ToString() + "(LAN = " + sa.IsLANAddress() + ")";
        }
        date.currDebugString = ("My GUID is " + date.server.GetGuidFromSystemAddress(RakNet.RakNet.UNASSIGNED_SYSTEM_ADDRESS).ToString());
        if (date.Rev_Thread != null)
        {
            date.Rev_Thread.Abort();
        }
        date.Rev_Thread = new Thread(Rev);
        date.Rev_Thread.Start();
        date.isConnected = true;
        date.isConnectFuncRuned = true;
    }
    void Rev()
    {
        while (true)
        {
            System.Threading.Thread.Sleep(30);
            for (date.p = date.server.Receive(); date.p != null; date.server.DeallocatePacket(date.p), date.p = date.server.Receive())
            {
                date.packetIdentifier = GetPacketIdentifier(date.p);
                date.currDefaultMessageIdTypes = (DefaultMessageIDTypes) date.packetIdentifier;
                switch (date.currDefaultMessageIdTypes)
                {
                    case DefaultMessageIDTypes.ID_DISCONNECTION_NOTIFICATION:
                        date.currDebugString = ("ID_DISCONNECTION_NOTIFICATION from " + date.p.systemAddress.ToString(true));
                        break;
                    case DefaultMessageIDTypes.ID_NEW_INCOMING_CONNECTION:
                        date.currDebugString = ("ID_NEW_INCOMING_CONNECTION from " + date.p.systemAddress.ToString(true) + "with GUID " + date.p.guid.ToString());
                        date.currDebugString = (System.Text.Encoding.UTF8.GetString(date.p.data));
                        date.clientID = date.p.systemAddress;
                        date.currDebugString = ("Remote internal IDs: ");
                        if (date.NewPlayerConnect != null) date.NewPlayerConnect(date.p.systemAddress);
                        for (int index = 0; index < date.MAXIMUM_NUMBER_OF_INTERNAL_IDS; index++)
                        {
                            SystemAddress internalId = date.server.GetInternalID(date.p.systemAddress, index);
                            if (internalId != RakNet.RakNet.UNASSIGNED_SYSTEM_ADDRESS)
                            {
                                date.currDebugString = ((index + 1).ToString() + ". " + internalId.ToString(true));
                            }
                        }
                        break;
                    case DefaultMessageIDTypes.ID_INCOMPATIBLE_PROTOCOL_VERSION:
                        date.currDebugString = ("ID_INCOMPATIBLE_PROTOCOL_VERSION");
                        break;
                    case DefaultMessageIDTypes.ID_CONNECTED_PING:
                    case DefaultMessageIDTypes.ID_UNCONNECTED_PING:
                        date.currDebugString = ("Ping from " + date.p.systemAddress.ToString(true));
                        break;
                    case DefaultMessageIDTypes.ID_CONNECTION_LOST:
                        date.currDebugString = ("ID_CONNECTION_LOST from " + date.p.systemAddress.ToString(true));
                        if (date.PlayerConnectLost != null) date.PlayerConnectLost(date.p.systemAddress);
                        break;
                    case DefaultMessageIDTypes.ID_USER_PACKET_ENUM:
                        date.receiveBitStream.Reset();
                        date.receiveBitStream.Write(date.p.data, date.p.length);
                        date.receiveBitStream.IgnoreBytes(1);
                        date.receiveBitStream.Read(out date.message);
                        date.currDebugString = "\r\nBy " + date.p.systemAddress.ToString() +
                                               " Rev msg \r\nDefaultMessageIdTypes: " +
                                               Enum.GetName(typeof(DefaultMessageIDTypes), date.currDefaultMessageIdTypes) +
                                               "\r\n" + date.currTime +
                                               "\r\n" + date.currTime +
                                               "\r\nMsg:" + date.message;
                        break;
                    default:
                        date.message = Encoding.UTF8.GetString(date.p.data);
                        if (date.Rev_Msg != null) date.Rev_Msg(date.message);
                        date.currDebugString = "\r\nBy " + date.p.systemAddress.ToString() +
                                               " Rev msg \r\nDefaultMessageIdTypes: " +
                                               Enum.GetName(typeof(DefaultMessageIDTypes), date.currDefaultMessageIdTypes) +
                                               "\r\n" + date.currTime +
                                               "\r\nMsg:" + date.message;
                        Send("i Rev Msg:[" +date.message+"]");
                        break;
                }
            }
        }
    }
    private static byte GetPacketIdentifier(Packet p)
    {
        if (p == null)
            return 255;
        byte buf = p.data[0];
        if (buf == (char)DefaultMessageIDTypes.ID_TIMESTAMP)
        {
            return (byte)p.data[5];
        }
        else
            return buf;
    }
}

client 

using System;
using System.Linq;
using System.Text;
using System.Threading;
using RakNet;
public class RakNetClient
{
    public RakNetClient_Date date;
    private static bool _isActive;
    public bool isActive
    {
        get
        {
            if (date.client == null)
                return false;
            if (date.isInit && date.isConnectFuncRuned && date.isConnected)
            {
                _isActive = date.client.IsActive();//C++ dll  需要靜態變量來接受
                return _isActive;
            }
            return false;
        }
    }
    public RakNetClient(string ServeIp, string serverPort)
    {
        date.ServeIp = ServeIp;
        date.serverPort = serverPort;
    }
    public void Init_Date()
    {
        //作爲客戶端時,就使用0表示使用系統自動分配
        date.clientIp = "0";
        date.clientPort = "0";
        date.isServer = false;
        date.socketFamily = 2;  // use IPv6 =23,Ipv4 =2
        date.Rumpelstiltskin = "Rumpelstiltskin"; //Password
        date.client = RakPeerInterface.GetInstance();
        date.rss = new RakNetStatistics();
        date.clientID = RakNet.RakNet.UNASSIGNED_SYSTEM_ADDRESS;
        date.isCONNECTION_ATTEMPT_STARTED = true;
        date.socketDescriptor = new SocketDescriptor(Convert.ToUInt16(date.clientPort), date.clientIp);
        date.socketDescriptor.socketFamily = date.socketFamily;
        date.client.Startup(8, date.socketDescriptor, 1);
        date.client.SetOccasionalPing(true);
        date.receiveBitStream = new BitStream();
        date.p = new Packet();
        date.isInit = true;
    }
    void ConnectFail()
    {
        date.isConnected = false;
        if (date.Connect_Fail != null)
            date.Connect_Fail();
    }
    void Rev()
    {
        while (true)
        {
            Thread.Sleep(30);
            for (date.p = date.client.Receive(); date.p != null; date.client.DeallocatePacket(date.p), date.p = date.client.Receive())
            {
                date.packetIdentifier = GetPacketIdentifier(date.p);
                date.currDefaultMessageIdTypes = (DefaultMessageIDTypes)date.packetIdentifier;
                switch (date.currDefaultMessageIdTypes)
                {
                    case DefaultMessageIDTypes.ID_DISCONNECTION_NOTIFICATION:
                        date.currDebugString = ("ID_DISCONNECTION_NOTIFICATION");
                        ConnectFail();
                        break;
                    case DefaultMessageIDTypes.ID_ALREADY_CONNECTED:
                        date.currDebugString = ("ID_ALREADY_CONNECTED with guid " + date.p.guid);
                        break;
                    case DefaultMessageIDTypes.ID_INCOMPATIBLE_PROTOCOL_VERSION:
                        date.currDebugString = ("ID_INCOMPATIBLE_PROTOCOL_VERSION ");
                        break;
                    case DefaultMessageIDTypes.ID_REMOTE_DISCONNECTION_NOTIFICATION:
                        date.currDebugString = ("ID_REMOTE_DISCONNECTION_NOTIFICATION ");
                        break;
                    case DefaultMessageIDTypes.ID_REMOTE_CONNECTION_LOST: // Server telling the date.clients of another date.client disconnecting forcefully.  You can manually broadcast this in a peer to peer enviroment if you want.
                        date.currDebugString = ("ID_REMOTE_CONNECTION_LOST");
                        ConnectFail();
                        break;
                    case DefaultMessageIDTypes.ID_CONNECTION_BANNED: // Banned from this server
                        date.currDebugString = ("We are banned from this server.\n");
                        break;
                    case DefaultMessageIDTypes.ID_CONNECTION_ATTEMPT_FAILED:
                        date.currDebugString = ("Connection attempt failed ");
                        ConnectFail();
                        break;
                    case DefaultMessageIDTypes.ID_NO_FREE_INCOMING_CONNECTIONS:
                        date.currDebugString = ("Server is full ");
                        break;
                    case DefaultMessageIDTypes.ID_INVALID_PASSWORD:
                        date.currDebugString = ("ID_INVALID_PASSWORD\n");
                        break;
                    case DefaultMessageIDTypes.ID_CONNECTION_LOST:
                        ConnectFail();
                        // Couldn't deliver a reliable packet - i.e. the other system was abnormally
                        // terminated
                        date.currDebugString = ("ID_CONNECTION_LOST\n");
                        break;
                    case DefaultMessageIDTypes.ID_CONNECTION_REQUEST_ACCEPTED:
                        if (date.Connect_Success != null) date.Connect_Success();
                        // This tells the date.client they have connected
                        date.currDebugString = ("ID_CONNECTION_REQUEST_ACCEPTED to %s " + date.p.systemAddress.ToString() + "with GUID " + date.p.guid.ToString());
                        date.currDebugString = ("My external address is:" + date.client.GetExternalID(date.p.systemAddress).ToString());
                        break;
                    case DefaultMessageIDTypes.ID_CONNECTED_PING:
                    case DefaultMessageIDTypes.ID_UNCONNECTED_PING:
                        date.currDebugString = ("Ping from " + date.p.systemAddress.ToString(true));
                        break;
                    case DefaultMessageIDTypes.ID_USER_PACKET_ENUM:
                        date.receiveBitStream.Reset();
                        date.receiveBitStream.Write(date.p.data, date.p.length);
                        date.receiveBitStream.IgnoreBytes(1);
                        date.receiveBitStream.Read(out date.message);
                        date.currDebugString = "\r\nBy " + date.p.systemAddress.ToString() +
                                               " Rev msg \r\nDefaultMessageIdTypes: " +
                                               Enum.GetName(typeof(DefaultMessageIDTypes), date.currDefaultMessageIdTypes) +
                                               "\r\n" + date.currTime +
                                               "\r\n" + date.currTime +
                                               "\r\nMsg:" + date.message;
                        break;
                    default:
                        date.message = Encoding.UTF8.GetString(date.p.data.Skip(0).ToArray());
                        date.currDebugString = "\r\nBy " + date.p.systemAddress.ToString() +
                                               " Rev msg \r\nDefaultMessageIdTypes: " +
                                               Enum.GetName(typeof(DefaultMessageIDTypes), date.currDefaultMessageIdTypes) +
                                               "\r\n" + date.currTime +
                                               "\r\nMsg:" + date.message;
                        if (date.Rev_Msg != null) date.Rev_Msg(date.message);
                        break;
                }
            }
        }
    }
    /*
    public virtual uint Send(
      string data,
      int length,
      PacketPriority priority,
      PacketReliability reliability,
      char orderingChannel,
      AddressOrGUID systemIdentifier,
      bool broadcast,
      uint forceReceiptNumber)
    {
      uint num = RakNetPINVOKE.RakPeerInterface_Send__SWIG_0(this.swigCPtr, data, length, (int) priority, (int) reliability, orderingChannel, AddressOrGUID.getCPtr(systemIdentifier), broadcast, forceReceiptNumber);
      if (RakNetPINVOKE.SWIGPendingException.Pending)
        throw RakNetPINVOKE.SWIGPendingException.Retrieve();
      return num;
    }
    public virtual uint Send(
      string data,
      int length,
      PacketPriority priority,
      PacketReliability reliability,
      char orderingChannel,
      AddressOrGUID systemIdentifier,
      bool broadcast)
    {
      uint num = RakNetPINVOKE.RakPeerInterface_Send__SWIG_1(this.swigCPtr, data, length, (int) priority, (int) reliability, orderingChannel, AddressOrGUID.getCPtr(systemIdentifier), broadcast);
      if (RakNetPINVOKE.SWIGPendingException.Pending)
        throw RakNetPINVOKE.SWIGPendingException.Retrieve();
      return num;
    }
     */
    public void Send(string message)
    {
        if (date.client != null && isActive)
        {
            if (message.Length > 0)
            {
                date.client.Send(message, message.Length + 1, PacketPriority.HIGH_PRIORITY, PacketReliability.RELIABLE_ORDERED, (char)0, RakNet.RakNet.UNASSIGNED_SYSTEM_ADDRESS, true);
                // PacketPriority.HIGH_PRIORITY 每一種優先級的發送次數大約是比它優先級低的快兩倍。例如,如果HIGH_PRIORITY發送2條消息,在大致相同的時間內只會發送一條IMMEDIATE_PRIORITY消息。奇怪的是IMMEDIATE_PRIORITY可能會首先到達目的端。
                //PacketReliability.RELIABLE_ORDERED 用RELIABLE_ORDERED作爲數據包的可靠性類型。對於所有的有序類型,使用有序流,下面會介紹到。
                date.currDebugString = "\r\nTo:" + date.client.GetExternalID(RakNet.RakNet.UNASSIGNED_SYSTEM_ADDRESS).ToString() + "\r\n" + date.currTime + "\r\nSend:" + message;
            }
            else
            {
                date.currDebugString = ("Send message fail : you message Length <= 0");
            }
        }
        else
        {
            date.currDebugString = ("because client.IsActive equal false ,So Send message fail :" + message);
        }
    }
    public void Send(BitStream bitStream)
    {
        date.message = Encoding.UTF8.GetString(bitStream.GetData().ToList().Skip(1).ToArray());
        if (date.client != null && isActive)
        {
            // PacketPriority.HIGH_PRIORITY 每一種優先級的發送次數大約是比它優先級低的快兩倍。例如,如果HIGH_PRIORITY發送2條消息,在大致相同的時間內只會發送一條IMMEDIATE_PRIORITY消息。奇怪的是IMMEDIATE_PRIORITY可能會首先到達目的端。
            //PacketReliability.RELIABLE_ORDERED 用RELIABLE_ORDERED作爲數據包的可靠性類型。對於所有的有序類型,使用有序流,下面會介紹到。
            date.client.Send(bitStream, PacketPriority.HIGH_PRIORITY, PacketReliability.RELIABLE_ORDERED, (char)0, RakNet.RakNet.UNASSIGNED_SYSTEM_ADDRESS, true);
            date.currDebugString = "\r\nTo:" + date.client.GetExternalID(RakNet.RakNet.UNASSIGNED_SYSTEM_ADDRESS).ToString() + "\r\n" + date.currTime + "\r\nSend:" + bitStream.ToString();
        }
        else
        {
            date.currDebugString = ("because client.IsActive equal false ,So Send message fail :" + date.message);
        }
    }
    /// <summary>
    /// 發送指定類型的數據包
    /// </summary>
    /// <param name="message"></param>
    /// <param name="type"></param>
    public void Send(string message, DefaultMessageIDTypes type)
    {
        BitStream bitStream = new BitStream();
        bitStream.Write((byte)type);
        bitStream.Write(message);
        Send(bitStream);
    }
    //SystemAddress 的知識
    AddressOrGUID SystemAddressToAddressOrGUID(string ip, ushort port)
    {
        //內網用戶 從包中獲取 自己公網ip ,GetExternalID 獲取公網ip 
        date.client.GetExternalID(date.p.systemAddress).ToString();  //   " 120.77.0.244 | 63279" 
        //默認連接中第一個地址
        //RakNet.RakNet.UNASSIGNED_SYSTEM_ADDRESS
        //本地地址
        //SystemAddress.Tostring();
        //構建
        var SystemAddress_ = new SystemAddress(ip, port);
        var s = new AddressOrGUID(new SystemAddress(ip, port));
        return s;
    }
    public void Close()
    {
        if (date.isInit && date.isConnectFuncRuned)
        {
            date.Rev_Thread?.Abort();
            date.client?.Shutdown(300); //停工;關閉
            RakPeerInterface.DestroyInstance(date.client);
            date.isConnectFuncRuned = false;
            date.isInit = false;
            date.currDebugString = ("connected close  [" + date.ServeIp + ":" + date.serverPort + "] " + "\r\n" + date.currTime);
        }
    }
    /// <summary>
    /// Init 後,可以更換 新的服務器的 ip 端口
    /// </summary>
    public void Connect(string newIp, string newPort)
    {
        if (date.client != null)
        {
            Close();
        }
        date.ServeIp = newIp;
        date.serverPort = newPort;
        Connect();
    }
    public void Connect()
    {
        if (date.isInit == false)
        {
            Init_Date();
        }
        date.currDebugString = "Connecting ... [" + date.ServeIp + ":" + date.serverPort + "]";
        if (date.isCONNECTION_ATTEMPT_STARTED)
        {
            date.car = date.client.Connect(date.ServeIp, Convert.ToUInt16(date.serverPort), date.Rumpelstiltskin, date.Rumpelstiltskin.Length);
            /*
 1. host是一個IP地址,或域名
       2. remotePort是遠端系統監聽的端口,傳遞給Startup()函數的端口參數。
       3. passwordData是隨着連接請求發送的二進制數據。如果這個參數與傳遞給RakPeerInterface::SetPassword()的參數不同,遠端系統會回覆ID_INVALID_PASSWORD。
       4. passwordDataLength是passwordData的長度,單位是字節。
       5. publicKey 是遠端系統上傳遞給InitializeSecurity()函數的公用密鑰參數。如果你不適用,傳遞0。
       6. connectionSocketINdex是你要發送的客戶端的Socket在傳遞給RakPeer::Startup()函數的socket描述符的數組中的索引。
       7. sendConnectionAttemptCount是在確定無法連接前要做出的發送嘗試次數。這個也用於MTU檢測,使用3個不同的MTU大小。默認的值12意味着發送每個MTU四次,這對於容忍任何原因的包丟失也是足夠的了。更低的值意味着ID_CONNECTION_ATTEMPT_FAILED會更快返回。
       8. timeBetweenSendConnectionAttemptsMS是進行另外一次連接嘗試要等待的毫秒數。比較好的值是4倍的ping值。
       9. 如果消息不能發送,在丟掉遠端系統之前,爲這次連接,timeoutTime指出了要等待多少毫秒。默認值是0,意味着使用SetTimeoutTime()方法中的全局值。
   連接嘗試成功Connect()會返回CONNECTION_ATTEMPT_STARTED值,如果失敗會返回其他的值。
   注意:Connect()返回TRUE並不意味着已經連接成功。如果連接成功,應該會返回ID_CONNECTION_REQUEST_ACCEPTED。否則,會收到一條錯誤消息。
連接消息作爲Packet::data結構的第一個字節返回
             */
            if (date.car != RakNet.ConnectionAttemptResult.CONNECTION_ATTEMPT_STARTED)
                throw new Exception();
            date.isCONNECTION_ATTEMPT_STARTED = false;
        }
        else
        {
            ConnectionAttemptResult car2 = date.client.Connect(date.ServeIp, Convert.ToUInt16(date.serverPort), date.Rumpelstiltskin, date.Rumpelstiltskin.Length);
        }
        date.currDebugString = "My Local IP Addresses:";
        for (uint i = 0; i < date.client.GetNumberOfAddresses(); i++)
        {
            date.currDebugString = date.client.GetLocalIP(i).ToString();
        }
        date.currDebugString = "My GUID is " + date.client.GetGuidFromSystemAddress(RakNet.RakNet.UNASSIGNED_SYSTEM_ADDRESS).ToString();
        if (date.Rev_Thread != null)
        {
            date.Rev_Thread.Abort();
        }
        date.Rev_Thread = new Thread(Rev);
        date.Rev_Thread.Start();
        date.isConnected = true;
        date.isConnectFuncRuned = true;
    }
    public void Disconnect(string index_str)
    {
        uint index = Convert.ToUInt32(index_str, 16);
        date.client.CloseConnection(date.client.GetSystemAddressFromIndex(index), false);
        date.currDebugString = "Disconnecting index :" + index_str;
    }
    /*
用包(Packet)的第一個字節(byte)表明包的類型(DefaultMessageIDTypes),而1個字節(byte)最多表示256種不同的狀態
byte byte_ = Packet.data[0];
DefaultMessageIDTypes type =   (DefaultMessageIDTypes)byte_;
     */
    /// <summary>
    /// 確定數據包類型
    /// </summary>
    /// <param name="p"></param>
    /// <returns></returns>
    private static byte GetPacketIdentifier(Packet p)
    {
        if (p == null)
            return 255;
        byte buf = p.data[0];
        if (buf == (char)DefaultMessageIDTypes.ID_TIMESTAMP)
        {
            return (byte)p.data[5];
        }
        else
            return buf;
    }
}
public struct RakNetClient_Date
{
    public RakPeerInterface client;
    public SystemAddress clientID;
    public RakNetStatistics rss;
    public SocketDescriptor socketDescriptor;
    public string ServeIp, serverPort, clientPort, clientIp;
    public ConnectionAttemptResult car;
    public bool isServer;
    public string Rumpelstiltskin;
    public Packet p;
    public byte packetIdentifier;
    public bool isCONNECTION_ATTEMPT_STARTED;//是否是第一次連接
    public bool isInit;//是否初始化了Date
    public bool isConnectFuncRuned;// Connect函數是否執行過
    public bool isConnected;
    public Thread Rev_Thread;
    public Action<string> Rev_Msg; //收到數據 事件 消息回調
    public Action<string> Debug_Msg; //調試信息 事件 消息回調
    public BitStream receiveBitStream;
    public string currDebugString
    {
        set
        {
            if (Debug_Msg != null)
                Debug_Msg(value);
        }
    }
    public DefaultMessageIDTypes currDefaultMessageIdTypes;
    public Action Connect_Fail; //連接失敗 或者 失去連接 事件 消息回調
    public Action Connect_Success; //連接成功事件 消息回調
    public StartupResult startupResult;
    public short socketFamily;
    public string message;
    //Serve
    public RakPeerInterface server;
    public int MAXIMUM_NUMBER_OF_INTERNAL_IDS;
    public Action<SystemAddress> NewPlayerConnect; //新玩家接入時
    public Action<SystemAddress> PlayerConnectLost; //失去玩家連接時
    public string currTime
    {
        get
        {
            return "Time:" + System.DateTime.Now.ToString("yyyy_MM_dd hh:mm:ss:fff");
        }
    }
}

Use

using System;
using System.Collections.Generic;
using System.Windows.Forms;
using RakNet;
namespace RakNetDot
{
    public partial class Form1 : Form
    {
        public Form1()
        {
            InitializeComponent();
            var textBox8897 = textBox3;
            //多行
            textBox8897.Multiline = true;
            //不自動換行
            textBox8897.WordWrap = true;
            //添加滾動條,,  ScrollBars.Horizontal=橫,ScrollBars.Vertical=豎,
            textBox8897.ScrollBars = ScrollBars.Vertical;
            //textbox滾動條保持在最下面
            textBox8897.TextChanged += (sender, args) =>
            {
                textBox8897.SelectionStart = textBox8897.Text.Length;
                textBox8897.SelectionLength = 0;
                textBox8897.ScrollToCaret();
            };
             textBox8897 = textBox6;
            //多行
            textBox8897.Multiline = true;
            //不自動換行
            textBox8897.WordWrap = true;
            //添加滾動條,,  ScrollBars.Horizontal=橫,ScrollBars.Vertical=豎,
            textBox8897.ScrollBars = ScrollBars.Vertical;
            //textbox滾動條保持在最下面
            textBox8897.TextChanged += (sender, args) =>
            {
                textBox8897.SelectionStart = textBox8897.Text.Length;
                textBox8897.SelectionLength = 0;
                textBox8897.ScrollToCaret();
            };
        }
        private RakNetClient client;
        private RakNetServe rakNetServe;
        private void button1_Click(object sender, EventArgs e)
        {//連接
            if (client == null || client.date.client == null) //新建
            {
                string Serve_ip = textBox1.Text;
                string Serve_port = textBox2.Text;
                client = new RakNetClient(Serve_ip, Serve_port);
                client.date.Debug_Msg += x =>
                {
                    // 當一個控件的InvokeRequired屬性值爲真時,說明有一個創建它以外的線程想訪問它
                    if (textBox3.InvokeRequired)
                    {
                        Action<string> actionDelegate = (txt) => { textBox3.AppendText("\r\n" + txt + "\r\n"); };
                        textBox3.Invoke(actionDelegate, x);
                    }
                    else
                    {
                        textBox3.AppendText("\r\n" + x + "\r\n");
                    }
                };
                client.date.Debug_Msg += x => { Console.WriteLine(x); };
                client.Connect(Serve_ip, Serve_port);
                client.date.Connect_Fail += () =>
                {
                    // 當一個控件的InvokeRequired屬性值爲真時,說明有一個創建它以外的線程想訪問它
                    if (button1.InvokeRequired)
                    {
                        Action<string> actionDelegate = (txt) => { button1.Text = (txt); };
                        button1.Invoke(actionDelegate, "connect");
                    }
                    else
                    {
                        button1.Text = "connect";
                    }
                };
            }
            else if (client.date.isInit==false || client.isActive == false) //重連
            {
                client.Connect();
            }
            else if (client.date.isInit && client.isActive) //關閉
            {
                client.Close();
            }
            if (client != null)
            {
                button1.Text = client.isActive ? "Stop connect" : "connect";
            }
            else
            {
                button1.Text = "connect";
            }
        }
        private void button2_Click(object sender, EventArgs e)
        {//發送
            client?.Send(textBox4.Text,DefaultMessageIDTypes.ID_USER_PACKET_ENUM);
        }
        private void Form1_FormClosed(object sender, FormClosedEventArgs e)
        {
            client?.Close();
            rakNetServe?.Close();
        }
        List<SystemAddress> list =new List<SystemAddress>();
        private void button4_Click(object sender, EventArgs e)
        {
            if (rakNetServe == null)
            {
                string Serve_port = textBox7.Text;
                rakNetServe = new RakNetServe(Serve_port);
                rakNetServe.date.Debug_Msg += x =>
                {
                    // 當一個控件的InvokeRequired屬性值爲真時,說明有一個創建它以外的線程想訪問它
                    if (textBox6.InvokeRequired)
                    {
                        Action<string> actionDelegate = (txt) => { textBox6.AppendText("\r\n" + txt + "\r\n"); };
                        textBox6.Invoke(actionDelegate, x);
                    }
                    else
                    {
                        textBox6.AppendText("\r\n" + x + "\r\n");
                    }
                };
                rakNetServe.date.NewPlayerConnect += x =>
                {
                    list.Clear();
                    list = rakNetServe.GetConnectionList();
                    if (list.Count > 0)
                    {
                        var kvDictonary = new Dictionary<string, string>();
                        for (int i = 0; i < list.Count; i++)
                        {
                            var item = list[i];
                            kvDictonary.Add(item.ToString(), item.ToString());
                        }
                        BindingSource bs = new BindingSource();
                        bs.DataSource = kvDictonary;
                        comboBox1.DataSource = bs;
                        comboBox1.ValueMember = "Key";
                        comboBox1.DisplayMember = "Value";
                    }
                };
                rakNetServe.date.PlayerConnectLost += x =>
                {
                    list.Clear();
                    list = rakNetServe.GetConnectionList();
                    if (list.Count > 0)
                    {
                        var kvDictonary = new Dictionary<string, string>();
                        for (int i = 0; i < list.Count; i++)
                        {
                            var item = list[i];
                            kvDictonary.Add(item.ToString(), item.ToString());
                        }
                        BindingSource bs = new BindingSource();
                        bs.DataSource = kvDictonary;
                        comboBox1.DataSource = bs;
                        comboBox1.ValueMember = "Key";
                        comboBox1.DisplayMember = "Value";
                    }
                };
                rakNetServe.Connect();
                button4.Text = "Stop";
            }
            else
            {
                rakNetServe.Close();
                button4.Text = "Listen";
            }
        }
        private void button3_Click(object sender, EventArgs e)
        {
            if (list.Count > 0 && comboBox1.SelectedIndex >=0 && comboBox1.SelectedIndex < list.Count)
            {
                SystemAddress add = list[comboBox1.SelectedIndex];
                rakNetServe.Send(textBox5.Text,add,DefaultMessageIDTypes.ID_USER_PACKET_ENUM);
            }
            else
            {
                textBox6.AppendText("\r\n" + "send msg fail ,becucase no player" + "\r\n");
            }
        }
    }
}

exe 程序在 qq羣文件夾裏 431859012

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章