【发布时间】:2018-07-24 03:40:12
【问题描述】:
服务器.pl
sub sock_initialize {
my $sock = q{};
my $port = q{};
# Get a port for our server.
$sock = IO::Socket::INET->new(
Listen => SOMAXCONN, # listen queue depth
LocalPort => 0,
Reuse => 1
);
die "Unable to bind a port: $!" if !$sock;
$port = $sock->sockport();
my $ip = "";
my $uid = (getpwuid( $> ))[2];
my $queue = join(":", $ip, $port, $$, $uid);
print sprintf("put started on port $port ($$), SOMAXCONN=%d\n", SOMAXCONN);
return $sock;
} ## end sub sock_initialize
my $listen_sock = sock_initialize();
while (1) {
#my $xsock = Accept();
my $xsock;
while (1) {
$! = 0;
# Accept can block. Need to use nonblocking poll (Stevens)
$xsock = $listen_sock->accept; # ACCEPT
last if defined $xsock;
next if $! == EINTR;
die "accept error: $!";
if ( defined $xsock ) {
$xsock->blocking(0); # mark executor socket nonblocking
$xsock->sockopt( SO_KEEPALIVE() => 1 ) or die "sockopt: $!";
}
#my $rbufp = $conn->readbufref;
#my $rdstatus = Read( $sock, $rbufp );
my $buff = "";
while (1) {
$! = 0;
# Accept can block. Need to use nonblocking poll (Stevens)
$xsock = $listen_sock->accept; # ACCEPT
last if defined $xsock;
next if $! == EINTR;
die "accept error: $!";
if ( defined $xsock ) {
$xsock->blocking(0); # mark executor socket nonblocking
$xsock->sockopt( SO_KEEPALIVE() => 1 ) or die "sockopt: $!";
}
}
#my $rbufp = $conn->readbufref;
#my $rdstatus = Read( $sock, $rbufp );
my $buff = "";
while (1) {
my $nbytes = sysread $xsock, $buff, 32768, length($buff); # SYSCALL
if ( !defined $nbytes ) { # read error
next if $! == EINTR;
last if $! == EWOULDBLOCK; # normal
return;
}
last if $nbytes == 0; # EOF
}
print "received $buff\n";
last;
}
client.pl
my $host = "localhost";
my $port = 37402; # get port number from server.pl
my $s = IO::Socket::INET->new (PeerAddr => $host,
PeerPort => $port,
Type => SOCK_STREAM,
Proto => 'tcp',
Timeout => 1);
if ($s) {
$s->blocking (0) ;
}
my $nbytes = syswrite $s, "hi from X"; # SYSCALL
首先,我将启动 server.pl
$perl test_socket_server.pl
$put started on port 37402 (16974), SOMAXCONN=128
然后我会把端口号放在client.pl上
perl test_socket_client.pl
然后,在 server.pl shell 上,我看到了
received hi from X
所以,它按预期工作。 现在,当我通过
将 server.pl 放入容器中时docker run ubuntu perl server.pl
put started on port 38170 (1), SOMAXCONN=128
然后,我会在 client.pl 中写入端口号并运行它,但是 server.pl 没有收到消息
我的理解是容器端口不会通过 EXPOSE 暴露给主机
现在,即使问题可以通过 EXPOSE 解决,server.pl 也会连接到未分配的端口,即每次运行时色情号码都会发生变化LocalPort => 0, server.pl 在容器内运行。我的理解是您必须在容器运行时公开端口,但此时您不知道 server.pl 将在哪个端口运行。我希望它是这种方式,没有指定端口,因为 server.pl 的多个实例可以在一个容器中运行(因此需要能够使用不同的端口)。有什么策略可以解决这个问题吗?
你可以在启动容器时公开端口范围,也许是 30000 及以上? [我已经阅读了一些关于暴露端口范围的其他堆栈溢出问题,但它似乎存在一些性能问题,因为每个端口都分叉了一个真正的进程(?)Docker expose all ports or range of ports from 7000 to 8000 理想的解决方案是以某种方式只暴露应用程序正在使用的端口它在运行时驻留在容器中。也许这是由协调器完成的?
【问题讨论】:
-
您能否链接处理使用端口 ragens 时的性能问题的帖子?为什么你要提供服务器和客户端的源代码?很难直截了当,而且我认为无论如何您都不愿意更改代码以使用固定端口,因此即使
nc -l -p $((RANDOM%9999))也可以证明您要实现的目标,但我会省略这些细节. -
重提你的问题:你没有提到使用网络选项
host的参数,比如:--net=host所以你不需要首先绑定/公开端口,而是端口获取需要时直接绑定 -
@Murmel 这是一个被容器化的遗留代码,并且希望在不更改应用程序的情况下在容器中按原样工作。代码是版本化的,如果我们进行基础设施更改(容器化),我们必须将修复/功能应用于所有先前版本,即 --net=host
-
好吧,我不太确定你是否明白
--net=host选项是 docker API 的一部分(并且不建议作为附加参数添加到你的应用程序中),所以我将此点添加到我的答案的可能选项列表中。但可能是,我错过了你的观点,为什么这不是你的选择。