CSharp

.NET Core Console 에서 WebSocket Server 만들기

yogingang 2023. 3. 7. 16:44
반응형

일반적으로 .NET Core Console 에서 websocket server 를 만들지 않는다.

그대신 aspnet core 의 websocket 기능을 활용하게 된다. 

그런데 우리가 항상 aspnet core 상에서 프로그래밍을 하지는 않는다.

Console 에서 사용하는 방법이 필요하다. 

물론 GenericHost 에서 aspnet core 의 몇몇 기능을 올려서 사용 할 수 있지만

이또한 결국 runtime 시에 aspnet core runtime 이 필요하게 된다. 

 

어쨌든 Console 에서 aspnet core runtime 없이 websocket server 를 구현해 보자

dotnet core 2.1 이상 부터는 HttpListener 와 System.Net.WebSocket 을 이용해서 구현이 가능하다.

참고할점은 System.Net.WebSocket 같은 경우는 event 기반에 message 처리를 하지 않으므로

이부분을 참고 하는게 좋을것이다.

 

WebSocket Server 쪽 Program.cs

// See https://aka.ms/new-console-template for more information
using System.Net;
using System.Net.WebSockets;
using System.Text;

var listener = new HttpListener();
listener.Prefixes.Add("http://localhost:8080/");
listener.Start();

Console.WriteLine("Listening...");

while (true)
{
    var context = await listener.GetContextAsync();

    if (context.Request.IsWebSocketRequest)
    {
        Console.WriteLine("WebSocket request received");

        var webSocketContext = await context.AcceptWebSocketAsync(subProtocol: null);
        var webSocket = webSocketContext.WebSocket;

        await Echo(webSocket);

        Console.WriteLine("WebSocket closed");
        Console.ReadLine();
    }
    else
    {
        context.Response.StatusCode = (int)HttpStatusCode.BadRequest;
        context.Response.Close();
    }
}

async Task Echo(WebSocket webSocket)
{
    var buffer = new byte[1024];

    while (webSocket.State == WebSocketState.Open)
    {
        var receiveResult = await webSocket.ReceiveAsync(new ArraySegment<byte>(buffer), CancellationToken.None);

        if (receiveResult.MessageType == WebSocketMessageType.Close)
        {
            await webSocket.CloseAsync(WebSocketCloseStatus.NormalClosure, "", CancellationToken.None);
        }
        else
        {
            var messageBytes = new ArraySegment<byte>(Encoding.UTF8.GetBytes("Echo: ")).
                Concat(new ArraySegment<byte>(buffer, 0, receiveResult.Count)).ToArray();

            var sendBuffer = new ArraySegment<byte>(messageBytes);

            Console.WriteLine(Encoding.UTF8.GetString(buffer));

            await webSocket.SendAsync(sendBuffer, WebSocketMessageType.Text, true, CancellationToken.None);
        }
    }
}

 

위에 내용을 보면 정말 간단하게 만들어진 WebSocket Server 이다. 

 

1. HttpListener 객체를 생성하여 로컬 호스트의 8080 포트에서 HTTP 요청을 수신.

2. WebSocket 요청인 경우, context.AcceptWebSocketAsync 메서드를 호출하여 WebSocket 연결을 수락.

3. Echo 메서드를 호출하여 WebSocket 객체를 전달하고, 받은 데이터를 "Echo: "라는 접두사와 함께 다시 보냄.

4. WebSocket 요청이 아닌 경우, StatusCode 속성을 400(Bad Request)으로 설정하고 응답을 닫음.

 

이제 Server 와 통신하는 client 를 작성해 보자

WebSocket Client 쪽 Program.cs

// See https://aka.ms/new-console-template for more information
using System.Net.WebSockets;
using System.Text;

var webSocket = new ClientWebSocket();
await webSocket.ConnectAsync(new Uri("ws://localhost:8080"), CancellationToken.None);

Console.WriteLine("WebSocket connected");

var buffer = new byte[1024];
var message = "Hello, World!";
var sendBuffer = new ArraySegment<byte>(Encoding.UTF8.GetBytes(message));

await webSocket.SendAsync(sendBuffer, WebSocketMessageType.Text, true, CancellationToken.None);

var receiveResult = await webSocket.ReceiveAsync(new ArraySegment<byte>(buffer), CancellationToken.None);
var response = Encoding.UTF8.GetString(buffer, 0, receiveResult.Count);

Console.WriteLine($"Received: {response}");

await webSocket.CloseAsync(WebSocketCloseStatus.NormalClosure, "", CancellationToken.None);

Console.WriteLine("WebSocket closed");
Console.ReadLine();

1. ClientWebSocket 객체를 생성하여 ws://localhost:8080 주소로 WebSocket 연결을 요청한다.
2. webSocket.ConnectAsync 메서드를 호출하여 연결을 수립하고, "WebSocket connected"라고 콘솔에 출력한다.
3. "Hello, World!"라는 메시지를 바이트 배열로 변환하고, SendAsync 메서드를 호출하여 서버에 전송한다.
4. ReceiveAsync 메서드를 호출하여 서버로부터 응답을 받고, 바이트 배열을 문자열로 변환하여 콘솔에 출력한다.
5. CloseAsync 메서드를 호출하여 연결을 종료하고, "WebSocket closed"라고 콘솔에 출력한다.

 

관련영상

https://youtu.be/AWj1Uszfe5M

반응형