├── Connection.cs ├── README.md └── unittest.cs /Connection.cs: -------------------------------------------------------------------------------- 1 | // 2014.04 2 | // Tracy Ma 3 | // Original c++ version author: Glenn Fiedler 4 | using UnityEngine; 5 | using System.Collections.Generic; 6 | 7 | public class Address 8 | { 9 | // public bool Equals(Address other) 10 | // { 11 | // if() 12 | // } 13 | public Address() 14 | { 15 | _address = 0; 16 | _port = 0; 17 | } 18 | public Address(char a, char b, char c, char d, ushort port) 19 | { 20 | _address = (uint)(a << 24); 21 | _address |= (uint)(b << 16); 22 | _address |= (uint)(c << 8); 23 | _address |= (uint)(d); 24 | _port = port; 25 | } 26 | public Address(uint address, ushort port) 27 | { 28 | _address = address; 29 | _port = port; 30 | } 31 | 32 | public uint GetAddress() 33 | { 34 | return _address; 35 | } 36 | 37 | public ushort GetPort() 38 | { 39 | return _port; 40 | } 41 | public override bool Equals(System.Object obj) 42 | { 43 | if (obj == null) 44 | { 45 | return false; 46 | } 47 | Address a = obj as Address; 48 | if ((System.Object)a == null) 49 | { 50 | return false; 51 | } 52 | return (_address == a._address) && (_port == a._port); 53 | } 54 | public override int GetHashCode() 55 | { 56 | return (int)(_address ^ _port); 57 | } 58 | public static bool operator ==(Address one, Address other) 59 | { 60 | return one._address == other._address && one._port == other._port; 61 | } 62 | public static bool operator !=(Address one, Address other) 63 | { 64 | return !(one == other); 65 | } 66 | public static bool operator <(Address one, Address other) 67 | { 68 | if (one._address < other._address) 69 | return true; 70 | if (one._address > other._address) 71 | return false; 72 | else 73 | return one._port < other._port; 74 | } 75 | public static bool operator >(Address one, Address other) 76 | { 77 | if (one._address > other._address) 78 | return true; 79 | if (one._address < other._address) 80 | return false; 81 | else 82 | return one._port > other._port; 83 | } 84 | public void Reset() 85 | { 86 | _address = 0; 87 | _port = 0; 88 | } 89 | uint _address; 90 | ushort _port; 91 | } 92 | 93 | public class Socket 94 | { 95 | public Socket() 96 | { 97 | socket = null; 98 | } 99 | ~Socket() 100 | { 101 | Close(); 102 | } 103 | /// 104 | /// 初始化套接字和sendorRemote 105 | /// 106 | /// 端口 107 | /// 108 | public bool Open(ushort port) 109 | { 110 | socket = new System.Net.Sockets.Socket(System.Net.Sockets.AddressFamily.InterNetwork, 111 | System.Net.Sockets.SocketType.Dgram, System.Net.Sockets.ProtocolType.Udp); 112 | socket.Blocking = false; 113 | return true; 114 | } 115 | public void Close() 116 | { 117 | socket.Close(); 118 | } 119 | //public bool IsOpen() 120 | //{ 121 | // return socket.Available(); 122 | //} 123 | public bool Send(ref System.Net.IPEndPoint ipep, byte[] data, int size) 124 | { 125 | if (socket == null) 126 | { 127 | return false; 128 | } 129 | 130 | int count = socket.SendTo(data, size, System.Net.Sockets.SocketFlags.None, ipep); 131 | if (count > 0) 132 | return true; 133 | else 134 | return false; 135 | } 136 | public int Receive(ref System.Net.EndPoint sendor, byte[] data, int size) 137 | { 138 | int count = socket.ReceiveFrom(data, ref sendor); 139 | return count; 140 | } 141 | 142 | System.Net.Sockets.Socket socket = null; 143 | } 144 | 145 | public class Connection 146 | { 147 | public enum Mode 148 | { 149 | None, 150 | Server, 151 | Client 152 | }; 153 | Mode mode; 154 | uint protocolID; 155 | float timeout; 156 | bool running; 157 | enum State 158 | { 159 | Disconnected, 160 | Listening, 161 | Connecting, 162 | ConnectFail, 163 | Connected 164 | }; 165 | State state; 166 | float timeoutAccumulator; 167 | Socket socket = new Socket(); 168 | System.Net.IPEndPoint address = new System.Net.IPEndPoint(System.Net.IPAddress.Any, 1912); 169 | 170 | void ClearData() 171 | { 172 | state = State.Disconnected; 173 | timeoutAccumulator = 0.0f; 174 | //address.Reset(); 175 | } 176 | 177 | protected virtual void OnStart() { } 178 | protected virtual void OnStop() { } 179 | protected virtual void OnConnect() { } 180 | protected virtual void OnDisconnect() { } 181 | // constructor 182 | //public Connection() 183 | //{ } 184 | public Connection(uint pID, float TO) 185 | { 186 | this.protocolID = pID; 187 | this.timeout = TO; 188 | mode = Mode.None; 189 | running = false; 190 | ClearData(); 191 | } 192 | 193 | public bool Start(ushort port) 194 | { 195 | Debug.Log("start connection on port " + port); 196 | if (!socket.Open(port)) 197 | { 198 | return false; 199 | } 200 | running = true; 201 | OnStart(); 202 | return true; 203 | } 204 | 205 | public void Stop() 206 | { 207 | Debug.Log("stop connection"); 208 | bool connected = IsConnected(); 209 | ClearData(); 210 | socket.Close(); 211 | running = false; 212 | if (connected) 213 | OnDisconnect(); 214 | OnStop(); 215 | } 216 | public bool IsRunning() 217 | { 218 | return running; 219 | } 220 | public void Listen() 221 | { 222 | Debug.Log("server listening for connection"); 223 | bool connected = IsConnected(); 224 | ClearData(); 225 | if (connected) 226 | OnDisconnect(); 227 | mode = Mode.Server; 228 | state = State.Listening; 229 | } 230 | public void Connect(ref System.Net.IPEndPoint addr) 231 | { 232 | //print("client connecting to %hhu.%hhu.%hhu.%hhu:%d\n", 233 | // addr.GetA(), addr.GetB(), addr.GetC(), addr.GetD(), addr.GetPort()); 234 | bool connected = IsConnected(); 235 | ClearData(); 236 | if (connected) 237 | OnDisconnect(); 238 | mode = Mode.Client; 239 | state = State.Connecting; 240 | address = addr; 241 | Debug.Log("(0)address = " + address.ToString()); 242 | } 243 | 244 | public bool IsConnecting() 245 | { 246 | return state == State.Connecting; 247 | } 248 | 249 | public bool ConnectFailed() 250 | { 251 | return state == State.ConnectFail; 252 | } 253 | 254 | public bool IsConnected() 255 | { 256 | return state == State.Connected; 257 | } 258 | 259 | public bool IsListening() 260 | { 261 | return state == State.Listening; 262 | } 263 | public Mode GetMode() 264 | { 265 | return mode; 266 | } 267 | public virtual void Update(float deltaTime) 268 | { 269 | timeoutAccumulator += deltaTime; 270 | if (timeoutAccumulator > timeout) 271 | { 272 | if (state == State.Connecting) 273 | { 274 | Debug.Log("connect timed out"); 275 | ClearData(); 276 | state = State.ConnectFail; 277 | OnDisconnect(); 278 | } 279 | else if (state == State.Connected) 280 | { 281 | Debug.Log("connnection timed out"); 282 | ClearData(); 283 | if (state == State.Connecting) 284 | { 285 | state = State.ConnectFail; 286 | } 287 | OnDisconnect(); 288 | } 289 | } 290 | } 291 | public static string ByteArrayToString(byte[] ba) 292 | { 293 | string hex = System.BitConverter.ToString(ba); 294 | return hex.Replace("-", ""); 295 | } 296 | public virtual bool SendPacket(byte[] data, int size) 297 | { 298 | //if (address.GetAddress() == 0) 299 | //{ 300 | // return false; 301 | //} 302 | byte[] packet = new byte[size + 4]; 303 | packet[0] = (byte)(protocolID >> 24); 304 | packet[1] = (byte)((protocolID >> 16) & 0xff); 305 | packet[2] = (byte)((protocolID >> 8) & 0xff); 306 | packet[3] = (byte)(protocolID & 0xff); 307 | System.Buffer.BlockCopy(data, 0, packet, 4, data.Length); 308 | Debug.Log(ByteArrayToString(packet)); 309 | 310 | Debug.Log("IP = " + address.ToString()); 311 | return socket.Send(ref address, packet, size + 4); 312 | 313 | } 314 | public virtual int ReceivePacket(ref byte[] data, int size) 315 | { 316 | byte[] packet = new byte[size + 4]; 317 | System.Net.IPEndPoint remoteIpEp = new System.Net.IPEndPoint(System.Net.IPAddress.Any, 0); 318 | System.Net.EndPoint remoteEp = (System.Net.EndPoint)remoteIpEp; 319 | int count = socket.Receive(ref remoteEp, packet, size + 4); 320 | if (count == 0) 321 | { 322 | return 0; 323 | } 324 | if (count <= 4) 325 | { 326 | return 0; 327 | } 328 | if (packet[0] != (byte)(protocolID >> 24) || 329 | packet[1] != (byte)((protocolID >> 16) & 0xFF) || 330 | packet[2] != (byte)((protocolID >> 8) & 0xFF) || 331 | packet[3] != (byte)(protocolID & 0xFF)) 332 | { 333 | return 0; 334 | } 335 | if (mode == Mode.Server && !IsConnected()) 336 | { 337 | Debug.Log("server accepts connection from client "); 338 | state = State.Connected; 339 | address = remoteIpEp; 340 | OnConnect(); 341 | } 342 | // TODO 343 | if (address.Equals(remoteIpEp)) 344 | { 345 | if (state == State.Connecting) 346 | { 347 | state = State.Connected; 348 | OnConnect(); 349 | } 350 | timeoutAccumulator = 0.0f; 351 | System.Buffer.BlockCopy(packet, 4, data, 0, count - 4); 352 | return count - 4; 353 | } 354 | return 0; 355 | } 356 | public virtual int GetHeaderSize() 357 | { 358 | return 4; 359 | } 360 | } 361 | public struct PacketData 362 | { 363 | public uint sequence; 364 | public int size; 365 | public float time; 366 | } 367 | 368 | public class PacketQueue : LinkedList 369 | { 370 | bool sequence_more_recent(uint s1, uint s2, uint max_sequence) 371 | { 372 | return ((s1 > s2) && (s1 - s2 <= max_sequence / 2)) || ((s2 > s1) && (s2 - s1 > max_sequence / 2)); 373 | } 374 | 375 | public bool exists(uint sequence) 376 | { 377 | 378 | foreach (PacketData pd in this) 379 | { 380 | if (pd.sequence == sequence) 381 | { 382 | return true; 383 | } 384 | } 385 | return false; 386 | } 387 | public void insert_sorted(PacketData p, uint max_sequence) 388 | { 389 | if (this.Count == 0) 390 | { 391 | this.AddLast(p); 392 | } 393 | else 394 | { 395 | if (!sequence_more_recent(p.sequence, this.First.Value.sequence, max_sequence)) 396 | { 397 | this.AddFirst(p); 398 | } 399 | else if (sequence_more_recent(p.sequence, this.Last.Value.sequence, max_sequence)) 400 | { 401 | this.AddLast(p); 402 | } 403 | else 404 | { 405 | for (LinkedListNode node = this.First; node != this.Last.Next; node = node.Next) 406 | { 407 | if (sequence_more_recent(node.Value.sequence, p.sequence, max_sequence)) 408 | { 409 | this.AddAfter(node, p); 410 | break; 411 | } 412 | } 413 | } 414 | } 415 | } 416 | public void verify_sorted(uint max_sequence) 417 | { 418 | if (this.Count < 2) 419 | { 420 | Debug.LogError("queue is too short"); 421 | } 422 | for (LinkedListNode node = this.First; node != this.Last.Next; node = node.Next) 423 | { 424 | if (node.Next != null) 425 | { 426 | if (sequence_more_recent(node.Value.sequence, node.Next.Value.sequence, max_sequence)) 427 | { 428 | Debug.LogError("verify_sorted fail!"); 429 | } 430 | } 431 | 432 | } 433 | } 434 | 435 | } 436 | public class ReliabilitySystem 437 | { 438 | public ReliabilitySystem(uint max_sequence = 0xffffffff) 439 | { 440 | this.max_sequence = max_sequence; 441 | Reset(); 442 | } 443 | public void Reset() 444 | { 445 | local_sequence = 0; 446 | remote_sequence = 0; 447 | sentQueue.Clear(); 448 | receivedQueue.Clear(); 449 | pendingAckQueue.Clear(); 450 | ackedQueue.Clear(); 451 | sent_packets = 0; 452 | recv_packets = 0; 453 | lost_packets = 0; 454 | acked_packets = 0; 455 | sent_bandwidth = 0.0f; 456 | acked_bandwidth = 0.0f; 457 | rtt = 0.0f; 458 | rtt_maximum = 0.0f; 459 | } 460 | public void PacketSent(int size) 461 | { 462 | if (sentQueue.exists(local_sequence)) 463 | { 464 | Debug.Log("local sequence exists " + local_sequence); 465 | } 466 | PacketData data; 467 | data.sequence = local_sequence; 468 | data.size = size; 469 | data.time = 0.0f; 470 | sentQueue.AddLast(data); 471 | pendingAckQueue.AddLast(data); 472 | sent_packets++; 473 | local_sequence++; 474 | if (local_sequence > max_sequence) 475 | { 476 | local_sequence = 0; 477 | } 478 | } 479 | static bool sequence_more_recent(uint s1, uint s2, uint max_sequence) 480 | { 481 | return ((s1 > s2) && (s1 - s2 <= max_sequence / 2)) || ((s2 > s1) && (s2 - s1 > max_sequence / 2)); 482 | } 483 | public void PacketReceived(uint sequence, int size) 484 | { 485 | recv_packets++; 486 | if (receivedQueue.exists(sequence)) 487 | return; 488 | PacketData data; 489 | data.sequence = sequence; 490 | data.size = size; 491 | data.time = 0.0f; 492 | receivedQueue.AddLast(data); 493 | if (sequence_more_recent(sequence, remote_sequence, max_sequence)) 494 | { 495 | remote_sequence = sequence; 496 | } 497 | } 498 | public uint GenerateAckBits() 499 | { 500 | return generate_ack_bits(GetRemoteSequence(), ref receivedQueue, max_sequence); 501 | } 502 | public void ProcessAck(uint ack, uint ack_bits) 503 | { 504 | process_ack(ack, ack_bits, ref pendingAckQueue, ref ackedQueue, ref acks, acked_packets, rtt, max_sequence); 505 | } 506 | public void Update(float deltaTime) 507 | { 508 | acks.Clear(); 509 | AdvanceQueueTime(deltaTime); 510 | UpdateQueues(); 511 | UpdateStatus(); 512 | } 513 | public static uint bit_index_for_sequence(uint sequence, uint ack, uint max_sequence) 514 | { 515 | if (sequence > ack) 516 | { 517 | return ack + (max_sequence - sequence); 518 | } 519 | else 520 | { 521 | return ack - 1 - sequence; 522 | } 523 | } 524 | public static uint generate_ack_bits(uint ack, ref PacketQueue received_queue, uint max_sequence) 525 | { 526 | uint ack_bits = 0; 527 | foreach (PacketData received in received_queue) 528 | { 529 | if (received.sequence == ack || sequence_more_recent(received.sequence, ack, max_sequence)) 530 | break; 531 | uint bit_index = bit_index_for_sequence(received.sequence, ack, max_sequence); 532 | if (bit_index <= 31) 533 | { 534 | ack_bits |= 1U << (int)bit_index; 535 | } 536 | } 537 | return ack_bits; 538 | } 539 | public static void process_ack(uint ack, uint ack_bits, ref PacketQueue pending_ack_queue, 540 | ref PacketQueue acked_queue, ref List acks, 541 | uint acked_packets, float rtt, uint max_sequence) 542 | { 543 | if (pending_ack_queue.Count == 0) 544 | { 545 | return; 546 | } 547 | var node = pending_ack_queue.First; 548 | while (node != null) 549 | { 550 | var nextnode = node.Next; 551 | 552 | bool acked = false; 553 | if (node.Value.sequence == ack) 554 | { 555 | acked = true; 556 | } 557 | else if (!sequence_more_recent(node.Value.sequence, ack, max_sequence)) 558 | { 559 | uint bit_index = bit_index_for_sequence(node.Value.sequence, ack, max_sequence); 560 | if (bit_index <= 31) 561 | { 562 | acked = System.Convert.ToBoolean((ack_bits >> (int)bit_index) & 1); 563 | } 564 | } 565 | if (acked) 566 | { 567 | rtt += (node.Value.time - rtt) * 0.1f; 568 | 569 | acked_queue.insert_sorted(node.Value, max_sequence); 570 | acks.Add(node.Value.sequence); 571 | acked_packets++; 572 | pending_ack_queue.Remove(node); 573 | node = nextnode; 574 | } 575 | else 576 | { 577 | node = nextnode; 578 | } 579 | } 580 | 581 | } 582 | public uint GetLocalSequence() 583 | { 584 | return local_sequence; 585 | } 586 | public uint GetRemoteSequence() 587 | { 588 | return remote_sequence; 589 | } 590 | public uint GetMaxSequence() 591 | { 592 | return max_sequence; 593 | } 594 | public void GetAcks() 595 | { 596 | 597 | } 598 | public uint GetSentPackets() 599 | { 600 | return sent_packets; 601 | } 602 | public uint GetReceivePackets() 603 | { 604 | return recv_packets; 605 | } 606 | public uint GetLostPackets() 607 | { 608 | return lost_packets; 609 | } 610 | public uint GetAckedPackets() 611 | { 612 | return acked_packets; 613 | } 614 | public float GetSentBandwidth() 615 | { 616 | return sent_bandwidth; 617 | } 618 | public float GetAckedBandwidth() 619 | { 620 | return acked_bandwidth; 621 | } 622 | 623 | public float GetRoundTripTime() 624 | { 625 | return rtt; 626 | } 627 | public int GetHeaderSize() 628 | { 629 | return 12; 630 | } 631 | protected void AdvanceQueueTime(float deltaTime) 632 | { 633 | PacketData data; 634 | for (LinkedListNode node = sentQueue.First; node != sentQueue.Last.Next; node = node.Next) 635 | { 636 | data.sequence = node.Value.sequence; 637 | data.size = node.Value.size; 638 | data.time = node.Value.time + deltaTime; 639 | node.Value = data; 640 | } 641 | for (LinkedListNode node = receivedQueue.First; node != receivedQueue.Last.Next; node = node.Next) 642 | { 643 | data.sequence = node.Value.sequence; 644 | data.size = node.Value.size; 645 | data.time = node.Value.time + deltaTime; 646 | node.Value = data; 647 | } 648 | for (LinkedListNode node = pendingAckQueue.First; node != pendingAckQueue.Last.Next; node = node.Next) 649 | { 650 | data.sequence = node.Value.sequence; 651 | data.size = node.Value.size; 652 | data.time = node.Value.time + deltaTime; 653 | node.Value = data; 654 | } 655 | for (LinkedListNode node = ackedQueue.First; node != ackedQueue.Last.Next; node = node.Next) 656 | { 657 | data.sequence = node.Value.sequence; 658 | data.size = node.Value.size; 659 | data.time = node.Value.time + deltaTime; 660 | node.Value = data; 661 | } 662 | } 663 | protected void UpdateQueues() 664 | { 665 | const float epsilon = 0.001f; 666 | while ((sentQueue.Count > 0) && (sentQueue.First.Value.time > (rtt_maximum + epsilon))) 667 | { 668 | sentQueue.RemoveFirst(); 669 | } 670 | if (receivedQueue.Count > 0) 671 | { 672 | uint latest_sequence = receivedQueue.Last.Value.sequence; 673 | uint minimum_sequence = latest_sequence >= 34 ? (latest_sequence - 34) : max_sequence - (34 - latest_sequence); 674 | while ((receivedQueue.Count > 0) && !sequence_more_recent(receivedQueue.First.Value.sequence, minimum_sequence, max_sequence)) 675 | { 676 | receivedQueue.RemoveFirst(); 677 | } 678 | } 679 | while (ackedQueue.Count > 0 && ackedQueue.First.Value.time > rtt_maximum * 2 - epsilon) 680 | { 681 | ackedQueue.RemoveFirst(); 682 | } 683 | while (pendingAckQueue.Count > 0 && pendingAckQueue.First.Value.time > rtt_maximum + epsilon) 684 | { 685 | pendingAckQueue.RemoveFirst(); 686 | lost_packets++; 687 | } 688 | } 689 | protected void UpdateStatus() 690 | { 691 | int sent_bytes_per_second = 0; 692 | foreach (PacketData data in sentQueue) 693 | { 694 | sent_bytes_per_second += data.size; 695 | } 696 | int acked_packets_per_second = 0; 697 | int acked_bytes_per_second = 0; 698 | foreach (PacketData data in ackedQueue) 699 | { 700 | if (data.time >= rtt_maximum) 701 | { 702 | acked_packets_per_second++; 703 | acked_bytes_per_second += data.size; 704 | } 705 | } 706 | sent_bytes_per_second = (int)(sent_bytes_per_second / rtt_maximum); 707 | acked_bytes_per_second = (int)(acked_bytes_per_second / rtt_maximum); 708 | sent_bandwidth = sent_bytes_per_second * (8 / 1000.0f); 709 | acked_bandwidth = acked_bytes_per_second * (8 / 1000.0f); 710 | } 711 | uint max_sequence; 712 | uint local_sequence; 713 | uint remote_sequence; 714 | 715 | uint sent_packets; 716 | uint recv_packets; 717 | uint lost_packets; 718 | uint acked_packets; 719 | 720 | float sent_bandwidth; 721 | float acked_bandwidth; 722 | float rtt; 723 | float rtt_maximum; 724 | 725 | List acks; 726 | 727 | PacketQueue sentQueue = new PacketQueue(); 728 | PacketQueue pendingAckQueue = new PacketQueue(); 729 | PacketQueue receivedQueue = new PacketQueue(); 730 | PacketQueue ackedQueue = new PacketQueue(); 731 | } 732 | 733 | public class ReliableConnection : Connection 734 | { 735 | public ReliableConnection(uint protocolId, float timeout, uint max_sequence = 0xffffffff) 736 | : base(protocolId, timeout) 737 | { 738 | reliabilitySystem = new ReliabilitySystem(max_sequence); 739 | ClearData(); 740 | } 741 | ~ReliableConnection() 742 | { 743 | if (base.IsRunning()) 744 | { 745 | base.Stop(); 746 | } 747 | } 748 | bool SendPacket(ref byte[] data, int size) 749 | { 750 | const int header = 12; 751 | byte[] packet = new byte[header + size]; 752 | uint seq = reliabilitySystem.GetLocalSequence(); 753 | uint ack = reliabilitySystem.GetRemoteSequence(); 754 | uint ack_bits = reliabilitySystem.GenerateAckBits(); 755 | WriteHeader(ref packet, seq, ack, ack_bits); 756 | System.Buffer.BlockCopy(data, 0, packet, header, data.Length); 757 | if (!base.SendPacket(packet, size + header)) 758 | { 759 | return false; 760 | } 761 | reliabilitySystem.PacketSent(size); 762 | return true; 763 | } 764 | public override int ReceivePacket(ref byte[] data, int size) 765 | { 766 | const int header = 12; 767 | if (size <= header) 768 | { 769 | return 0; 770 | } 771 | byte[] packet = new byte[header + size]; 772 | int count = base.ReceivePacket(ref packet, size + header); 773 | if (count == 0) 774 | return 0; 775 | if (count <= header) 776 | return 0; 777 | uint packet_sequence = 0; 778 | uint packet_ack = 0; 779 | uint packet_ack_bits = 0; 780 | ReadHeader(ref packet, ref packet_sequence, ref packet_ack, ref packet_ack_bits); 781 | reliabilitySystem.PacketReceived(packet_sequence, count - header); 782 | reliabilitySystem.ProcessAck(packet_ack, packet_ack_bits); 783 | System.Buffer.BlockCopy(packet, header, data, 0, count - header); 784 | return count - header; 785 | } 786 | public void WriteInteger(ref byte[] data, uint value, int offset) 787 | { 788 | data[offset] = (byte)(value >> 24); 789 | data[offset + 1] = (byte)((value >> 16) & 0xff); 790 | data[offset + 2] = (byte)((value >> 8) & 0xff); 791 | data[offset + 3] = (byte)(value & 0xff); 792 | } 793 | public void WriteHeader(ref byte[] header, uint sequence, uint ack, uint ack_bits) 794 | { 795 | WriteInteger(ref header, sequence, 0); 796 | WriteInteger(ref header, ack, 4); 797 | WriteInteger(ref header, ack_bits, 8); 798 | } 799 | 800 | public void ReadInteger(ref byte[] data, ref uint value, int offset) 801 | { 802 | value = ((uint)(data[offset] << 24) | 803 | (uint)(data[offset + 1] << 16) | 804 | (uint)(data[offset + 2] << 8) | 805 | (uint)(data[offset + 3])); 806 | } 807 | public void ReadHeader(ref byte[] header, ref uint sequence, ref uint ack, ref uint ack_bits) 808 | { 809 | ReadInteger(ref header, ref sequence, 0); 810 | ReadInteger(ref header, ref ack, 4); 811 | ReadInteger(ref header, ref ack_bits, 8); 812 | } 813 | public override void Update(float deltaTime) 814 | { 815 | base.Update(deltaTime); 816 | reliabilitySystem.Update(deltaTime); 817 | } 818 | public override int GetHeaderSize() 819 | { 820 | return base.GetHeaderSize() + reliabilitySystem.GetHeaderSize(); 821 | } 822 | public ReliabilitySystem GetReliableSystem() 823 | { 824 | return reliabilitySystem; 825 | } 826 | protected override void OnStop() 827 | { 828 | ClearData(); 829 | } 830 | 831 | protected override void OnDisconnect() 832 | { 833 | ClearData(); 834 | } 835 | void ClearData() 836 | { 837 | reliabilitySystem.Reset(); 838 | } 839 | ReliabilitySystem reliabilitySystem; 840 | } -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | unity_rudp 2 | ========== 3 | 4 | Reliable UDP Protocol can be used with Unity3D. 5 | 6 | Manually translate from c++ version https://code.google.com/p/netgame/ -------------------------------------------------------------------------------- /unittest.cs: -------------------------------------------------------------------------------- 1 | using UnityEngine; 2 | using System.Collections.Generic; 3 | 4 | public class unittest : MonoBehaviour 5 | { 6 | void test_ipendpoint_endpoint_equal() 7 | { 8 | System.Net.IPEndPoint ipep = new System.Net.IPEndPoint(System.Net.IPAddress.Parse("127.0.0.1"), 1912); 9 | System.Net.EndPoint ep = (System.Net.IPEndPoint)ipep; 10 | print(ipep.ToString()); 11 | print(ep.ToString()); 12 | print(ipep.Equals(ep)); 13 | 14 | //System.Net.IPEndPoint ipep2 = new System.Net.IPEndPoint(System.Net.IPAddress.Any, 0); 15 | //System.Net.EndPoint sender = (System.Net.EndPoint)ipep; 16 | //sender = new 17 | } 18 | void test_remove_items_in_loops() 19 | { 20 | var myList = new List { 0, 1, 2, 3, 4, 5 }; 21 | print("before"); 22 | foreach (int i in myList) 23 | { 24 | print(i); 25 | } 26 | for (int i = 0; i < myList.Count - 1; i++) 27 | { 28 | if (myList[i] >= 3) 29 | { 30 | myList.RemoveAt(i); 31 | } 32 | } 33 | print("after"); 34 | foreach (int i in myList) 35 | { 36 | print(i); 37 | } 38 | } 39 | void test_list_pushback() 40 | { 41 | var myList = new List { 0, 1, 2, 3, 4, 5 }; 42 | myList.Add(11); 43 | print(myList[myList.Count - 1]); 44 | } 45 | void test_remove_in_while() 46 | { 47 | var myList = new List { 0, 1, 2, 3, 4, 5 }; 48 | while (myList.Count > 0 && myList[0] < 5) 49 | { 50 | myList.RemoveAt(0); 51 | print(myList.Count); 52 | } 53 | } 54 | void test_packet_queue() 55 | { 56 | uint MaximumSequence = 255; 57 | PacketQueue packetQueue = new PacketQueue(); 58 | PacketData data; 59 | 60 | print("check insert back"); 61 | for (uint i = 0; i < 100; ++i) 62 | { 63 | data = new PacketData(); 64 | data.sequence = i; 65 | packetQueue.insert_sorted(data, MaximumSequence); 66 | if (i > 1) 67 | packetQueue.verify_sorted(MaximumSequence); 68 | } 69 | 70 | print("check insert front"); 71 | packetQueue.Clear(); 72 | for (uint i = 100; i < 0; ++i) 73 | { 74 | data = new PacketData(); 75 | data.sequence = i; 76 | packetQueue.insert_sorted(data, MaximumSequence); 77 | if (i > 1) 78 | packetQueue.verify_sorted(MaximumSequence); 79 | } 80 | print("check insert random"); 81 | packetQueue.Clear(); 82 | for (uint i = 100; i < 0; ++i) 83 | { 84 | data = new PacketData(); 85 | data.sequence = (uint)(UnityEngine.Random.value * 10) & 0xff; 86 | packetQueue.insert_sorted(data, MaximumSequence); 87 | if (i > 1) 88 | packetQueue.verify_sorted(MaximumSequence); 89 | } 90 | print("check insert wrap around"); 91 | packetQueue.Clear(); 92 | for (uint i = 200; i <= 255; ++i) 93 | { 94 | data = new PacketData(); 95 | data.sequence = i; 96 | packetQueue.insert_sorted(data, MaximumSequence); 97 | if (i > 201) 98 | packetQueue.verify_sorted(MaximumSequence); 99 | } 100 | for (uint i = 0; i <= 50; ++i) 101 | { 102 | data = new PacketData(); 103 | data.sequence = i; 104 | packetQueue.insert_sorted(data, MaximumSequence); 105 | if (i > 1) 106 | packetQueue.verify_sorted(MaximumSequence); 107 | } 108 | } 109 | void test_reliability_system() 110 | { 111 | const uint MaximumSequence = 255; 112 | Debug.Log(ReliabilitySystem.bit_index_for_sequence(255, 1, MaximumSequence)); 113 | ///////////////////////////////// 114 | print("check generate ack bits"); 115 | PacketQueue packetQueue = new PacketQueue(); 116 | for (uint i = 0; i < 32; ++i) 117 | { 118 | PacketData data = new PacketData(); 119 | data.sequence = i; 120 | packetQueue.insert_sorted(data, MaximumSequence); 121 | 122 | } 123 | packetQueue.verify_sorted(MaximumSequence); 124 | if (ReliabilitySystem.generate_ack_bits(32, ref packetQueue, MaximumSequence) == 0xFFFFFFFF) 125 | { 126 | Debug.Log("OK"); 127 | } 128 | if (ReliabilitySystem.generate_ack_bits(31, ref packetQueue, MaximumSequence) == 0x7FFFFFFF) 129 | { 130 | Debug.Log("OK"); 131 | } 132 | if (ReliabilitySystem.generate_ack_bits(33, ref packetQueue, MaximumSequence) == 0xFFFFFFFE) 133 | { 134 | Debug.Log("OK"); 135 | } 136 | if (ReliabilitySystem.generate_ack_bits(16, ref packetQueue, MaximumSequence) == 0x0000FFFF) 137 | { 138 | Debug.Log("OK"); 139 | } 140 | if (ReliabilitySystem.generate_ack_bits(48, ref packetQueue, MaximumSequence) == 0xFFFF0000) 141 | { 142 | Debug.Log("OK"); 143 | } 144 | 145 | ///////////////////////////////// 146 | print("check generate ack bits with wrap"); 147 | 148 | 149 | packetQueue.Clear(); 150 | for (uint i = 255 - 31; i <= 255; ++i) 151 | { 152 | PacketData data = new PacketData(); 153 | data.sequence = i; 154 | packetQueue.insert_sorted(data, MaximumSequence); 155 | 156 | } 157 | packetQueue.verify_sorted(MaximumSequence); 158 | if (packetQueue.Count == 32) 159 | { 160 | Debug.Log("ack wrap ok"); 161 | }; 162 | if (ReliabilitySystem.generate_ack_bits(0, ref packetQueue, MaximumSequence) == 0xFFFFFFFF) 163 | { 164 | Debug.Log("ack wrap ok"); 165 | }; 166 | if (ReliabilitySystem.generate_ack_bits(255, ref packetQueue, MaximumSequence) == 0x7FFFFFFF) 167 | { 168 | Debug.Log("ack wrap ok"); 169 | }; 170 | if (ReliabilitySystem.generate_ack_bits(1, ref packetQueue, MaximumSequence) == 0xFFFFFFFE) 171 | { 172 | Debug.Log("ack wrap ok"); 173 | }; 174 | if (ReliabilitySystem.generate_ack_bits(240, ref packetQueue, MaximumSequence) == 0x0000FFFF) 175 | { 176 | Debug.Log("ack wrap ok"); 177 | }; 178 | if (ReliabilitySystem.generate_ack_bits(16, ref packetQueue, MaximumSequence) == 0xFFFF0000) 179 | { 180 | Debug.Log("ack wrap ok"); 181 | }; 182 | 183 | print("check process ack (1)"); 184 | PacketQueue pendingAckQueue = new PacketQueue(); 185 | for (uint i = 0; i < 33; ++i) 186 | { 187 | PacketData data = new PacketData(); 188 | data.sequence = i; 189 | data.time = 0.0f; 190 | pendingAckQueue.insert_sorted(data, MaximumSequence); 191 | 192 | } 193 | pendingAckQueue.verify_sorted(MaximumSequence); 194 | PacketQueue ackedQueue = new PacketQueue(); 195 | List acks = new List(); 196 | float rtt = 0.0f; 197 | uint acked_packets = 0; 198 | ReliabilitySystem.process_ack(32, 0xFFFFFFFF, ref pendingAckQueue, ref ackedQueue, ref acks, acked_packets, rtt, MaximumSequence); 199 | if (acks.Count == 33) 200 | { 201 | Debug.Log("process ack (1) ok"); 202 | }; 203 | if (acked_packets == 33) 204 | { 205 | Debug.Log("process ack (1) ok"); 206 | }; 207 | if (ackedQueue.Count == 33) 208 | { 209 | Debug.Log("process ack (1) ok"); 210 | }; 211 | if (pendingAckQueue.Count == 0) 212 | { 213 | Debug.Log("process ack (1) ok"); 214 | }; 215 | ackedQueue.verify_sorted(MaximumSequence); 216 | for (int i = 0; i < acks.Count; ++i) 217 | { 218 | Debug.Log(acks[i]); 219 | } 220 | 221 | for (LinkedListNode node = ackedQueue.First; node != ackedQueue.Last.Next; node = node.Next) 222 | { 223 | Debug.Log(node.Value.sequence); 224 | } 225 | 226 | /////////////////////////////////////////////// 227 | print("check process ack (2)"); 228 | { 229 | PacketQueue pendingAckQueue2 = new PacketQueue(); 230 | for (uint i = 0; i < 33; ++i) 231 | { 232 | PacketData data = new PacketData(); 233 | data.sequence = i; 234 | data.time = 0.0f; 235 | pendingAckQueue2.insert_sorted(data, MaximumSequence); 236 | 237 | } 238 | pendingAckQueue2.verify_sorted(MaximumSequence); 239 | PacketQueue ackedQueue2 = new PacketQueue(); 240 | List acks2 = new List(); 241 | float rtt2 = 0.0f; 242 | uint acked_packets2 = 0; 243 | ReliabilitySystem.process_ack(32, 0x0000FFFF, ref pendingAckQueue2, ref ackedQueue2, ref acks2, acked_packets2, rtt2, MaximumSequence); 244 | if (acks2.Count == 17) 245 | { 246 | Debug.Log("process ack (2) ok"); 247 | }; 248 | if (acked_packets2 == 17) 249 | { 250 | Debug.Log("process ack (2) ok"); 251 | }; 252 | if (ackedQueue2.Count == 17) 253 | { 254 | Debug.Log("process ack (2) ok"); 255 | }; 256 | if (pendingAckQueue2.Count == 33 - 17) 257 | { 258 | Debug.Log("process ack (2) ok"); 259 | }; 260 | ackedQueue2.verify_sorted(MaximumSequence); 261 | for (LinkedListNode node = pendingAckQueue2.First; node != pendingAckQueue2.Last.Next; node = node.Next) 262 | { 263 | Debug.Log(node.Value.sequence); 264 | } 265 | print("==========================="); 266 | for (LinkedListNode node = ackedQueue2.First; node != ackedQueue2.Last.Next; node = node.Next) 267 | { 268 | Debug.Log(node.Value.sequence); 269 | } 270 | for (int i = 0; i < acks2.Count; ++i) 271 | { 272 | if (acks2[i] == i + 16) 273 | { 274 | Debug.Log("process ack (2) ok"); 275 | }; 276 | } 277 | 278 | } 279 | 280 | ////////////////////////////////////////////// 281 | print("check process ack (3)\n"); 282 | { 283 | PacketQueue pendingAckQueue3 = new PacketQueue(); 284 | for (uint i = 0; i < 32; ++i) 285 | { 286 | PacketData data = new PacketData(); 287 | data.sequence = i; 288 | data.time = 0.0f; 289 | pendingAckQueue3.insert_sorted(data, MaximumSequence); 290 | 291 | } 292 | pendingAckQueue3.verify_sorted(MaximumSequence); 293 | PacketQueue ackedQueue3 = new PacketQueue(); 294 | List acks3 = new List(); 295 | float rtt3 = 0.0f; 296 | uint acked_packets3 = 0; 297 | ReliabilitySystem.process_ack(48, 0xFFFF0000, ref pendingAckQueue3, ref ackedQueue3, ref acks3, acked_packets3, rtt3, MaximumSequence); 298 | if (acks3.Count == 16) 299 | { 300 | Debug.Log("process ack(3) ok"); 301 | }; 302 | if (acked_packets3 == 16) 303 | { 304 | Debug.Log("process ack(3) ok"); 305 | }; 306 | if (ackedQueue3.Count == 16) 307 | { 308 | Debug.Log("process ack(3) ok"); 309 | }; 310 | if (pendingAckQueue3.Count == 16) 311 | { 312 | Debug.Log("process ack(3) ok"); 313 | }; 314 | ackedQueue3.verify_sorted(MaximumSequence); 315 | 316 | for (LinkedListNode node = pendingAckQueue3.First; node != pendingAckQueue3.Last.Next; node = node.Next) 317 | { 318 | Debug.Log(node.Value.sequence); 319 | } 320 | print("==========================="); 321 | for (LinkedListNode node = ackedQueue3.First; node != ackedQueue3.Last.Next; node = node.Next) 322 | { 323 | Debug.Log(node.Value.sequence); 324 | } 325 | for (int i = 0; i < acks3.Count; ++i) 326 | { 327 | if (acks3[i] == i + 16) 328 | { 329 | Debug.Log("process ack (3) ok"); 330 | }; 331 | } 332 | } 333 | } 334 | 335 | void test_join() 336 | { 337 | print("-----------------------------------------------------"); 338 | print("test join"); 339 | print("-----------------------------------------------------"); 340 | 341 | ushort ServerPort = 19120; 342 | const int ClientPort = 19121; 343 | const int ProtocolId = 0x11112222; 344 | const float DeltaTime = 0.001f; 345 | const float TimeOut = 1.0f; 346 | 347 | ReliableConnection client = new ReliableConnection(ProtocolId, TimeOut); 348 | ReliableConnection server = new ReliableConnection(ProtocolId, TimeOut); 349 | 350 | if (!client.Start(ClientPort)) 351 | { 352 | Debug.LogError(""); 353 | }; 354 | if (!server.Start(ServerPort)) 355 | { 356 | Debug.LogError(""); 357 | }; 358 | System.Net.IPEndPoint addr = new System.Net.IPEndPoint(System.Net.IPAddress.Parse("127.0.0.1"), 1912); 359 | client.Connect(ref addr); 360 | server.Listen(); 361 | 362 | while (true) 363 | { 364 | if (client.IsConnected() && server.IsConnected()) 365 | break; 366 | 367 | if (!client.IsConnecting() && client.ConnectFailed()) 368 | break; 369 | 370 | byte[] client_packet = { 0x00, 0x10, 0x20, 0x30 }; 371 | client.SendPacket(client_packet, (client_packet.Length)); 372 | 373 | byte[] server_packet = { 0x01, 0x11, 0x21, 0x31 }; 374 | server.SendPacket(server_packet, (server_packet.Length)); 375 | 376 | while (true) 377 | { 378 | byte[] packet = new byte[256]; 379 | int bytes_read = client.ReceivePacket(ref packet, (packet.Length)); 380 | if (bytes_read == 0) 381 | break; 382 | } 383 | 384 | while (true) 385 | { 386 | byte[] packet = new byte[256]; 387 | int bytes_read = server.ReceivePacket(ref packet, (packet.Length)); 388 | if (bytes_read == 0) 389 | break; 390 | } 391 | 392 | client.Update(DeltaTime); 393 | server.Update(DeltaTime); 394 | } 395 | 396 | if (!client.IsConnected()) { Debug.LogError("client connect error"); }; 397 | if (!server.IsConnected()) { Debug.LogError("server connect error"); }; 398 | } 399 | void Start() 400 | { 401 | test_join(); 402 | } 403 | void Update() 404 | { 405 | 406 | } 407 | } --------------------------------------------------------------------------------