Warning: file_get_contents(/data/phpspider/zhask/data//catemap/9/extjs/3.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Perl 未接收到关机前发送的所有套接字数据_Perl_Sockets - Fatal编程技术网

Perl 未接收到关机前发送的所有套接字数据

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'

我正在编写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'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,你不会发现任何关于刷新的提示。另外,的手册页根本没有提到这种行为

实际问题是客户端代码中的以下行(请参阅代码注释):

filehandle
SOCKET
已完全缓冲,这意味着您的数据不会立即打印到网络中,而是首先在内部缓冲区中累积。一旦内部缓冲区被填满,其数据将被发送。您试图通过
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
。例如,更好,有更多的例子