[Network] System.Net.Sockets.Socket๊ณผ Linux epoll

๋ฐฐ๊ฒฝ

์ˆ˜์ฒœ๊ฐœ์˜ ์†Œ์ผ“์„ ์—ด๊ณ  Accept๋ฅผ Multiplexing ์œผ๋กœ ์ฒ˜๋ฆฌํ•ด์•ผ ํ•ฉ๋‹ˆ๋‹ค.

select๋ฅผ ์‚ฌ์šฉํ•˜์—ฌ ๋ฒ”์šฉ์ ์ธ ์ฝ”๋“œ๋ฅผ ์ž‘์„ฑํ•  ์ˆ˜ ์žˆ์ง€๋งŒ
์ด๋ฒคํŠธ๋ฅผ ์ฒ˜๋ฆฌํ•˜๊ธฐ ์œ„ํ•ด ์†Œ์ผ“์˜ ๊ฐœ์ˆ˜๋งŒํผ ์„ ํ˜•์œผ๋กœ ์ฐพ๊ณ  ๋งค ํ˜ธ์ถœ๋งˆ๋‹ค
์†Œ์ผ“ ๋ฆฌ์ŠคํŠธ๋ฅผ ๋ณต์‚ฌํ•ด์•ผํ•˜๋Š” ๋ฌธ์ œ๊ฐ€ ์žˆ์Šต๋‹ˆ๋‹ค.

์ด๋ฅผ ํ•ด๊ฒฐํ•˜๊ธฐ ์œ„ํ•ด IO Completion Port ๋ฅผ ์‚ฌ์šฉํ•  ์ˆ˜ ์žˆ์ง€๋งŒ
IOCP๋Š” Windows ์˜ ๊ธฐ์ˆ ์ด๊ธฐ ๋•Œ๋ฌธ์— Linux์—์„  ๋Œ€์•ˆ์„ ์ฐพ์•„์•ผํ•ฉ๋‹ˆ๋‹ค.

epoll?

epoll์€ ํ™•์žฅ ๊ฐ€๋Šฅํ•œ I/O ์ด๋ฒคํŠธ ์•Œ๋ฆผ ๋ฉ”์ปค๋‹ˆ์ฆ˜์„์œ„ํ•œ Linux ์ปค๋„ ์‹œ์Šคํ…œ ํ˜ธ์ถœ์ž…๋‹ˆ๋‹ค.

ํ™˜๊ฒฝ

  • .NET 6, C# 10
  • Ubuntu 20.04

๊ตฌํ˜„

epoll_create
epoll_ctl
epoll_wait

์œ„ ์„ธ๊ฐœ ํ•จ์ˆ˜๋ฅผ ์‚ฌ์šฉํ•˜๊ธฐ ์œ„ํ•ด P/Invoke ์ฝ”๋“œ๋ฅผ ์ž‘์„ฑํ•ฉ๋‹ˆ๋‹ค.
(Tdms.Linux ๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ๋ฅผ ์‚ฌ์šฉํ•ด๋„ ๋ฉ๋‹ˆ๋‹ค.)

Libc.cs

public static class Libc
{
    public const int EPOLL_CTL_ADD = 0x1;
    public const int EPOLL_CTL_DEL = 0x2;
    public const int EPOLL_CTL_MOD = 0x3;

    [StructLayout(LayoutKind.Explicit)]
    public struct epoll_data
    {
        [FieldOffset(0)]
        public IntPtr ptr;

        [FieldOffset(0)]
        public int fd;

        [FieldOffset(0)]
        public uint u32;

        [FieldOffset(0)]
        public ulong u64;
    };

    [StructLayout(LayoutKind.Explicit)]
    public struct epoll_event
    {
        [FieldOffset(0)]
        public EPOLL_EVENTS events;

        [FieldOffset(4)]
        public epoll_data data;
    };

    [Flags]
    public enum EPOLL_EVENTS : uint
    {
        EPOLLIN = 0x001,
        EPOLLPRI = 0x002,
        EPOLLOUT = 0x004,
        EPOLLRDNORM = 0x040,
        EPOLLRDBAND = 0x080,
        EPOLLWRNORM = 0x100,
        EPOLLWRBAND = 0x200,
        EPOLLMSG = 0x400,
        EPOLLERR = 0x008,
        EPOLLHUP = 0x010,
        EPOLLRDHUP = 0x2000,
        EPOLLEXCLUSIVE = 1u << 28,
        EPOLLWAKEUP = 1u << 29,
        EPOLLONESHOT = 1u << 30,
        EPOLLET = 1u << 31
    }

    [DllImport("libc.so.6")]
    public static extern int epoll_create(int size);

    [DllImport("libc.so.6")]
    public static extern unsafe int epoll_ctl(int epfd, int op, int fd, epoll_data* epevent);

    [DllImport("libc.so.6")]
    public static extern unsafe int epoll_wait(int epfd, epoll_data* events, int maxevents, int timeout);
}

Program.cs

const int portStart = 10000;
const int portEnd = 12000;

// epoll ์ƒ์„ฑ

var epollDescriptor = Libc.epoll_create(1);

if (epollDescriptor < 0)
    throw new IOException($"Call to epoll_create API failed({epollDescriptor})");

var sockets = new Dictionary<int, Socket>();

for (int i = portStart; i <= portEnd; i++)
{
    var socket = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
    socket.Bind(new IPEndPoint(IPAddress.Any, i));
    socket.Listen();
    sockets[socket.Handle.ToInt32()] = socket;

    // epoll ์ด๋ฒคํŠธ ๋“ฑ๋ก

    unsafe
    {
        var epEvent = new Libc.epoll_event
        {
            events = Libc.EPOLL_EVENTS.EPOLLIN,
            data = new Libc.epoll_data
            {
                fd = socket.Handle.ToInt32()
            }
        };

        var result = Libc.epoll_ctl(epollDescriptor, Libc.EPOLL_CTL_ADD, epEvent.data.fd, &epEvent);

        if (result != 0)
            throw new IOException($"Call to epoll_ctl(EPOLL_CTL_ADD) API failed({result})");
    }
}

// epoll ์ด๋ฒคํŠธ ์ˆ˜์‹  ํ›„ Socket.Accept
unsafe
{
    var epEvent = new Libc.epoll_event();

    while (true)
    {
        var result = Libc.epoll_wait(epollDescriptor, &epEvent, 1, -1);

        if (result > 0)
        {
            var socket = sockets[epEvent.data.fd];
            var client = socket.Accept();
            Console.WriteLine($"[{socket.LocalEndPoint}] Accept from {client.RemoteEndPoint}");
        }
    }
}
7๊ฐœ์˜ ์ข‹์•„์š”

IOCP game server์— windows server๋ฅผ ๋งŽ์ด ์‚ฌ์šฉํ•˜๋Š” ์ด์œ ์ค‘ ํ•˜๋‚˜์ฃ !

3๊ฐœ์˜ ์ข‹์•„์š”

์ด๋ฏธ ๋‹ท๋„ท์ฝ”์–ด์—์„œ๋Š” ๋‚ด๋ถ€์ ์œผ๋กœ ๋ฆฌ๋ˆ…์Šค์—์„œ๋Š” epoll์„ ์‚ฌ์šฉํ•˜๊ณ  ์žˆ์Šต๋‹ˆ๋‹ค. ๋‹ท๋„ท์ฝ”์–ด์—์„œ ์‚ฌ์šฉํ•˜๋Š” epoll ๋ณด๋‹ค ๋” ์ตœ์ ํ™”(์ฆ‰ ์ž์‹ ๋งŒ์„ ์œ„ํ•œ)๋ฅผ ํ•˜๊ณ  ์‹ถ์€ ๊ฒฝ์šฐ์—๋งŒ ์ง์ ‘ epoll API๋ฅผ ๋‹ค๋ฃจ๋Š” ๊ฒƒ์ด ์ข‹์Šต๋‹ˆ๋‹ค.

2๊ฐœ์˜ ์ข‹์•„์š”

๋‚ด๋ถ€์ ์œผ๋กœ epoll์„ ๋‹ค๋ฃจ๊ณ  ์žˆ์ง€๋งŒ ๋Œ€๋Ÿ‰์˜ ์†Œ์ผ“์„ ํ•˜๋‚˜์˜ epoll๋กœ ์ปจํŠธ๋กคํ•  ๋ฐฉ๋ฒ•์€ ์—†๋Š”๊ฒƒ์œผ๋กœ ์•Œ๊ณ ์žˆ์Šต๋‹ˆ๋‹ค.

2๊ฐœ์˜ ์ข‹์•„์š”