/// <summary>从队列消费消息并推送到WebSocket客户端</summary> /// <param name="socket"></param> /// <param name="queue"></param> /// <param name="source"></param> /// <returns></returns> public static async Task ConsumeAndPushAsync(this System.Net.WebSockets.WebSocket socket, IProducerConsumer <String> queue, CancellationTokenSource source) { var token = source.Token; //var queue = _queue.GetQueue<String>($"cmd:{node.Code}"); try { while (!token.IsCancellationRequested && socket.State == System.Net.WebSockets.WebSocketState.Open) { var msg = await queue.TakeOneAsync(30_000); if (msg != null) { await socket.SendAsync(new ArraySegment <Byte>(msg.GetBytes()), System.Net.WebSockets.WebSocketMessageType.Text, true, token); } else { await Task.Delay(100, token); } } } catch (Exception ex) { XTrace.WriteException(ex); } finally { //if (token.GetValue("_source") is CancellationTokenSource source) source.Cancel(); source.Cancel(); } }
// ------------------------------------------------------------------------------------ public System.Threading.Tasks.Task SendAsync( System.Net.WebSockets.WebSocket WS, System.Threading.CancellationTokenSource cts_shutdown) { return(WS.SendAsync( new ArraySegment <byte>(m_ary_buf, 0, m_idx_byte) , System.Net.WebSockets.WebSocketMessageType.Binary, true // endOfMessage , cts_shutdown.Token)); }
public async Task SendMessage(string message) { var messageArr = socketEncoding.Encode(message); if(messageArr.Length > options.ReceiveBufferSize) { bool isEnd = false; int count = 0; for (int i = 0; i < messageArr.Length; i = i+ options.ReceiveBufferSize) { count = messageArr.Length > i + options.ReceiveBufferSize ? options.ReceiveBufferSize : messageArr.Length - i; isEnd = count != options.ReceiveBufferSize; await socket.SendAsync(new ArraySegment<byte>(messageArr, i, count),System.Net.WebSockets.WebSocketMessageType.Text, isEnd, CancellationToken.None); } logger.LogInformation($"{ "Received message is \t" + message }"); } else { await socket.SendAsync(new ArraySegment<byte>(messageArr,0,messageArr.Length), System.Net.WebSockets.WebSocketMessageType.Text, true, CancellationToken.None); } }
// https://docs.microsoft.com/en-us/aspnet/core/fundamentals/websockets?view=aspnetcore-2.1 private static async System.Threading.Tasks.Task Echo( Microsoft.AspNetCore.Http.HttpContext context , System.Net.WebSockets.WebSocket webSocket) { WebSocketTextWriter wtw = new WebSocketTextWriter(webSocket); byte[] buffer = new byte[1024 * 4]; System.Net.WebSockets.WebSocketReceiveResult result = await webSocket.ReceiveAsync( new System.ArraySegment <byte>(buffer) , System.Threading.CancellationToken.None ); while (!result.CloseStatus.HasValue) { //string answer = @"The server received the following message: "; //byte[] answerBuffer = System.Text.Encoding.UTF8.GetBytes(answer); //await webSocket.SendAsync( // new ArraySegment<byte>(answerBuffer, 0, answerBuffer.Length) // , System.Net.WebSockets.WebSocketMessageType.Text // , false, System.Threading.CancellationToken.None //); wtw.WriteLine("Test 123"); await wtw.TransmitAsync(); wtw.WriteLine("Test 456"); await wtw.TransmitAsync(); wtw.WriteLine("Echo: "); await wtw.FlushAsync(); wtw.Write(@"The server received the following message: "); await wtw.FlushAsync(); // wtw.Send(false, new byte[0]); await webSocket.SendAsync( new System.ArraySegment <byte>(buffer, 0, result.Count) , result.MessageType , result.EndOfMessage , System.Threading.CancellationToken.None ); result = await webSocket.ReceiveAsync( new System.ArraySegment <byte>(buffer) , System.Threading.CancellationToken.None ); } // Whend await webSocket.CloseAsync(result.CloseStatus.Value, result.CloseStatusDescription, System.Threading.CancellationToken.None); } // End Task Echo
public override void Write(byte[] buffer, int offset, int count) { try { webSocket.SendAsync( new ArraySegment <byte>(buffer, offset, count), System.Net.WebSockets.WebSocketMessageType.Binary, true, cts.Token) .Wait(); } catch { cts.Cancel(); } }
public static async Task SendAsync(this System.Net.WebSockets.WebSocket webSocket, string msg) { try { await Task.Run(() => { var buffer = Encoding.UTF8.GetBytes(msg); var arrSegment = new ArraySegment <byte>(buffer, 0, buffer.Length); lock (lockObj) { webSocket.SendAsync(arrSegment, System.Net.WebSockets.WebSocketMessageType.Text, true, CancellationToken.None); } }); } catch (Exception exc) { Console.WriteLine("wx 执行的错误"); Console.WriteLine(exc.Message); } }
/// <summary> /// Invoked when this handler is determined to be the best suited to handle the supplied connection. /// </summary> /// <param name="context"> /// The HTTP context. /// </param> /// <returns> /// The handling task. /// </returns> public override async Task Handle(HttpContext context) { ClientWebSocket wsServer = null; System.Net.WebSockets.WebSocket wsClient = null; try { // First we need the URL for this connection, since it's been requested to be // upgraded to a websocket. var connFeature = context.Features.Get <IHttpRequestFeature>(); string fullUrl = string.Empty; if (connFeature != null && connFeature.RawTarget != null && !string.IsNullOrEmpty(connFeature.RawTarget) && !(string.IsNullOrWhiteSpace(connFeature.RawTarget))) { fullUrl = $"{context.Request.Scheme}://{context.Request.Host}{connFeature.RawTarget}"; } else { fullUrl = $"{context.Request.Scheme}://{context.Request.Host}{context.Request.Path}{context.Request.QueryString}"; } // Need to replate the scheme with appropriate websocket scheme. if (fullUrl.StartsWith("http://", StringComparison.OrdinalIgnoreCase)) { fullUrl = "ws://" + fullUrl.Substring(7); } else if (fullUrl.StartsWith("https://", StringComparison.OrdinalIgnoreCase)) { fullUrl = "wss://" + fullUrl.Substring(8); } // Next we need to try and parse the URL as a URI, because the websocket client // requires this for connecting upstream. if (!Uri.TryCreate(fullUrl, UriKind.RelativeOrAbsolute, out Uri wsUri)) { LoggerProxy.Default.Error("Failed to parse websocket URI."); return; } // Create the websocket that's going to connect to the remote server. wsServer = new ClientWebSocket(); wsServer.Options.Cookies = new System.Net.CookieContainer(); //wsServer.Options.SetBuffer((int)ushort.MaxValue * 16, (int)ushort.MaxValue * 16); foreach (var proto in context.WebSockets.WebSocketRequestedProtocols) { wsServer.Options.AddSubProtocol(proto); } foreach (var hdr in context.Request.Headers) { if (!ForbiddenWsHeaders.IsForbidden(hdr.Key)) { try { wsServer.Options.SetRequestHeader(hdr.Key, hdr.Value.ToString()); } catch (Exception hdrException) { LoggerProxy.Default.Error(hdrException); } } } foreach (var cookie in context.Request.Cookies) { try { wsServer.Options.Cookies.Add(new Uri(fullUrl, UriKind.Absolute), new System.Net.Cookie(cookie.Key, System.Net.WebUtility.UrlEncode(cookie.Value))); } catch (Exception e) { LoggerProxy.Default.Error("Error while attempting to add websocket cookie."); LoggerProxy.Default.Error(e); } } if (context.Connection.ClientCertificate != null) { wsServer.Options.ClientCertificates = new System.Security.Cryptography.X509Certificates.X509CertificateCollection(new[] { context.Connection.ClientCertificate.ToV2Certificate() }); } // Connect the server websocket to the upstream, remote webserver. await wsServer.ConnectAsync(wsUri, context.RequestAborted); foreach (string key in wsServer.ResponseHeaders) { if (!ForbiddenWsHeaders.IsForbidden(key)) { try { var value = wsServer.ResponseHeaders[key]; context.Response.Headers[key] = wsServer.ResponseHeaders[key]; } catch (Exception hdrException) { LoggerProxy.Default.Error(hdrException); } } } // Create, via acceptor, the client websocket. This is the local machine's websocket. wsClient = await context.WebSockets.AcceptWebSocketAsync(wsServer.SubProtocol ?? null); // Match the HTTP version of the client on the upstream request. We don't want to // transparently pass around headers that are wrong for the client's HTTP version. Version upstreamReqVersionMatch = null; Match match = s_httpVerRegex.Match(context.Request.Protocol); if (match != null && match.Success) { upstreamReqVersionMatch = Version.Parse(match.Value); } var msgNfo = new HttpMessageInfo { Url = wsUri, Method = new HttpMethod(context.Request.Method), IsEncrypted = context.Request.IsHttps, Headers = context.Request.Headers.ToNameValueCollection(), HttpVersion = upstreamReqVersionMatch ?? new Version(1, 0), MessageProtocol = MessageProtocol.WebSocket, MessageType = MessageType.Request, RemoteAddress = context.Connection.RemoteIpAddress, RemotePort = (ushort)context.Connection.RemotePort, LocalAddress = context.Connection.LocalIpAddress, LocalPort = (ushort)context.Connection.LocalPort }; _configuration.NewHttpMessageHandler?.Invoke(msgNfo); switch (msgNfo.ProxyNextAction) { case ProxyNextAction.DropConnection: { await wsClient.CloseAsync(System.Net.WebSockets.WebSocketCloseStatus.NormalClosure, string.Empty, CancellationToken.None); return; } } var serverMessageInfo = new HttpMessageInfo { Url = wsUri, MessageId = msgNfo.MessageId, Method = new HttpMethod(context.Request.Method), IsEncrypted = context.Request.IsHttps, Headers = context.Request.Headers.ToNameValueCollection(), HttpVersion = upstreamReqVersionMatch ?? new Version(1, 0), MessageProtocol = MessageProtocol.WebSocket, MessageType = MessageType.Response, RemoteAddress = context.Connection.RemoteIpAddress, RemotePort = (ushort)context.Connection.RemotePort, LocalAddress = context.Connection.LocalIpAddress, LocalPort = (ushort)context.Connection.LocalPort }; var clientMessageInfo = new HttpMessageInfo { Url = wsUri, MessageId = msgNfo.MessageId, IsEncrypted = context.Request.IsHttps, Headers = context.Request.Headers.ToNameValueCollection(), HttpVersion = upstreamReqVersionMatch ?? new Version(1, 0), MessageProtocol = MessageProtocol.WebSocket, MessageType = MessageType.Request, RemoteAddress = context.Connection.RemoteIpAddress, RemotePort = (ushort)context.Connection.RemotePort, LocalAddress = context.Connection.LocalIpAddress, LocalPort = (ushort)context.Connection.LocalPort }; bool inspect = true; switch (msgNfo.ProxyNextAction) { case ProxyNextAction.AllowAndIgnoreContent: case ProxyNextAction.AllowAndIgnoreContentAndResponse: { inspect = false; } break; } // Spawn an async task that will poll the remote server for data in a loop, and then // write any data it gets to the client websocket. var serverTask = Task.Run(async() => { System.Net.WebSockets.WebSocketReceiveResult serverResult = null; var serverBuffer = new byte[1024 * 4]; try { bool looping = true; serverResult = await wsServer.ReceiveAsync(new ArraySegment <byte>(serverBuffer), context.RequestAborted); while (looping && !serverResult.CloseStatus.HasValue && !context.RequestAborted.IsCancellationRequested) { if (inspect) { serverMessageInfo.Body = new Memory <byte>(serverBuffer, 0, serverResult.Count); switch (serverResult.MessageType) { case System.Net.WebSockets.WebSocketMessageType.Binary: { serverMessageInfo.BodyContentType = s_octetStreamContentType; } break; case System.Net.WebSockets.WebSocketMessageType.Text: { serverMessageInfo.BodyContentType = s_plainTextContentType; } break; } _configuration.HttpMessageWholeBodyInspectionHandler?.Invoke(serverMessageInfo); } switch (serverMessageInfo.ProxyNextAction) { case ProxyNextAction.DropConnection: { looping = false; } break; default: { await wsClient.SendAsync(new ArraySegment <byte>(serverBuffer, 0, serverResult.Count), serverResult.MessageType, serverResult.EndOfMessage, context.RequestAborted); if (!wsClient.CloseStatus.HasValue) { serverResult = await wsServer.ReceiveAsync(new ArraySegment <byte>(serverBuffer), context.RequestAborted); continue; } } break; } looping = false; } await wsClient.CloseAsync(serverResult.CloseStatus.Value, serverResult.CloseStatusDescription, context.RequestAborted); } catch (Exception err) { LoggerProxy.Default.Error(err); try { var closeStatus = serverResult?.CloseStatus ?? System.Net.WebSockets.WebSocketCloseStatus.NormalClosure; var closeMessage = serverResult?.CloseStatusDescription ?? string.Empty; await wsClient.CloseAsync(closeStatus, closeMessage, context.RequestAborted); } catch { } } }); // Spawn an async task that will poll the local client websocket, in a loop, and then // write any data it gets to the remote server websocket. var clientTask = Task.Run(async() => { System.Net.WebSockets.WebSocketReceiveResult clientResult = null; var clientBuffer = new byte[1024 * 4]; try { bool looping = true; clientResult = await wsClient.ReceiveAsync(new ArraySegment <byte>(clientBuffer), context.RequestAborted); while (looping && !clientResult.CloseStatus.HasValue && !context.RequestAborted.IsCancellationRequested) { if (inspect) { clientMessageInfo.Body = new Memory <byte>(clientBuffer, 0, clientResult.Count); switch (clientResult.MessageType) { case System.Net.WebSockets.WebSocketMessageType.Binary: { clientMessageInfo.BodyContentType = s_octetStreamContentType; } break; case System.Net.WebSockets.WebSocketMessageType.Text: { clientMessageInfo.BodyContentType = s_plainTextContentType; } break; } _configuration.HttpMessageWholeBodyInspectionHandler?.Invoke(clientMessageInfo); } switch (clientMessageInfo.ProxyNextAction) { case ProxyNextAction.DropConnection: { looping = false; } break; default: { await wsServer.SendAsync(new ArraySegment <byte>(clientBuffer, 0, clientResult.Count), clientResult.MessageType, clientResult.EndOfMessage, context.RequestAborted); if (!wsServer.CloseStatus.HasValue) { clientResult = await wsClient.ReceiveAsync(new ArraySegment <byte>(clientBuffer), context.RequestAborted); continue; } } break; } looping = false; } await wsServer.CloseAsync(clientResult.CloseStatus.Value, clientResult.CloseStatusDescription, context.RequestAborted); } catch (Exception err) { LoggerProxy.Default.Error(err); try { var closeStatus = clientResult?.CloseStatus ?? System.Net.WebSockets.WebSocketCloseStatus.NormalClosure; var closeMessage = clientResult?.CloseStatusDescription ?? string.Empty; await wsServer.CloseAsync(closeStatus, closeMessage, context.RequestAborted); } catch { } } }); // Above, we have created a bridge between the local and remote websocket. Wait for // both associated tasks to complete. await Task.WhenAll(serverTask, clientTask); } catch (Exception wshe) { LoggerProxy.Default.Error(wshe); } finally { if (wsClient != null) { wsClient.Dispose(); wsClient = null; } if (wsServer != null) { wsServer.Dispose(); wsServer = null; } } }
public override async Task Handle(HttpContext context) { ClientWebSocket wsServer = null; System.Net.WebSockets.WebSocket wsClient = null; try { // First we need the URL for this connection, since it's been requested to be upgraded to // a websocket. var fullUrl = Microsoft.AspNetCore.Http.Extensions.UriHelper.GetDisplayUrl(context.Request); // Need to replate the scheme with appropriate websocket scheme. if (fullUrl.StartsWith("http://")) { fullUrl = "ws://" + fullUrl.Substring(7); } else if (fullUrl.StartsWith("https://")) { fullUrl = "wss://" + fullUrl.Substring(8); } // Next we need to try and parse the URL as a URI, because the websocket client requires // this for connecting upstream. if (!Uri.TryCreate(fullUrl, UriKind.RelativeOrAbsolute, out Uri wsUri)) { LoggerProxy.Default.Error("Failed to parse websocket URI."); return; } // Create the websocket that's going to connect to the remote server. wsServer = new ClientWebSocket(); wsServer.Options.Cookies = new System.Net.CookieContainer(); wsServer.Options.SetBuffer((int)ushort.MaxValue * 16, (int)ushort.MaxValue * 16); foreach (var cookie in context.Request.Cookies) { try { wsServer.Options.Cookies.Add(new Uri(fullUrl, UriKind.Absolute), new System.Net.Cookie(cookie.Key, System.Net.WebUtility.UrlEncode(cookie.Value))); } catch (Exception e) { LoggerProxy.Default.Error("Error while attempting to add websocket cookie."); LoggerProxy.Default.Error(e); } } if (context.Connection.ClientCertificate != null) { wsServer.Options.ClientCertificates = new System.Security.Cryptography.X509Certificates.X509CertificateCollection(new[] { context.Connection.ClientCertificate.ToV2Certificate() }); } var reqHeaderBuilder = new StringBuilder(); foreach (var hdr in context.Request.Headers) { if (!ForbiddenWsHeaders.IsForbidden(hdr.Key)) { reqHeaderBuilder.AppendFormat("{0}: {1}\r\n", hdr.Key, hdr.Value.ToString()); try { wsServer.Options.SetRequestHeader(hdr.Key, hdr.Value.ToString()); Console.WriteLine("Set Header: {0} ::: {1}", hdr.Key, hdr.Value.ToString()); } catch (Exception hdrException) { Console.WriteLine("Failed Header: {0} ::: {1}", hdr.Key, hdr.Value.ToString()); LoggerProxy.Default.Error(hdrException); } } } reqHeaderBuilder.Append("\r\n"); LoggerProxy.Default.Info(string.Format("Connecting websocket to {0}", wsUri.AbsoluteUri)); // Connect the server websocket to the upstream, remote webserver. await wsServer.ConnectAsync(wsUri, context.RequestAborted); LoggerProxy.Default.Info(String.Format("Connected websocket to {0}", wsUri.AbsoluteUri)); // Create, via acceptor, the client websocket. This is the local machine's websocket. wsClient = await context.WebSockets.AcceptWebSocketAsync(wsServer.SubProtocol ?? null); ProxyNextAction nxtAction = ProxyNextAction.AllowAndIgnoreContentAndResponse; string customResponseContentType = string.Empty; byte[] customResponse = null; m_msgBeginCb?.Invoke(wsUri, reqHeaderBuilder.ToString(), null, context.Request.IsHttps ? MessageType.SecureWebSocket : MessageType.WebSocket, MessageDirection.Request, out nxtAction, out customResponseContentType, out customResponse); switch (nxtAction) { case ProxyNextAction.DropConnection: { if (customResponse != null) { } await wsClient.CloseAsync(System.Net.WebSockets.WebSocketCloseStatus.NormalClosure, string.Empty, CancellationToken.None); return; } } // Spawn an async task that will poll the remote server for data in a loop, and then // write any data it gets to the client websocket. var serverTask = Task.Run(async() => { System.Net.WebSockets.WebSocketReceiveResult serverStatus = null; var serverBuffer = new byte[1024 * 4]; try { bool looping = true; serverStatus = await wsServer.ReceiveAsync(new ArraySegment <byte>(serverBuffer), context.RequestAborted); while (looping && !serverStatus.CloseStatus.HasValue && !context.RequestAborted.IsCancellationRequested) { await wsClient.SendAsync(new ArraySegment <byte>(serverBuffer, 0, serverStatus.Count), serverStatus.MessageType, serverStatus.EndOfMessage, context.RequestAborted); if (!wsClient.CloseStatus.HasValue) { serverStatus = await wsServer.ReceiveAsync(new ArraySegment <byte>(serverBuffer), context.RequestAborted); continue; } looping = false; } await wsClient.CloseAsync(serverStatus.CloseStatus.Value, serverStatus.CloseStatusDescription, context.RequestAborted); } catch { try { var closeStatus = serverStatus?.CloseStatus ?? System.Net.WebSockets.WebSocketCloseStatus.NormalClosure; var closeMessage = serverStatus?.CloseStatusDescription ?? string.Empty; await wsClient.CloseAsync(closeStatus, closeMessage, context.RequestAborted); } catch { } } }); // Spawn an async task that will poll the local client websocket, in a loop, and then // write any data it gets to the remote server websocket. var clientTask = Task.Run(async() => { System.Net.WebSockets.WebSocketReceiveResult clientResult = null; var clientBuffer = new byte[1024 * 4]; try { bool looping = true; clientResult = await wsClient.ReceiveAsync(new ArraySegment <byte>(clientBuffer), context.RequestAborted); while (looping && !clientResult.CloseStatus.HasValue && !context.RequestAborted.IsCancellationRequested) { await wsServer.SendAsync(new ArraySegment <byte>(clientBuffer, 0, clientResult.Count), clientResult.MessageType, clientResult.EndOfMessage, context.RequestAborted); if (!wsServer.CloseStatus.HasValue) { clientResult = await wsClient.ReceiveAsync(new ArraySegment <byte>(clientBuffer), context.RequestAborted); continue; } looping = false; } await wsServer.CloseAsync(clientResult.CloseStatus.Value, clientResult.CloseStatusDescription, context.RequestAborted); } catch { try { var closeStatus = clientResult?.CloseStatus ?? System.Net.WebSockets.WebSocketCloseStatus.NormalClosure; var closeMessage = clientResult?.CloseStatusDescription ?? string.Empty; await wsServer.CloseAsync(closeStatus, closeMessage, context.RequestAborted); } catch { } } }); // Above, we have created a bridge between the local and remote websocket. Wait for both // associated tasks to complete. await Task.WhenAll(serverTask, clientTask); } catch (Exception wshe) { if (wshe is System.Net.WebSockets.WebSocketException) { var cast = wshe as System.Net.WebSockets.WebSocketException; Console.WriteLine(cast.WebSocketErrorCode); if (cast.Data != null) { foreach (KeyValuePair <object, object> kvp in cast.Data) { Console.WriteLine("{0} ::: {1}", kvp.Key, kvp.Value); } } } LoggerProxy.Default.Error(wshe); } finally { if (wsClient != null) { wsClient.Dispose(); wsClient = null; } if (wsServer != null) { wsServer.Dispose(); wsServer = null; } } }
public async Task Invoke(HttpContext httpContext, IHostingEnvironment hostingEnvironment) { if (httpContext.WebSockets.IsWebSocketRequest) { //升级协议,建立链接。返回代表此链接的websocket对象。 socket = await httpContext.WebSockets.AcceptWebSocketAsync(); var buffer = new byte[options.ReceiveBufferSize]; List <byte> msgArr = new List <byte>(); //开始侦听socket,获取消息。此时可以向客户端发送消息。 //接收到消息后,消息将传入到buffer中。 //WebSocketResult 消息接收结果。 //result.CloseStatus 关闭状态 //result.CloseStatusDescription 关闭状态描述 //result.Count 接收的消息长度 //result.EndOfMessage 是否已经接受完毕 //result.MessageType 消息类型 Text(文字,默认UTF-8编码),Binary(二进制),Close(关闭消息); var result = await socket.ReceiveAsync(new ArraySegment <byte>(buffer), CancellationToken.None); //当关闭状态没有值时: while (!result.CloseStatus.HasValue) { msgArr.Clear(); //循环接收消息。 while (!result.EndOfMessage) { msgArr.AddRange(new ArraySegment <byte>(buffer, 0, result.Count)); result = await socket.ReceiveAsync(new ArraySegment <byte>(buffer), CancellationToken.None); } msgArr.AddRange(new ArraySegment <byte>(buffer, 0, result.Count)); switch (result.MessageType) { case System.Net.WebSockets.WebSocketMessageType.Binary: try { var fileName = Path.Combine(hostingEnvironment.WebRootPath, Guid.NewGuid().ToString() + ".png"); using (FileStream fileStream = new FileStream(fileName, FileMode.OpenOrCreate)) { await fileStream.WriteAsync(msgArr.ToArray(), 0, msgArr.Count()); } } catch (FileNotFoundException fileNotFound) { await socket.SendAsync(new ArraySegment <byte>(socketEncoding.Encode(fileNotFound.Message)), System.Net.WebSockets.WebSocketMessageType.Text, true, CancellationToken.None); } catch (InvalidOperationException inEx) { await socket.SendAsync(new ArraySegment <byte>(socketEncoding.Encode(inEx.Message)), System.Net.WebSockets.WebSocketMessageType.Text, true, CancellationToken.None); } catch (Exception e) { await socket.SendAsync(new ArraySegment <byte>(socketEncoding.Encode(e.Message)), System.Net.WebSockets.WebSocketMessageType.Text, true, CancellationToken.None); } break; case System.Net.WebSockets.WebSocketMessageType.Close: //关闭链接。 await socket.CloseAsync(System.Net.WebSockets.WebSocketCloseStatus.NormalClosure, "客户端关闭", CancellationToken.None); break; case System.Net.WebSockets.WebSocketMessageType.Text: //获取客户端发送的消息。消息编码,采用UTF8 var message = socketEncoding.Decode(msgArr.ToArray()); //回显数据 await SendMessage("OK \t" + message); break; default: break; } result = await socket.ReceiveAsync(new ArraySegment <byte>(buffer), CancellationToken.None); } } else { await _next(httpContext); } }
/// <summary> /// Invoked when this handler is determined to be the best suited to handle the supplied connection. /// </summary> /// <param name="context"> /// The HTTP context. /// </param> /// <returns> /// The handling task. /// </returns> public override async Task Handle(HttpContext context) { ClientWebSocket wsServer = null; System.Net.WebSockets.WebSocket wsClient = null; DiagnosticsWebSession diagSession = new DiagnosticsWebSession(); try { // First we need the URL for this connection, since it's been requested to be upgraded to // a websocket. var fullUrl = Microsoft.AspNetCore.Http.Extensions.UriHelper.GetDisplayUrl(context.Request); // Need to replate the scheme with appropriate websocket scheme. if (fullUrl.StartsWith("http://", StringComparison.OrdinalIgnoreCase)) { fullUrl = "ws://" + fullUrl.Substring(7); } else if (fullUrl.StartsWith("https://", StringComparison.OrdinalIgnoreCase)) { fullUrl = "wss://" + fullUrl.Substring(8); } diagSession.ClientRequestUri = fullUrl; // Next we need to try and parse the URL as a URI, because the websocket client requires // this for connecting upstream. if (!Uri.TryCreate(fullUrl, UriKind.RelativeOrAbsolute, out Uri wsUri)) { LoggerProxy.Default.Error("Failed to parse websocket URI."); return; } // Create the websocket that's going to connect to the remote server. wsServer = new ClientWebSocket(); wsServer.Options.Cookies = new System.Net.CookieContainer(); wsServer.Options.SetBuffer((int)ushort.MaxValue * 16, (int)ushort.MaxValue * 16); foreach (var cookie in context.Request.Cookies) { try { wsServer.Options.Cookies.Add(new Uri(fullUrl, UriKind.Absolute), new System.Net.Cookie(cookie.Key, System.Net.WebUtility.UrlEncode(cookie.Value))); } catch (Exception e) { LoggerProxy.Default.Error("Error while attempting to add websocket cookie."); LoggerProxy.Default.Error(e); } } if (context.Connection.ClientCertificate != null) { wsServer.Options.ClientCertificates = new System.Security.Cryptography.X509Certificates.X509CertificateCollection(new[] { context.Connection.ClientCertificate.ToV2Certificate() }); } if (Collector.IsDiagnosticsEnabled) { var diagHeaderBuilder = new StringBuilder(); foreach (var hdr in context.Request.Headers) { diagHeaderBuilder.AppendFormat($"{hdr.Key}: {hdr.Value.ToString()}\r\n"); } diagSession.ClientRequestHeaders = diagHeaderBuilder.ToString(); } var reqHeaderBuilder = new StringBuilder(); foreach (var hdr in context.Request.Headers) { if (!ForbiddenWsHeaders.IsForbidden(hdr.Key)) { reqHeaderBuilder.AppendFormat("{0}: {1}\r\n", hdr.Key, hdr.Value.ToString()); try { wsServer.Options.SetRequestHeader(hdr.Key, hdr.Value.ToString()); } catch (Exception hdrException) { LoggerProxy.Default.Error(hdrException); } } } reqHeaderBuilder.Append("\r\n"); diagSession.ServerRequestHeaders = reqHeaderBuilder.ToString(); // Connect the server websocket to the upstream, remote webserver. await wsServer.ConnectAsync(wsUri, context.RequestAborted); // Create, via acceptor, the client websocket. This is the local machine's websocket. wsClient = await context.WebSockets.AcceptWebSocketAsync(wsServer.SubProtocol ?? null); var msgNfo = new HttpMessageInfo { Url = wsUri, IsEncrypted = context.Request.IsHttps, Headers = context.Request.Headers.ToNameValueCollection(), MessageProtocol = MessageProtocol.WebSocket, MessageType = MessageType.Request, RemoteAddress = context.Connection.RemoteIpAddress, RemotePort = (ushort)context.Connection.RemotePort, LocalAddress = context.Connection.LocalIpAddress, LocalPort = (ushort)context.Connection.LocalPort }; _newMessageCb?.Invoke(msgNfo); switch (msgNfo.ProxyNextAction) { case ProxyNextAction.DropConnection: { await wsClient.CloseAsync(System.Net.WebSockets.WebSocketCloseStatus.NormalClosure, string.Empty, CancellationToken.None); return; } } // Spawn an async task that will poll the remote server for data in a loop, and then // write any data it gets to the client websocket. var serverTask = Task.Run(async() => { System.Net.WebSockets.WebSocketReceiveResult serverStatus = null; var serverBuffer = new byte[1024 * 4]; try { bool looping = true; serverStatus = await wsServer.ReceiveAsync(new ArraySegment <byte>(serverBuffer), context.RequestAborted); while (looping && !serverStatus.CloseStatus.HasValue && !context.RequestAborted.IsCancellationRequested) { await wsClient.SendAsync(new ArraySegment <byte>(serverBuffer, 0, serverStatus.Count), serverStatus.MessageType, serverStatus.EndOfMessage, context.RequestAborted); if (!wsClient.CloseStatus.HasValue) { serverStatus = await wsServer.ReceiveAsync(new ArraySegment <byte>(serverBuffer), context.RequestAborted); continue; } looping = false; } await wsClient.CloseAsync(serverStatus.CloseStatus.Value, serverStatus.CloseStatusDescription, context.RequestAborted); } catch { try { var closeStatus = serverStatus?.CloseStatus ?? System.Net.WebSockets.WebSocketCloseStatus.NormalClosure; var closeMessage = serverStatus?.CloseStatusDescription ?? string.Empty; await wsClient.CloseAsync(closeStatus, closeMessage, context.RequestAborted); } catch { } } }); // Spawn an async task that will poll the local client websocket, in a loop, and then // write any data it gets to the remote server websocket. var clientTask = Task.Run(async() => { System.Net.WebSockets.WebSocketReceiveResult clientResult = null; var clientBuffer = new byte[1024 * 4]; try { bool looping = true; clientResult = await wsClient.ReceiveAsync(new ArraySegment <byte>(clientBuffer), context.RequestAborted); while (looping && !clientResult.CloseStatus.HasValue && !context.RequestAborted.IsCancellationRequested) { await wsServer.SendAsync(new ArraySegment <byte>(clientBuffer, 0, clientResult.Count), clientResult.MessageType, clientResult.EndOfMessage, context.RequestAborted); if (!wsServer.CloseStatus.HasValue) { clientResult = await wsClient.ReceiveAsync(new ArraySegment <byte>(clientBuffer), context.RequestAborted); continue; } looping = false; } await wsServer.CloseAsync(clientResult.CloseStatus.Value, clientResult.CloseStatusDescription, context.RequestAborted); } catch { try { var closeStatus = clientResult?.CloseStatus ?? System.Net.WebSockets.WebSocketCloseStatus.NormalClosure; var closeMessage = clientResult?.CloseStatusDescription ?? string.Empty; await wsServer.CloseAsync(closeStatus, closeMessage, context.RequestAborted); } catch { } } }); // Above, we have created a bridge between the local and remote websocket. Wait for both // associated tasks to complete. await Task.WhenAll(serverTask, clientTask); } catch (Exception wshe) { LoggerProxy.Default.Error(wshe); } finally { Collector.ReportSession(diagSession); if (wsClient != null) { wsClient.Dispose(); wsClient = null; } if (wsServer != null) { wsServer.Dispose(); wsServer = null; } } }