WebsocketFrame.cs 4.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155
  1. using System;
  2. using System.Text;
  3. namespace IFramework.Net.WebSocket
  4. {
  5. internal class WebsocketFrame : DataFrame
  6. {
  7. private Encoding encoding = Encoding.UTF8;
  8. private const string acceptMask = "258EAFA5-E914-47DA-95CA-C5AB0DC85B11";//固定字符串
  9. private readonly char[] splitChars =null;
  10. public WebsocketFrame()
  11. {
  12. splitChars = BaseInfo.SplitChars.ToCharArray();
  13. }
  14. public SegmentOffset RspAcceptedFrame(AccessInfo access)
  15. {
  16. var accept = new AcceptInfo()
  17. {
  18. Connection = access.Connection,
  19. Upgrade = access.Upgrade,
  20. SecWebSocketLocation = access.Host,
  21. SecWebSocketOrigin = access.Origin,
  22. SecWebSocketAccept = (access.SecWebSocketKey + acceptMask).ToSha1Base64(encoding)
  23. };
  24. return new SegmentOffset(encoding.GetBytes(accept.ToString()));
  25. }
  26. public AcceptInfo ParseAcceptedFrame(string msg)
  27. {
  28. string[] msgs = msg.Split(BaseInfo.NewLine.ToCharArray(),StringSplitOptions.RemoveEmptyEntries);
  29. var acceptInfo = new AcceptInfo
  30. {
  31. HttpProto = msgs[0]
  32. };
  33. foreach (var item in msgs)
  34. {
  35. string[] kv = item.Split(splitChars,StringSplitOptions.RemoveEmptyEntries);
  36. switch (kv[0])
  37. {
  38. case "Upgrade":
  39. acceptInfo.Upgrade = kv[1];
  40. break;
  41. case "Connection":
  42. acceptInfo.Connection = kv[1];
  43. break;
  44. case "Sec-WebSocket-Accept":
  45. acceptInfo.SecWebSocketAccept = kv[1];
  46. break;
  47. case "Sec-WebSocket-Location":
  48. acceptInfo.SecWebSocketLocation = kv[1];
  49. break;
  50. case "Sec-WebSocket-Origin":
  51. acceptInfo.SecWebSocketOrigin = kv[1];
  52. break;
  53. }
  54. }
  55. return acceptInfo;
  56. }
  57. public SegmentOffset ToSegmentFrame(string content)
  58. {
  59. var buf = encoding.GetBytes(content);
  60. Payload = new SegmentOffset()
  61. {
  62. buffer = buf
  63. };
  64. PayloadLength = Payload.buffer.LongLength;
  65. return new SegmentOffset(EncodingToBytes());
  66. }
  67. public SegmentOffset ToSegmentFrame(byte[] buf, OpCodeType code = OpCodeType.Text)
  68. {
  69. OpCode = (byte)code;
  70. Payload = new SegmentOffset()
  71. {
  72. buffer = buf
  73. };
  74. PayloadLength = Payload.buffer.LongLength;
  75. return new SegmentOffset(EncodingToBytes());
  76. }
  77. public SegmentOffset ToSegmentFrame(SegmentOffset data, OpCodeType code = OpCodeType.Text)
  78. {
  79. OpCode = (byte)code;
  80. Payload = data;
  81. PayloadLength = Payload.buffer.LongLength;
  82. return new SegmentOffset(EncodingToBytes());
  83. }
  84. public AccessInfo GetHandshakePackage(SegmentOffset segOffset)
  85. {
  86. string msg = encoding.GetString(segOffset.buffer, segOffset.offset, segOffset.size);
  87. string[] items = msg.Split(BaseInfo.NewLine.ToCharArray(), StringSplitOptions.RemoveEmptyEntries);
  88. if (items.Length < 6)
  89. throw new Exception("access format error..." + msg);
  90. AccessInfo access = new AccessInfo()
  91. {
  92. HttpProto = items[0]
  93. };
  94. foreach (var item in items)
  95. {
  96. string[] kv = item.Split(splitChars,StringSplitOptions.RemoveEmptyEntries);
  97. switch (kv[0])
  98. {
  99. case "Connection":
  100. access.Connection = kv[1];
  101. break;
  102. case "Host":
  103. access.Host = kv[1];
  104. break;
  105. case "Origin":
  106. access.Origin = kv[1];
  107. break;
  108. case "Upgrade":
  109. access.Upgrade = kv[1];
  110. break;
  111. case "Sec-WebSocket-Key":
  112. access.SecWebSocketKey = kv[1];
  113. break;
  114. case "Sec-WebSocket-Version":
  115. access.SecWebSocketVersion = kv[1];
  116. break;
  117. case "Sec-WebSocket-Extensions":
  118. access.SecWebSocketExtensions = kv[1];
  119. break;
  120. }
  121. }
  122. return access;
  123. }
  124. }
  125. [Flags]
  126. internal enum OpCodeType : byte
  127. {
  128. Attach = 0x0,
  129. Text = 0x1,
  130. Bin = 0x2,
  131. Close = 0x8,
  132. Bing = 0x9,
  133. Bong = 0xA,
  134. }
  135. }