2023년 3월 11일 토요일

Protobuf-net 서버-클라이언트 데이터 송수신 예제

성능 신경쓰지 않고 단순히 데이터 주고 받는데 집중하면 동기 방식의 TCP/IP에 protobuf-net 조합이 가장 간편한 것 같다. 예제는 ChatGPT에서 찾은 것으로 단순하게 메시지 하나를 전달한다. 이 정도 예제만 바로 찾을 수 있어도 접근하기가 얼마나 쉬워지는지. 아쉬운 부분은 회사에서는 ChatGPT가 막혀있다.


아래는 서버 코드. 클라이언트 네트워크 스트림을 대상으로 Serialize를 호출하면 데이터가 클라이언트 쪽으로 전송된다. Protobuf-net을 사용하는 경우 *.proto 파일을 별도로 작성하고, 관리하지 않아도 되기 때문에 사용하기 간편하다.


using System;
using System.Net;
using System.Net.Sockets;
using ProtoBuf;

public class Program
{
    private const int Port = 12345;
    private const int BufferSize = 1024;

    [ProtoContract]
    public class Message
    {
        [ProtoMember(1)]
        public int Id { get; set; }
        [ProtoMember(2)]
        public string Text { get; set; }
    }

    static void Main(string[] args)
    {
        var listener = new TcpListener(IPAddress.Any, Port);
        listener.Start();
        Console.WriteLine($"Listening on port {Port}");

        while (true)
        {
            using (var client = listener.AcceptTcpClient())
            {
                var stream = client.GetStream();
                var buffer = new byte[BufferSize];
                var bytesRead = stream.Read(buffer, 0, BufferSize);
                var message = Serializer.Deserialize<Message>(new ArraySegment<byte>(buffer, 0, bytesRead));

                Console.WriteLine($"Received message from client: {message.Text}");

                var response = new Message { Id = 1, Text = "Hello from server!" };
                Serializer.Serialize(stream, response);
                Console.WriteLine($"Sent response to client: {response.Text}");
            }
        }
    }
}

다음은 클라이언트. ProtoContract 클래스는 서로 일치해야 한다.

using System;
using System.Net.Sockets;
using ProtoBuf;

public class Program
{
    private const string Host = "localhost";
    private const int Port = 12345;
    private const int BufferSize = 1024;

    [ProtoContract]
    public class Message
    {
        [ProtoMember(1)]
        public int Id { get; set; }
        [ProtoMember(2)]
        public string Text { get; set; }
    }

    static void Main(string[] args)
    {
        using (var client = new TcpClient(Host, Port))
        {
            var stream = client.GetStream();

            var message = new Message { Id = 1, Text = "Hello from client!" };
            Serializer.Serialize(stream, message);
            Console.WriteLine($"Sent message to server: {message.Text}");

            var buffer = new byte[BufferSize];
            var bytesRead = stream.Read(buffer, 0, BufferSize);
            var response = Serializer.Deserialize<Message>(new ArraySegment<byte>(buffer, 0, bytesRead));

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