Perl로 windows에서 Client/Server 작성시 fork/thread 사용 질문드려요.

전민수의 이미지

안녕하세요.

현재 camelbox(http://code.google.com/p/camelbox/)를 Windows XP에 설치하였고요,
IO::Socket과 socket 두 버전으로 코딩을 했는데요.
둘 다 fork를 하기 전에는 cmd.exe 창을 통해서 잘 실행이 되는데
fork를 적용한 경우 cmd.exe 창에서는 데이터가 전송되지 않고 멈춘것처럼 보입니다.
Cygwin에서 같은 코드를 실행시킬 경우에는 잘 됩니다....

처음에는 flushing 문제라 생각하고 처리해 주었는데요, (http://coding.derkeiler.com/Archive/Perl/comp.lang.perl.misc/2005-05/msg01045.html)
fork 만 사용하면 데이터 전송이 멈춘것처럼 동작해서요...
Cygwin에서 동작하는 걸로 봐서 Windows에서만 발생하는 문제인것 같은데,

(http://win32.perl.org/wiki/index.php?title=Compatibility_List_of_Perl_Modules#IO::Socket)
위 사이트에 보면 IO::Socket 의 경우 버그가 있다고는 하는데요.
그렇다면 listen,bind,accept,socket등의 함수를 사용한 버전은 동작해야 한다고 생각했는데 여전히 같은 현상이 발생하네요...

Windows에서 socket과 fork를 동시에 사용한 프로그래밍이 불가능한건가요?
조언 부탁드립니다.

아래는 테스트한 Server/Client 프로그램 코드입니다.

#!/bin/perl -w
require 5.002;
use strict;
use Socket;
use POSIX qw(:sys_wait_h);
use Carp;
use Sys::Hostname;
 
sub REAPER {
    1 until (-1 == waitpid(-1, WNOHANG));
    $SIG{CHLD} = \&REAPER;
}
sub logmsg { print "$0 $$: @_ at ", scalar localtime, "\n" }
 
my $port  = shift || 2345;
my $proto = getprotobyname('tcp');
my $kid;
 
socket(Server, PF_INET, SOCK_STREAM, $proto) or die "socket: $!";
setsockopt(Server, SOL_SOCKET, SO_REUSEADDR, pack("l", 1)) or die "setsockopt: $!";
bind(Server, sockaddr_in($port, INADDR_ANY)) or die "bind: $!";
listen(Server, SOMAXCONN)                    or die "listen: $!";
 
logmsg "server started on port $port";
 
my $paddr;
$SIG{CHLD} = \&REAPER;
$| = 1;
 
while ( $paddr = accept(Client, Server)) {
	my ($port, $iaddr) = sockaddr_in($paddr);
	my $name = gethostbyaddr($iaddr, AF_INET);
	logmsg "connection from $name [", inet_ntoa($iaddr), "] at port $port";
 
	my $old_fh = select(Client);
	$| = 1;
	select($old_fh);
 
	# execute a fork, if this is the parent,
	# its work is done, go straight to continue
	next if $kid = fork;
	die "fork: $!" unless defined $kid;
 
	# child now...
	# close the server - not needed
	close Server;
 
	print Client "Hello there, $name, it\'s now ", scalar localtime, "\n";
 
	my $buf;
	while (defined($buf = <Client>)) {	
		foreach ($buf) {
			if (/^HELLO$/) {
				print Client "Hi\n";
				last;
			}
			elsif (/^NAME$/) {
				print Client hostname(), "\n";				
				last;
			}
			elsif (/^DATE$/) {
				print Client scalar(localtime), "\n";
				last;
			}
			# default case:
			print Client "DEFAULT\n";
		}
	}
	close Client;	
}

#!/bin/perl -w
require 5.002;
use strict;
use Socket;
 
my ($remote, $port, $iaddr, $paddr, $proto, $line);
my ($in, $buf, $kid);
 
$remote = shift || 'localhost';
$port   = shift || 2345;		# random port
 
if ($port =~ /\D/) { $port = getservbyname($port, 'tcp') }
die "No port" unless $port;
 
$iaddr = inet_aton($remote) or die "no host; $remote";
$paddr = sockaddr_in($port, $iaddr);
$proto = getprotobyname('tcp');
 
socket(SOCK, PF_INET, SOCK_STREAM, $proto) or die "socket: $!";
connect(SOCK, $paddr)                      or die "connect: $!";
 
my $old_fh = select(SOCK);
$| = 1;
select($old_fh);
 
die "fork fail: $!" unless defined($kid = fork);
 
if ($kid) {
    # parent reads from STDIN, prints to socket
    while (defined($in = <STDIN>)) {
		print SOCK $in;
    }
    # kill the child process
    kill(TERM => $kid);
} else {
    # child reads from socket, prints to STDOUT
    while (defined($buf = <SOCK>)) {
		print $buf;
    }
    close SOCK;
}
 
exit;
aero의 이미지

일단 윈도우용 Perl의 대세는 딸기펄 ( http://strawberryperl.com/ ) 입니다.

시스템 콜관련 부분은 UNIX(linux), Win32 간에 포팅이 되었다고 해도 미묘하게 동작이 다른 부분이 있어
저수준(?)으로 구현하면 여러가지로 예외상황이나 신경써야 될 부분이 많을 수 있습니다.
이때는 그러한 층을 Wrapping해서 좀 더 고수준에서 편하게 쓸 수 있게 해주는 모듈들을 사용해 보세요.

POE - http://poe.perl.org/
AnyEvent - http://search.cpan.org/dist/AnyEvent/
요즘 뜨는
Coro - http://search.cpan.org/dist/Coro/

기타 참고할만한 글들
http://d.hatena.ne.jp/tokuhirom/20090630/1246324092
http://j2k.naver.com/j2k_frame.php/korean/d.hatena.ne.jp/tokuhirom/20090629/1246239835

전민수의 이미지

말씀해주신 자료 참고해서 한번 해보겠습니다. :-)

댓글 달기

Filtered HTML

  • 텍스트에 BBCode 태그를 사용할 수 있습니다. URL은 자동으로 링크 됩니다.
  • 사용할 수 있는 HTML 태그: <p><div><span><br><a><em><strong><del><ins><b><i><u><s><pre><code><cite><blockquote><ul><ol><li><dl><dt><dd><table><tr><td><th><thead><tbody><h1><h2><h3><h4><h5><h6><img><embed><object><param><hr>
  • 다음 태그를 이용하여 소스 코드 구문 강조를 할 수 있습니다: <code>, <blockcode>, <apache>, <applescript>, <autoconf>, <awk>, <bash>, <c>, <cpp>, <css>, <diff>, <drupal5>, <drupal6>, <gdb>, <html>, <html5>, <java>, <javascript>, <ldif>, <lua>, <make>, <mysql>, <perl>, <perl6>, <php>, <pgsql>, <proftpd>, <python>, <reg>, <spec>, <ruby>. 지원하는 태그 형식: <foo>, [foo].
  • web 주소와/이메일 주소를 클릭할 수 있는 링크로 자동으로 바꿉니다.

BBCode

  • 텍스트에 BBCode 태그를 사용할 수 있습니다. URL은 자동으로 링크 됩니다.
  • 다음 태그를 이용하여 소스 코드 구문 강조를 할 수 있습니다: <code>, <blockcode>, <apache>, <applescript>, <autoconf>, <awk>, <bash>, <c>, <cpp>, <css>, <diff>, <drupal5>, <drupal6>, <gdb>, <html>, <html5>, <java>, <javascript>, <ldif>, <lua>, <make>, <mysql>, <perl>, <perl6>, <php>, <pgsql>, <proftpd>, <python>, <reg>, <spec>, <ruby>. 지원하는 태그 형식: <foo>, [foo].
  • 사용할 수 있는 HTML 태그: <p><div><span><br><a><em><strong><del><ins><b><i><u><s><pre><code><cite><blockquote><ul><ol><li><dl><dt><dd><table><tr><td><th><thead><tbody><h1><h2><h3><h4><h5><h6><img><embed><object><param>
  • web 주소와/이메일 주소를 클릭할 수 있는 링크로 자동으로 바꿉니다.

Textile

  • 다음 태그를 이용하여 소스 코드 구문 강조를 할 수 있습니다: <code>, <blockcode>, <apache>, <applescript>, <autoconf>, <awk>, <bash>, <c>, <cpp>, <css>, <diff>, <drupal5>, <drupal6>, <gdb>, <html>, <html5>, <java>, <javascript>, <ldif>, <lua>, <make>, <mysql>, <perl>, <perl6>, <php>, <pgsql>, <proftpd>, <python>, <reg>, <spec>, <ruby>. 지원하는 태그 형식: <foo>, [foo].
  • You can use Textile markup to format text.
  • 사용할 수 있는 HTML 태그: <p><div><span><br><a><em><strong><del><ins><b><i><u><s><pre><code><cite><blockquote><ul><ol><li><dl><dt><dd><table><tr><td><th><thead><tbody><h1><h2><h3><h4><h5><h6><img><embed><object><param><hr>

Markdown

  • 다음 태그를 이용하여 소스 코드 구문 강조를 할 수 있습니다: <code>, <blockcode>, <apache>, <applescript>, <autoconf>, <awk>, <bash>, <c>, <cpp>, <css>, <diff>, <drupal5>, <drupal6>, <gdb>, <html>, <html5>, <java>, <javascript>, <ldif>, <lua>, <make>, <mysql>, <perl>, <perl6>, <php>, <pgsql>, <proftpd>, <python>, <reg>, <spec>, <ruby>. 지원하는 태그 형식: <foo>, [foo].
  • Quick Tips:
    • Two or more spaces at a line's end = Line break
    • Double returns = Paragraph
    • *Single asterisks* or _single underscores_ = Emphasis
    • **Double** or __double__ = Strong
    • This is [a link](http://the.link.example.com "The optional title text")
    For complete details on the Markdown syntax, see the Markdown documentation and Markdown Extra documentation for tables, footnotes, and more.
  • web 주소와/이메일 주소를 클릭할 수 있는 링크로 자동으로 바꿉니다.
  • 사용할 수 있는 HTML 태그: <p><div><span><br><a><em><strong><del><ins><b><i><u><s><pre><code><cite><blockquote><ul><ol><li><dl><dt><dd><table><tr><td><th><thead><tbody><h1><h2><h3><h4><h5><h6><img><embed><object><param><hr>

Plain text

  • HTML 태그를 사용할 수 없습니다.
  • web 주소와/이메일 주소를 클릭할 수 있는 링크로 자동으로 바꿉니다.
  • 줄과 단락은 자동으로 분리됩니다.
댓글 첨부 파일
이 댓글에 이미지나 파일을 업로드 합니다.
파일 크기는 8 MB보다 작아야 합니다.
허용할 파일 형식: txt pdf doc xls gif jpg jpeg mp3 png rar zip.
CAPTCHA
이것은 자동으로 스팸을 올리는 것을 막기 위해서 제공됩니다.