#!/usr/bin/perl use warnings; use strict; use IO::Socket::INET; use IO::Epoll; use Time::HiRes qw(time sleep); use POSIX; use constant DEFAULT_PORT => 7500; use constant DEFAULT_NUM_CLIENTS => 100000; use constant BUFSIZE => 4096; use constant LISTEN_QUEUE => 1024; use constant EPOLL_TIMEOUT => 60_000; our $epoll; ($epoll = epoll_create(DEFAULT_NUM_CLIENTS)) > 0 or die "Couldn't create epoller: $!\n"; our $listen = IO::Socket::INET->new(Listen => LISTEN_QUEUE, LocalPort => DEFAULT_PORT, ReuseAddr => 1, ) or die "Couldn't get listen port: $!\n"; our $listenfd = fileno($listen); epoll_ctl($epoll, EPOLL_CTL_ADD, $listenfd, EPOLLIN) == 0 or die "Couldn't add FD to epoll: $!\n"; our @echosocks; our @outbuf; while(1) { my $events = epoll_wait($epoll, DEFAULT_NUM_CLIENTS, EPOLL_TIMEOUT) or die "Couldn't epoll_wait: $!\n"; foreach my $ev (@$events) { if ($ev->[0] == $listenfd) { my $accepted = $listen->accept() or die "Couldn't accept connection: $!\n"; epoll_ctl($epoll, EPOLL_CTL_ADD, fileno($accepted), EPOLLIN) == 0 or die "Couldn't add FD to epoll: $!\n"; push(@echosocks,$accepted); print "Accepted connection on fd ",fileno($accepted),"\n"; } else { if ($ev->[1] & EPOLLIN) { my $buf; my $readbytes = POSIX::read($ev->[0],$buf,BUFSIZE); if (!$readbytes || $readbytes == 0) { if (!defined($readbytes) && $! ne 'Connection reset by peer') { warn "Error reading socket $ev->[0]: $!\n"; } POSIX::close($ev->[0]); $outbuf[$ev->[0]] = undef; warn "Socket $ev->[0] gone.\n"; } else { if (!$outbuf[$ev->[0]]) { epoll_ctl($epoll, EPOLL_CTL_MOD, $ev->[0], EPOLLIN | EPOLLOUT) == 0 or die "Couldn't add FD to epoll for write: $!\n"; } $outbuf[$ev->[0]] .= $buf; } } if (($ev->[1] & EPOLLOUT) && $outbuf[$ev->[0]]) { my $wrote = POSIX::write($ev->[0],$outbuf[$ev->[0]],length($outbuf[$ev->[0]])) or die "Couldn't write: $!\n"; $outbuf[$ev->[0]] = substr($outbuf[$ev->[0]],$wrote); if (!$outbuf[$ev->[0]]) { epoll_ctl($epoll, EPOLL_CTL_MOD, $ev->[0], EPOLLIN) == 0 or die "Couldn't remove FD from epoll for write: $!"; } } } } }