使用Perl通过套接字传递文件名

3

我有两个用perl编写的脚本。第一个脚本将一个文件通过socket发送到服务器。服务器是我的第二个脚本,它将文件保存到一个文件中。 服务器会将文件保存为指定名称,该名称在代码中被固定。如何在发送文件之前获取发送文件的名称并将其发送到服务器? 请看下面是我的代码: 客户端:

my $socket = IO::Socket::INET->new(
    PeerAddr    =>  $local_host,
    PeerPort    =>  $local_port,
    Proto       => 'tcp',

)or die "Alert!";
my $bandwidth = 1024*5 ; # 5Kb/s - 
open my $fh, '<', "$direc/$my_data"
    or die "couldn't open the file";

  my $buffer ;
  while( sysread($fh, $buffer , $bandwidth) ) {
    print $socket $buffer ;
    sleep(1) ;
  }

  print "Data send.End \n" ;

  close ($fh) ;
  close($socket) ;

我的服务器:

my $my_socket = new IO::Socket::INET(
    LocalHost => $local_host,
    LocalPort => $local_port,
    Proto     => 'tcp',
    Listen    => 5,
    Reuse     => 1
);
die "Couldn't open my_socket $!n " unless $my_socket;
print "You can send the data now \n";
my $accepter = $my_socket->accept();
my $count=0;
#print "$directory.$save_dir/$my_data";
open my $fh, '>', "$direc/$save_dir/$my_data" #my data is the name, and it's "fixed", how to take it from client?
    or die "Couldn't open the file";
while(<$accepter>){
    chomp;
    last if $count++ ==10;
    say $fh $_;

}


print "End \n";
close $fh;
close $my_socket;
1个回答

4

让服务器写入客户端指定的文件名是一种安全风险。客户端可以告诉服务器覆盖文件,包括服务器本身。

相反,使用UUID作为真正的文件名。在其他地方存储客户端文件名/真实文件名对。


您需要想出一个协议,以便服务器可以区分文件名和内容。我们可以使用现有格式,如JSON或YAML,但它们需要将整个文件读入内存并编码内容。你可以自己构建一些东西,比如“第一行是文件名”,但我们可以做得更好。

如果您想进行流处理,我们可以使用一个简化版的HTTP协议。发送标题作为 Key: Value 行。空行结束标题,并开始发送内容。稍微付出一点额外的努力,我们就可以拥有一个简单而可扩展的协议。

这是服务器使用UUID::Tinyautodie的主循环。

# Read Key: Value headers until we see a blank line.
my %headers;
while(my $line = <$accepter>) {
    chomp $line;
    
    last if $line eq "";

    my($key, $value) = split /\s*:\s*/, $line;
    $headers{$key} = $value;
}

# Store the file in a random filename. Do not use the client's filename
# to avoid a host of security issues.
my $filename = create_uuid_as_string(UUID_V4);
open my $fh, ">", "incoming/$filename";

# Read the content and save it to the file.
my $buf;
while( read($accepter, $buf, 1024) ) {
    print $fh $buf;
}

say "$headers{Filename} was stored in incoming/$filename";
close $my_socket;

而客户端只需在发送文件内容之前发送一个“文件名”头。

open my $fh, '<', $filename;

print $socket "Filename: $filename\n\n";

my $buffer ;
while( sysread($fh, $buffer , $bandwidth) ) {
    print $socket $buffer ;
}

好的,谢谢你的帮助。不幸的是,你的答案没有解决我的问题。这是一个学校项目 :( - The Trainer
@TheTrainer 抱歉,它没有修复什么? - Schwern
传递名称 ;) 我知道 - 这不安全。在您的回答之后,我考虑了我的服务器。我以这种方式创建名称:“received_data_<current_date>”。但我仍然无法发送文件名。 - The Trainer
1
@TheTrainer 在这个答案中,客户端确实将文件名传递给了服务器。它在$headers{Filename}中。只是它没有用它来打开一个文件,但你应该能够进行修改。 - Schwern

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接