Warning: file_get_contents(/data/phpspider/zhask/data//catemap/8/perl/9.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

Warning: file_get_contents(/data/phpspider/zhask/data//catemap/3/sockets/2.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 选择在关闭的SCTP套接字上返回0_Perl_Sockets_Network Programming_Network Protocols_Sctp - Fatal编程技术网

Perl 选择在关闭的SCTP套接字上返回0

Perl 选择在关闭的SCTP套接字上返回0,perl,sockets,network-programming,network-protocols,sctp,Perl,Sockets,Network Programming,Network Protocols,Sctp,这与以下问题有关: 我有一个简单的echo客户端/并发服务器应用程序,它使用TCP运行得非常好。我可以通过管道将一个文件传输到客户端上的stdin,客户端将接收所有数据,调用select返回1表示套接字可读,然后调用read返回0表示EOF/FIN。然后客户端将退出。一切都很好 但是,SCTP上相同的应用程序会导致问题。唯一的改动是从IPPROTO_TCP改为IPPROTO_SCTP。服务器分叉,echo返回数据,子服务器退出,父服务器获取数据。客户端接收到所有数据,但之后select继续返回0

这与以下问题有关:

我有一个简单的echo客户端/并发服务器应用程序,它使用TCP运行得非常好。我可以通过管道将一个文件传输到客户端上的stdin,客户端将接收所有数据,调用select返回1表示套接字可读,然后调用read返回0表示EOF/FIN。然后客户端将退出。一切都很好

但是,SCTP上相同的应用程序会导致问题。唯一的改动是从IPPROTO_TCP改为IPPROTO_SCTP。服务器分叉,echo返回数据,子服务器退出,父服务器获取数据。客户端接收到所有数据,但之后select继续返回0个描述符就绪,没有我添加的超时,它将永远挂起

到底发生了什么事

以下是客户端的代码:

#!/usr/bin/perl -w
use strict;
use Socket;

# forward declaration
sub logmsg;

my $remote = shift || "localhost";
my $port = 9877;

($port) = $port =~ /^(\d+)$/ or die "invalid port";

my $iaddr = inet_aton($remote) || die "no host: $remote";
my $paddr = sockaddr_in($port, $iaddr);
my $proto = getprotobyname('sctp');

my $sockfd;

socket($sockfd, PF_INET, SOCK_STREAM, $proto) || die "socket: $!";
connect($sockfd, $paddr) || die "connect: $!";

str_cli($sockfd);

exit(0);

#----- subs down here ------#

sub str_cli {
    my $sockfd = shift;

    my ($n, $buff, $stdineof, $s);
    my $rin = '';

    $stdineof = 0;
    while ( 1 ) {
        if ($stdineof == 0) {
            vec($rin, fileno(STDIN), 1) = 1;
        }
        vec($rin, fileno($sockfd), 1) = 1; 

        my $nfound = select($rin, undef, undef, 1.0);
        if ($nfound < 0) {
            next if $!{EINTR};
            die "select: $!";
        } else { print "\$nfound == $nfound\n"; }

        if (vec($rin, fileno($sockfd), 1) == 1) { # socket readable
            print "trying to read from sockfd\n";
            $n = sysread($sockfd, $buff, 1024);
            if (!defined($n) || $n < 0) {
                # resume if sysread() returned because a signal was received
                next if $!{EINTR};
                die "sysread: $!";
            } elsif($n == 0) {
                if ($stdineof == 1) { return; } # normal termination
                else { die "str_cli: server terminated prematurely"; }
            }
            writen(*STDOUT, $buff);
        }

        if (vec($rin, fileno(STDIN), 1) == 1) { # stdin readable
            $n = sysread(STDIN, $buff, 1024);
            if (!defined($n) || $n < 0) {
                # resume if sysread() returned because a signal was received
                next if $!{EINTR};
                die "sysread: $!";
            } elsif($n == 0) {
                $stdineof = 1;
                if (!defined($s = shutdown($sockfd, SHUT_WR)) 
                    || $s == 0) { die("shutdown: $!"); }
                vec($rin, fileno(STDIN), 1) = 0;
                next;
            }
            writen($sockfd, $buff);
        }
    }
}

sub writen {
    my ($connfd, $buff) = @_;
    my $nleft = length($buff);
    my $total = 0;
    my $nwritten = 0;
    while ($nleft) {
        if (($nwritten = syswrite($connfd, $buff, $nleft, $total)) <= 0) {
            # resume if syswrite() returned because a signal was received
            # 0 indicates an error in this context
            next if $!{EINTR};
            die "syswrite: $!";
        }
        $nleft -= $nwritten;
        $total += $nwritten;
    }
}

sub logmsg { print "$0 $$: @_ at ", scalar localtime, "\n" }

记住,这在TCP上非常有效。我在Ubuntu 9.04上安装了所有需要的sctp软件包。

您依赖的是TCP的半关闭状态,这在sctp中是不可用的


使用TCP,shutdown$sockfd,shuth_WR将发送一个设置了FIN位的数据包,关闭连接的发送端,但仍然允许接收方向上的新数据。SCTP没有这种半关闭状态,此调用将启动SCTP关闭序列,其中整个连接关闭。可以找到更多详细信息。

那么,在SCTP中是否有一种方法可以告诉套接字已关闭,而不是应用程序协议级别的通知?如果您希望发送一个指示,表明已完成发送,但仍希望保持连接以接收响应,并且不希望在应用程序层执行此操作,您可以在单独的SCTP流中发送数据。然后,接收方可以对该流的关闭做出反应,并在另一个流中发回响应。@mark4o:您需要使用特定于sctp的api调用才能做到这一点,对吗?有没有使用标准套接字api的方法?只是想知道,在移植现有TCP应用程序时,如果不想引入特定于sctp的api调用,可以做些什么。如果不想使用特定于sctp的调用,如sctp_sendmsg,它将流号作为参数,那么可以使用sendmsg做同样的事情。这在技术上是一个标准的sockets api函数,但是传递给sendmsg的辅助数据是特定于sctp的。这就是我的想法。我只是回顾一下你提供的链接:关机。我的理解是,它关闭关联,但不关闭套接字,这就是为什么select不会像TCP那样返回任何就绪描述符的原因?