You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Perl Fork实现TCP Server无法接收客户端多数据包问题求助

Perl多客户端TCP服务器:修复无法接收后续数据包的问题

问题说明

当前基于fork实现的TCP服务器可接受多客户端连接,但存在以下缺陷:

  • 客户端能正常建立连接
  • 首次发送的数据包可被接收打印
  • 客户端保持连接发送的后续数据包无法被接收

核心原因是子进程仅执行一次recv就退出,没有持续监听客户端的数据流。以下是调整后的代码,实现客户端持续发送数据时,服务器能接收每个数据包并回复。

修改后的代码

#!/usr/bin/perl -w
use IO::Socket::INET;
use POSIX ':sys_wait_h'; # 引入WNOHANG常量

$SIG{CHLD} = sub { 
    # 非阻塞回收子进程,避免僵尸进程
    while ((my $pid = waitpid(-1, WNOHANG)) > 0) {}
};

my $socket = new IO::Socket::INET (
    LocalHost => '0.0.0.0',
    LocalPort => '5000',
    Proto => 'tcp',
    Listen => 10, # 支持至少10个等待连接的客户端
    Reuse => 1
);
die "cannot create socket $!\n" unless $socket;

while (my $new_sock = $socket->accept()) {
    my $pid = fork();
    die "Cannot fork: $!" unless defined($pid);

    if ($pid == 0) {     # 子进程负责处理单个客户端连接
        $socket->close(); # 子进程无需持有监听socket,立即关闭
        
        while (1) {
            my $data;
            # 接收客户端数据,返回值为接收的字节数
            my $bytes_recv = $new_sock->recv($data, 500);
            
            # 客户端断开连接(recv返回undef或0)时退出循环
            last unless defined $bytes_recv && $bytes_recv > 0;
            
            chomp $data;
            print "Received: $data\n";
            
            # 向客户端发送回复
            my $response = "Server ack: $data\n";
            $new_sock->send($response);
        }
        
        $new_sock->close(); # 关闭客户端连接
        exit(0); # 子进程正常退出
    } else {
        $new_sock->close(); # 父进程无需持有客户端连接,立即关闭
    }
}

关键修改点

  • 持续监听数据流:在子进程中添加while(1)循环,让子进程持续调用recv接收客户端数据,直到连接断开
  • 连接状态判断:通过recv的返回值判断客户端是否断开,避免无限阻塞
  • 回复逻辑:新增send调用,实现服务器对每个数据包的回复
  • 资源优化:父/子进程分别关闭不需要的socket,避免资源泄漏;改进子进程回收逻辑,防止僵尸进程
  • 满足连接需求:将Listen参数调整为10,支持至少10个等待连接的客户端

内容的提问来源于stack exchange,提问作者Lucas Rey

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.21 22:12:26