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