Perl 未接收到关机前发送的所有套接字数据
我正在编写Perl脚本,以便通过TCP在客户端和服务器之间发送字符串。已建立连接,但未收到从客户端发送的数据 服务器的完整代码Perl 未接收到关机前发送的所有套接字数据,perl,sockets,Perl,Sockets,我正在编写Perl脚本,以便通过TCP在客户端和服务器之间发送字符串。已建立连接,但未收到从客户端发送的数据 服务器的完整代码 #!/usr/bin/perl -w use strict; use Socket; my $port = 8021; my $proto = getprotobyname ('tcp'); my $server = "localhost"; socket (SOCKET, PF_INET, SOCK_STREAM, $proto) or die "Can'
#!/usr/bin/perl -w
use strict;
use Socket;
my $port = 8021;
my $proto = getprotobyname ('tcp');
my $server = "localhost";
socket (SOCKET, PF_INET, SOCK_STREAM, $proto)
or die "Can't open socket: $!";
bind (SOCKET, pack_sockaddr_in ($port, inet_aton ($server)))
or die "Can't bind $server:$port: $!";
listen (SOCKET, 5)
or die "Can't listen on $server:$port: $!";
my $client_addr;
while ($client_addr = accept (NEW_SOCKET, SOCKET))
{
my $name = gethostbyaddr ($client_addr, AF_INET);
while (<NEW_SOCKET>)
{
print "Recieved from client: $_<<ENDL\n";
}
print NEW_SOCKET "Smile from the server.";
print "Connection recieved from $name\n";
close NEW_SOCKET or warn "Couldn't close socket: $!";
}
目前,服务器输出
Connection recieved from ANantes-256-1-226-50.w2-0.abo.wanadoo.fr
和客户端输出
Server localhost:8021 responds with: Smile from the server.<<ENDL
服务器localhost:8021响应:来自服务器的微笑。这是一个典型的例子:。如果你对更多细节感兴趣,我建议你阅读这篇文章
当然,当你关机时,所有待处理的数据都应该被刷新,对吗
事实并非如此。如果你检查一下的perldoc,你不会发现任何关于刷新的提示。另外,的手册页根本没有提到这种行为
实际问题是客户端代码中的以下行(请参阅代码注释):
filehandleSOCKET
已完全缓冲,这意味着您的数据不会立即打印到网络中,而是首先在内部缓冲区中累积。一旦内部缓冲区被填满,其数据将被发送。您试图通过print
发送的消息只有几个字节长-远远没有将内部缓冲区填充到其最大大小
您已经了解了如何使用特殊的Perl变量$|
修改默认缓冲行为。通过更改此变量的默认值,可以使当前活动的filehandle成为热文件。这意味着内部缓冲区将在每次打印到文件句柄后刷新
现在,让我们看看如果要发送以下消息,您必须使用哪些不同的选项来替换上面提到的有问题的行:
my $msg = "Test message from client to $server:$port.";
选项#1:
use FileHandle;
SOCKET->autoflush(1);
print SOCKET $msg;
use IO::Handle; # or: use FileHandle
print SOCKET $msg;
SOCKET->flush();
{
my $oldfh = select SOCKET;
local $| = 1; # make SOCKET hot
print SOCKET $msg;
select $oldfh;
}
syswrite SOCKET, $msg;
use IO::Socket::INET;
my $sock = IO::Socket::INET->new(
PeerAddr => $server,
PeerPort => $port,
Proto => "tcp"
);
$sock->send($msg);
您可以使用FileHandle
中的autoflush()
选项2:
use FileHandle;
SOCKET->autoflush(1);
print SOCKET $msg;
use IO::Handle; # or: use FileHandle
print SOCKET $msg;
SOCKET->flush();
{
my $oldfh = select SOCKET;
local $| = 1; # make SOCKET hot
print SOCKET $msg;
select $oldfh;
}
syswrite SOCKET, $msg;
use IO::Socket::INET;
my $sock = IO::Socket::INET->new(
PeerAddr => $server,
PeerPort => $port,
Proto => "tcp"
);
$sock->send($msg);
您还可以使用方法flush()
在打印后手动刷新
选项#3:
use FileHandle;
SOCKET->autoflush(1);
print SOCKET $msg;
use IO::Handle; # or: use FileHandle
print SOCKET $msg;
SOCKET->flush();
{
my $oldfh = select SOCKET;
local $| = 1; # make SOCKET hot
print SOCKET $msg;
select $oldfh;
}
syswrite SOCKET, $msg;
use IO::Socket::INET;
my $sock = IO::Socket::INET->new(
PeerAddr => $server,
PeerPort => $port,
Proto => "tcp"
);
$sock->send($msg);
这将通过在本地范围中将$|
设置为1
来选择文件句柄套接字
,使其变热。在这之后,您的消息$msg
将通过print
发送,并通过重新选择旧文件句柄来恢复。全局变量$|
的旧值保持不变,因为我们仅在{}
块内局部更改了它
选项4:
use FileHandle;
SOCKET->autoflush(1);
print SOCKET $msg;
use IO::Handle; # or: use FileHandle
print SOCKET $msg;
SOCKET->flush();
{
my $oldfh = select SOCKET;
local $| = 1; # make SOCKET hot
print SOCKET $msg;
select $oldfh;
}
syswrite SOCKET, $msg;
use IO::Socket::INET;
my $sock = IO::Socket::INET->new(
PeerAddr => $server,
PeerPort => $port,
Proto => "tcp"
);
$sock->send($msg);
此外,您可以简单地使用syswrite()
完全绕过内部缓冲
选项#5:
use FileHandle;
SOCKET->autoflush(1);
print SOCKET $msg;
use IO::Handle; # or: use FileHandle
print SOCKET $msg;
SOCKET->flush();
{
my $oldfh = select SOCKET;
local $| = 1; # make SOCKET hot
print SOCKET $msg;
select $oldfh;
}
syswrite SOCKET, $msg;
use IO::Socket::INET;
my $sock = IO::Socket::INET->new(
PeerAddr => $server,
PeerPort => $port,
Proto => "tcp"
);
$sock->send($msg);
这是简单和直接的使用和取代几乎所有的代码。根据以下文件:
从版本1.18开始,默认情况下,所有IO::Socket对象都启用了自动刷新。早期版本并非如此
所有这5个选项都将为您提供所需的行为。您的服务器的while
中的服务器是什么?请使用警告
。这是一个输入错误,我修复了它,谢谢,但仍然有相同的问题。好的,我在服务器中将它改为而()
,现在两个程序都挂起。好的,修补完全改变了问题的范围。请重读一遍。现在不能讲,但要晚一点。如果这是关于学习如何更好地使用IO::Socket
。例如,更好,有更多的例子