ASP를 사용하여 WebSocket에 대해 알아보십시오.그물심

19966 단어 csharptutorialdotnet
이 문서에서는 RFC6455WebSockets 사양을 소개하고 일반적인 ASP를 구성합니다.NET(핵심)5 앱은 웹소켓 연결을 통해 신호기와 통신한다.우리는 표지 아래에서 발생하는 일을 이해하기 위해 기본 개념을 깊이 이해할 것이다.

WebSocket 정보


웹소켓의 도입은 클라이언트와 서버 간의 양방향 통신을 실현하기 위한 것이다.HTTP 1.0의 어려움 중 하나는 서버에 요청을 보낼 때마다 연결을 만들고 닫는 것이다.그러나 HTTP 1.1에서 (RFC 2616) 는 활성 유지 메커니즘을 사용하여 도입되었습니다.이러한 방식을 통해 연결은 여러 개의 요청에 중복될 수 있다. 이는 서버가 클라이언트의 상황을 알고 있으며, 매번 요청할 때마다 악수 과정을 다시 시작할 필요가 없기 때문이다.

💡 When you are learning about protocols, a good place to start is to read its corresponding RFC specification.


WebSockets는 지속적인 연결을 허용하기 때문에 HTTP 1.1 사양 위에 구축됩니다.따라서 WebSocket 연결을 처음 만들 때, 이것은 본질적으로 HTTP 1.1 요청입니다. (잠시 후에 이것에 대해 상세하게 설명할 것입니다.)이것은 클라이언트와 서버 간에 실시간 통신을 할 수 있게 한다.간단히 말해서 다음 그림은 WS 연결 시작(핸드셰이크), 데이터 전송 및 종료 중 발생한 상황을 보여줍니다.잠시 후에 우리는 이 개념들을 깊이 있게 토론할 것이다.
persistent connections
협의는 두 부분으로 나뉜다.핸드셰이크와 데이터 전송.
활용단어참조
우리 먼저 오프닝 악수를 이야기합시다.규범에 따라

The opening handshake is intended to be compatible with HTTP-based server-side software and intermediaries, so that a single port can be used by both HTTP clients talking to that server and WebSocket clients talking to that server.


쉽게 말하면, 웹소켓 연결은 단일 포트의 HTTP (TCP) 를 기반으로 한다.다음은 단계 요약입니다.
  • 서버는 수신되는 TCP 소켓 연결을 수신해야 합니다.이것은 당신이 분배한 모든 포트입니다. 보통 80 또는 443.
  • 클라이언트가 HTTP GET를 통해 악수를 시작하도록 요청한다. (그렇지 않으면 서버는 누구와 통화할지 모른다) 이것은'WebSocket'의'웹'부분이다.헤더에서 클라이언트는 서버에 연결을 웹소켓으로 업그레이드하도록 요구할 것입니다.
  • 서버는 프로토콜을 HTTP에서 WebSocket으로 변경할 것이라고 클라이언트에게 악수 응답을 보냈다.
  • 클라이언트와 서버가 모두 연결 세부 사항을 협상한다.만약 조건이 불리하다면 어느 쪽이든 물러날 수 있다.
  • 다음은 전형적인 오프닝(클라이언트) 악수 요청의 모습이다.
    GET /ws-endpoint HTTP/1.1
    Host: example.com:80
    Upgrade: websocket
    Connection: Upgrade
    Sec-WebSocket-Key: L4kHN+1Bx7zKbxsDbqgzHw==
    Sec-WebSocket-Version: 13
    
    클라이언트가 요청 Connection: UpgradeUpgrade: websocket 헤더를 어떻게 보내는지 주의하십시오.
    서버 핸드셰이크 응답,
    HTTP/1.1 101 Switching Protocols
    Upgrade: websocket
    Connection: Upgrade
    Sec-WebSocket-Accept: CTPN8jCb3BUjBjBtdjwSQCytuBo=
    
    서버가 응답 헤더에 어떻게 보내는지 주의하십시오 HTTP/1.1 101 Switching Protocols.101 이외의 어떤 것도 오프닝 악수가 완성되지 않았다는 것을 보여준다.
    마지막 악수는 매우 간단하다.클라이언트나 서버에서 악수 종료 요청을 보낼 수 있습니다.규범에 따라

    It is safe for both peers to initiate this handshake simultaneously. The closing handshake is intended to complement the TCP closing handshake (FIN/ACK), on the basis that the TCP closing handshake is not always reliable end-to-end, especially in the presence of intercepting proxies and other intermediaries.


    우리가 시범 부분으로 넘어갈 때, 우리는 실제 조작에서 이런 것들을 토론할 것이다.
    데이터 전송
    우리가 알아야 할 다음 관건적인 개념은 데이터 전송이다.어느 쪽이든지 주어진 시간에 메시지를 보낼 수 있다. 왜냐하면 이것은 듀플렉스 통신 프로토콜이기 때문이다.
    메시지는 하나 이상의 프레임으로 구성됩니다.프레임은 텍스트(UTF-8), 바이너리 및 제어 프레임(예: 0x8 (Close), 0x9 (Ping)0xA (Pong) 유형일 수 있습니다.
    관심 있는 경우 의 전체 RFC 사양을 읽을 수 있습니다.

    여기 있다 설치 프로그램


    그것을 행동에 옮겨서 어떻게 일을 하는지 봅시다.

    💡 Follow along with the completed code from my repository here


    먼저 새 5 WebAPI 응용 프로그램을 만듭니다.
    dotnet new webapi -n WebSocketsTutorial
    dotnet new sln
    dotnet sln add WebSocketsTutorial
    
    이제 우리는 신호기를 응용 프로그램에 추가할 것이다.
    dotnet add WebSocketsTutorial/ package Microsoft.AspNet.SignalR
    

    ASP。그물 예제 코드 해석


    우선 WebSockets 중간부품을 WebAPI 프로그램에 추가합니다.Startup.cs 파일로 이동하여 Configure 방법에 다음 줄을 추가합니다.
    나는 이 강좌에서 간단함을 유지하는 것을 좋아한다.그래서 나는 신호기(집선기 등)에 대해 이야기할 생각은 없다.그것은 완전히 웹소켓 통신을 기반으로 할 것이다.원시적인 WebSocket을 통해서도 같은 효과를 얻을 수 있습니다. 일을 간단하게 하려면 Signal을 사용할 필요가 없습니다.
    ...
    
    app.UseWebSockets();
    
    ...
    
    다음은 기본 WeatherForecast Controller를 삭제하고 WebSockets Controller라는 새 컨트롤러를 추가합니다.요청 파이프를 가로막는 것이 아니라 컨트롤러로만 조작할 것이니 주의하십시오
    이 컨트롤러의 전체 코드는 다음과 같다.이 코드는 Microsoft의 공식 문서 를 기반으로 합니다.
    example
    using System;
    using System.Net.WebSockets;
    using System.Text;
    using System.Threading;
    using System.Threading.Tasks;
    using Microsoft.AspNetCore.Mvc;
    using Microsoft.Extensions.Logging;
    
    namespace WebSocketsTutorial.Controllers
    {
        [ApiController]
        [Route("[controller]")]
        public class WebSocketsController : ControllerBase
        {
            private readonly ILogger<WebSocketsController> _logger;
    
            public WebSocketsController(ILogger<WebSocketsController> logger)
            {
                _logger = logger;
            }
    
            [HttpGet("/ws")]
            public async Task Get()
            {
              if (HttpContext.WebSockets.IsWebSocketRequest)
              {
                  using var webSocket = await HttpContext.WebSockets.AcceptWebSocketAsync();
                  _logger.Log(LogLevel.Information, "WebSocket connection established");
                  await Echo(webSocket);
              }
              else
              {
                  HttpContext.Response.StatusCode = 400;
              }
            }
    
            private async Task Echo(WebSocket webSocket)
            {
                var buffer = new byte[1024 * 4];
                var result = await webSocket.ReceiveAsync(new ArraySegment<byte>(buffer), CancellationToken.None);
                _logger.Log(LogLevel.Information, "Message received from Client");
    
                while (!result.CloseStatus.HasValue)
                {
                    var serverMsg = Encoding.UTF8.GetBytes($"Server: Hello. You said: {Encoding.UTF8.GetString(buffer)}");
                    await webSocket.SendAsync(new ArraySegment<byte>(serverMsg, 0, serverMsg.Length), result.MessageType, result.EndOfMessage, CancellationToken.None);
                    _logger.Log(LogLevel.Information, "Message sent to Client");
    
                    result = await webSocket.ReceiveAsync(new ArraySegment<byte>(buffer), CancellationToken.None);
                    _logger.Log(LogLevel.Information, "Message received from Client");
    
                }
                await webSocket.CloseAsync(result.CloseStatus.Value, result.CloseStatusDescription, CancellationToken.None);
                _logger.Log(LogLevel.Information, "WebSocket connection closed");
            }
        }
    }
    
    이것이 바로 우리가 한 일이고,
  • 새로운 경로 ws/ 추가
  • 현재 요청이 WebSockets를 통과했는지 확인하지 않으면 400이 던져집니다.
  • 클라이언트 시작 요청을 기다립니다.WebSocketsController.cs
  • 클라이언트가 연결을 닫을 때까지 순환에 들어갑니다.L:40
  • 순환 중에 우리는 메시지 앞에'Server:Hello. You said:'를 붙여서 클라이언트에게 보낼 것이다.
  • 클라이언트가 다른 요청을 보낼 때까지 기다립니다.
  • 처음 악수를 한 후에 서버는 클라이언트가 클라이언트에게 메시지를 전송할 때까지 기다릴 필요가 없습니다.응용 프로그램을 실행해서 효과가 있는지 봅시다.
    dotnet run --project WebSocketsTutorial
    
    응용 프로그램을 실행한 후 L:43로 이동합니다.너는 거들먹거리는 사용자 인터페이스를 보아야 한다.
    https://localhost:5001/swagger/index.html
    이제 클라이언트와 서버가 서로 통신하는 방법을 살펴봅시다.이 프레젠테이션에서는 Chrome의 DevTools(새 태그 열기)를 사용합니다.→ F12 키를 확인하거나 누릅니다.→ 콘솔 탭)을 참조하십시오.하지만 당신은 어떤 고객을 선택할 수 있습니다.
    우선, 서버 포트에 대한 웹소켓 연결을 만들 것입니다.
    let webSocket = new WebSocket('wss://localhost:5001/ws');
    
    이렇게 하는 목적은 클라이언트와 서버 간의 연결을 시작하는 것이다.wss://는 WebSockets 보안 프로토콜입니다. 왜냐하면 Google의 WebAPI 응용 프로그램은 TLS를 통해 제공되기 때문입니다.
    그리고 호출webSocket.send() 방법으로 메시지를 보낼 수 있습니다.콘솔은 아래 콘솔과 비슷해야 합니다.

    WebSocket 연결 가까이서 보기


    네트워크 탭으로 이동하면 WS 탭을 통해 요청을 필터링한 다음 마지막 이름ws을 클릭합니다.
    Messages 탭을 클릭하여 전달되는 메시지를 확인합니다.이 기간 동안 다음 명령을 호출하면 "클라이언트에서 보낸 것입니다!"를 볼 수 있습니다.이 상자에 나타나.해봐!
    webSocket.send("Client: Hello");
    

    보시다시피 서버는 클라이언트가 응답을 보내기를 기다려야 합니다. (즉, 처음 악수를 한 후) 클라이언트는 막히지 않은 상황에서 메시지를 보낼 수 있습니다.이것은 [전이중](전신)#전이중)u통신이다.우리는 이미 웹소켓 통신의 데이터 전송 방면을 소개했다.연습으로 클라이언트에게 메시지를 전송하여 실행 상황을 볼 수 있는 순환을 실행할 수 있습니다.
    이 밖에 서버와 클라이언트는 클라이언트가 여전히 활성 상태인지 확인하기 위해 https://en.wikipedia.org/wiki/Duplex가 필요하다.이것은 웹소켓의 실제 기능이다!만약 당신이 정말 이 데이터 패키지를 보고 싶다면, Wire Shark 같은 도구를 사용해서 아이디어를 얻을 수 있다.
    그것은 어떻게 악수를 합니까?알겠습니다. Headers 탭으로 넘어가면 본문 1절에서 언급한 요청 - 응답 제목을 볼 수 있습니다.🙌
    ping-pongs
    우리도 webSocket.close()를 시도해 볼 수 있다. 그러면 우리는 개방된 데이터 폐쇄를 완전히 덮어쓸 수 있다.

    결론


    WebSocket의 RFC를 보려는 경우 를 방문하여 읽으십시오.이 글은 웹소켓의 표면에만 닿을 뿐 안전성, 부하 균형, 에이전트 등 많은 다른 문제를 토론할 수 있다.
    나에게 어떤 피드백이나 평론도 알려주는 것을 잊지 마라.다음까지✌️

    RFC 6455 도구책

  • https://tools.ietf.org/html/rfc6455
  • https://docs.microsoft.com/en-us/aspnet/core/fundamentals/websockets?view=aspnetcore-5.0
  • https://www.meziantou.net/using-web-sockets-with-asp-net-core.htm
  • 좋은 웹페이지 즐겨찾기