Perl로 게임 엔진 개발하기: 7부 - 포크
7634 단어 gamedevperllinuxdevjournal
처음부터 읽고 싶다면. 확인
지난 게시물에 이어 . 우리는 엔진 텔넷 서버를 분기할 필요가 있는 것을 중단했습니다.
플레이어 2가 게임에 참여했습니다!
텔넷 서버의 수준을 높이고 knify forky를 사용하여 멀티 플레이어로 만들 시간입니다.
strftime
에서 Perl's POSIX module 식별자를 추가하여 출력 시간 스탬프를 찍는 데 도움을 주었습니다. setsid
식별자는 분기된 각 프로세스에 대한 새 세션 및 그룹 ID를 시작하기 위한 것입니다. A.K.A, 자식 프로세스. :sys_wait_h
은 waitpid()을 호출할 때 WNOHANG 플래그를 사용하여 자식 프로세스가 종료된 후 기다리지 않고 반환하기 위한 것입니다. 이는 보류 중인 모든 좀비 자식에 대해 비차단 대기를 제공합니다.좀비 공격!!!
프로세스가 종료(종료)되면 좀비가 되어 회수해야 합니다. 자식이 중지 또는 종료되었음을 나타내는 waitpid 수신 후 부모 프로세스가 CHLD signal을 호출하면 이 작업이 수행됩니다.
좋습니다. 코드를 분석하는 동안 작업할 수 있는 충분한 정보를 제공하기를 바랍니다.
#!/usr/bin/perl
use strict;
use warnings;
use IO::Socket::INET;
use POSIX qw(setsid);
use POSIX qw(strftime);
use POSIX ":sys_wait_h";
sub timestamp {
my $epoc_seconds = time();
my $time = strftime "%H:%M:%S", localtime($epoc_seconds);
my $date = strftime "%m/%d/%Y", localtime;
my $return = $date . " " . $time;
return ($return);
}
sub logmsg { print timestamp . " -> $0 -> PID:$$: @_ \n" }
logmsg "Begin";
my $socket = new IO::Socket::INET (
LocalHost => '192.168.1.15',
LocalPort => '27777',
Proto => 'tcp',
Listen => SOMAXCONN,
ReuseAddr => 1
);
my $waitedpid = 0;
my $player_data;
my $player_socket;
sub REAPER {
local $!; # don't let waitpid() overwrite current error
logmsg "Ending Player's Game";
while ((my $pid = waitpid(-1, WNOHANG)) > 0 && WIFEXITED($?)) {
logmsg "Closed Game ID:$pid : WaitPid:$waitedpid : " . ($? ? " with exit $?" : "");
}
$SIG{CHLD} = \&REAPER; # loathe SysV
}
#if we get the CHLD signal call REAPER sub
$SIG{CHLD} = \&REAPER;
logmsg "Ready and waiting for connection";
while(1)
{
next unless $player_socket = $socket->accept();
logmsg ("Incomming Connection");
logmsg ("Spawning Player A Game");
my $pid = fork();
next if $pid; #NEXT if $pid exists (parent)
#As Child
setsid();
my $proc = $$;
logmsg ("Game ID:$proc -> Ready");
# get information about a newly connected player
my $player_address = $player_socket->peerhost();
my $player_port = $player_socket->peerport();
logmsg "Game ID:$proc -> Connection from $player_address:$player_port";
my $response = "Welcome Player: $player_address:$player_port. Press any key to disconnect.";
$player_socket->send($response);
while ($player_socket->connected()) {
$player_socket->recv($player_data, 1024);
if ($player_data) {
logmsg "Player Disconnecting $player_address : $player_port";
$socket->close();
logmsg "Player Disconnected";
last;
}
}
last;
}
exit;
이 코드를 실행하고 SyncTERM을 통해 두 명의 플레이어와 연결하면 다음이 표시됩니다.
localhost:~/ANSIGameEngine # perl forking_telnet_server.pl
12/03/2021 18:16:58 -> forking_telnet_server.pl -> PID:15978: Begin
12/03/2021 18:16:58 -> forking_telnet_server.pl -> PID:15978: Ready and waiting for connection
12/03/2021 18:17:04 -> forking_telnet_server.pl -> PID:15978: Incomming Connection
12/03/2021 18:17:04 -> forking_telnet_server.pl -> PID:15978: Spawning Player A Game
12/03/2021 18:17:04 -> forking_telnet_server.pl -> PID:15979: Game ID:15979 -> Ready
12/03/2021 18:17:04 -> forking_telnet_server.pl -> PID:15979: Game ID:15979 -> Connection from 192.168.1.9:33422
12/03/2021 18:17:08 -> forking_telnet_server.pl -> PID:15978: Incomming Connection
12/03/2021 18:17:08 -> forking_telnet_server.pl -> PID:15978: Spawning Player A Game
12/03/2021 18:17:08 -> forking_telnet_server.pl -> PID:15980: Game ID:15980 -> Ready
12/03/2021 18:17:08 -> forking_telnet_server.pl -> PID:15980: Game ID:15980 -> Connection from 192.168.1.9:33428
12/03/2021 18:17:11 -> forking_telnet_server.pl -> PID:15979: Player Disconnecting 192.168.1.9 : 33422
12/03/2021 18:17:11 -> forking_telnet_server.pl -> PID:15979: Player Disconnected
12/03/2021 18:17:11 -> forking_telnet_server.pl -> PID:15978: Ending Player's Game
12/03/2021 18:17:11 -> forking_telnet_server.pl -> PID:15978: Closed Game ID:15979 : WaitPid:0 :
12/03/2021 18:17:13 -> forking_telnet_server.pl -> PID:15980: Player Disconnecting 192.168.1.9 : 33428
12/03/2021 18:17:13 -> forking_telnet_server.pl -> PID:15980: Player Disconnected
12/03/2021 18:17:13 -> forking_telnet_server.pl -> PID:15978: Ending Player's Game
12/03/2021 18:17:13 -> forking_telnet_server.pl -> PID:15978: Closed Game ID:15980 : WaitPid:0 :
작동 원리
새로 들어오는 텔넷 요청을 수락하는 기본(상위) 프로세스는 위의 예에서
PID:15978
입니다. 수신 서버를 설정한 후 연결 요청을 기다리고 새 플레이어(자식)가 연결되면 분기 프로세스를 생성합니다. 이 코드는 값 fork()
이 반환되는 자식(플레이어) 프로세스와 부모(주 대기 텔넷 서버) 프로세스를 구분합니다. 상위 프로세스는 fork()
의 반환 값으로 자식(플레이어) PID를 수신하므로 루프 백업하고 다른 플레이어가 연결될 때까지 기다립니다. 하위(플레이어) 프로세스는 0
에서 fork()
의 값을 수신하므로 코드에서 계속 아래쪽으로 이동합니다. Perl에서 if($pid)
는 TRUE
if $pid == (0 || undef)
를 평가하지 않습니다. 이는 자식(플레이어) 프로세스가 fork()
에서 반환된 값으로 받을 것입니다. 자식(플레이어) 프로세스에 새 세션을 제공하고 PID( $$
)를 기록하고 아무 키나 누를 때까지 기다립니다. 플레이어가 키를 누르면 소켓이 닫히고 자식(플레이어) 프로세스가 존재하며 좀비가 됩니다. 이는 상위(주) 프로세스가 CHLD 신호( $SIG{CHLD}
)를 수신하고 REAPER
를 호출할 때입니다.당신은 어떤가요?
이전에 포크로 작업한 적이 있습니까? 거두는 것을 잊고 좀비 아포칼립스를 일으켰습니까? 귀하의 경험에 대해 의견을 말하십시오. 귀하의 이야기를 듣고 싶습니다.
제안이나 의견이 있으면 건설적으로 공유하십시오. 또한 소셜 미디어 페이지를 방문하여 게임 엔진이 작동하는 모습을 보여주는 재미있는 동영상과 사진을 많이 확인하세요.
ANSI Game Engine on Facebook
건배!
숀
Reference
이 문제에 관하여(Perl로 게임 엔진 개발하기: 7부 - 포크), 우리는 이곳에서 더 많은 자료를 발견하고 링크를 클릭하여 보았다 https://dev.to/ansigameengine/developing-a-game-engine-with-perl-part-7-fork-3acm텍스트를 자유롭게 공유하거나 복사할 수 있습니다.하지만 이 문서의 URL은 참조 URL로 남겨 두십시오.
우수한 개발자 콘텐츠 발견에 전념 (Collection and Share based on the CC Protocol.)