免费注册 查看新帖 |

Chinaunix

  平台 论坛 博客 文库
最近访问板块 发新帖
查看: 2411 | 回复: 5
打印 上一主题 下一主题

perl socket 传送文件内存越来越大,内存怎么回收? [复制链接]

论坛徽章:
0
跳转到指定楼层
1 [收藏(0)] [报告]
发表于 2013-04-19 10:07 |只看该作者 |倒序浏览
本帖最后由 zhlong8 于 2013-04-19 15:10 编辑

请教各位大神:我想做一个文件服务器,用PERL SOCKET实现文件下载,源码如下,我的服务器端,进程在运行的过程中内存越占越多,请教有没有好的内存回收方法?
刚开始后占同存如下:


请求下载一个104MB的文件后


请求下载一个379mb的文件后


再请求下载一个104MB的文件后



下面是源码,请求各位帮助。谢谢!
服务端:
#!/usr/bin/perl
#Poster.pl
use Socket;
use IO::Socket::INET;
use IO::Select;
use strict;

while(1){
          my $file;
    my $server = IO::Socket::INET->new( LocalPort     => 9000,
                                        Listen        =>    5,   
                                        Proto         => 'tcp')
            or die "Couldn`t be a tcp server on port: 9000 :$@\n";
     #接收远程需求
    my $sel = IO::Select->new($server);
    while (my @ready = $sel->can_read) {
            foreach my $fh (@ready) {
                    #print "$fh == $server \n";
                if ($fh == $server) {
                    my $new = $server->accept();
                    $sel->add($new);
                }
                else {
                   $fh->recv($file,1024,0); #接收客户端消息
                   # print "$file 435345\n";

                    if (-e "$file") {
                    $fh->send("$file 存在,数据传输送开始 OK!\n",0);  #发送服务端消息
                     }
                    $fh->autoflush(1);
                    $sel->remove($fh);
                    $fh->close();
                       if (-e "$file") {
                               close ($server);  
                               &senddata("$file");
                                   open (F_L,">c:/tcp.log");
                            print F_L "$file\n";
                            close(F_L);
                      }
                }
            $fh = undef;
            }
    }              
  close ($server);
  $sel=undef;
  $server=undef;
}            
sub senddata {
        my ($file) = @_;
        print "$file senddata \n";
    #发送端代码
    #创建一个套接字,定义最大连接数为5,本地端口为9000,链接协议为tcp
    my $server = IO::Socket::INET->new(    LocalPort     => 9000,
                                        Listen        =>    5,   
                                        Proto         => 'tcp')
            or die "Couldn`t be a tcp server on port: 9000 :$@\n";
    #等待远程连接   
                           
    while( my ($client,$client_IP) = $server->accept()){
        my($port,$packed_ip) = sockaddr_in($client_IP);
        my $ip = inet_ntoa($packed_ip);
        print "有客户端:< $ip >连接上,准备传输数据....\n";
        #打开指定文件
        open IN,"<$file";
        #以二进制形式操作
        binmode(IN);
        
        #与客户端建立连接后,以二进制形式读取文件数据,向套接字发送数据
        my @out = <IN>;
        
        print $client @out;
        close IN;
        close ($server);            
    };
   $server = undef;
    print "数据传输完毕\n";       
       
}            


客户端:

#!/usr/bin/perl -w
use IO::Socket;  ##IO::Socket::INET模块是IO::Socket模块的子模块,不用重新use。
use IO::Select;  ##该模块和Linux下select()函数实现的功能一致,另扩展更过的功能。可以perldoc查看。
# hash to install IP Port
%ser_info = (
    "ser_ip" => "127.0.0.1",
    "ser_port" => "9000",
);
my $inputfile = $ARGV[0];
my $outfile = $ARGV[1];
&main();
#&maintest(); #接收返回信息
#&mainq();
sub mainq {
    my $files1;
    my $ser_addr = $ser_info{"ser_ip"};
    my $ser_port = $ser_info{"ser_port"};
    ##IO::Socket::INET->new()用于初始化一个socket连接,其中集成了socket、inet_aton、connect、bind、listen等功能。就不需要单独转换IP地址为网络地址结构了,直接使用IP地址就ok了。
    ##具体参数下面单独介绍。
    my $socket = IO::Socket::INET->new(
                                         PeerAddr => "$ser_addr",
                                         PeerPort => "$ser_port",
                                         Type => SOCK_STREAM,
                                         Proto => "tcp",
                                       )
       or die "Can not create socket connect.$@";
      
    if($socket){
        #当连接建立
        print"连接上了远程主机:$ser_addr,准备接收数据\n";
        my @Receive = <$socket>;
        open(OUT,">$files1");
            binmode(OUT);
        print OUT @Receive;
        close OUT;
        
    }                                   
   # close($socket);
    print"数据接收完毕\n";           
print "test \n";       
}

sub main {
    my $ser_addr = $ser_info{"ser_ip"};
    my $ser_port = $ser_info{"ser_port"};
    my $file_exists = 'no';
    ##IO::Socket::INET->new()用于初始化一个socket连接,其中集成了socket、inet_aton、connect、bind、listen等功能。就不需要单独转换IP地址为网络地址结构了,直接使用IP地址就ok了。
    ##具体参数下面单独介绍。
    my $socket = IO::Socket::INET->new(
                                         PeerAddr => "$ser_addr",
                                         PeerPort => "$ser_port",
                                         Type => SOCK_STREAM,
                                         Proto => "tcp",
                                       )
       or die "Can not create socket connect.$@";
    $socket->send("$inputfile",0);  ##发送消息至服务器端。
    $socket->autoflush(1);
    my $files1 = "$outfile";
    print "$socket  ok\n";
   # $socket->autoflush(1);
   # print "$socket \n";
    my $sel = IO::Select->new($socket); ##建立select对象
    while (my @ready = $sel->can_read) {    ##等待服务端返回的消息
            foreach my $fh (@ready) {
                if ($fh == $socket) {
                    while (<$fh>) {
                      print $_;
                      if (length($_) > 0) {
                              $file_exists = 'yes';
                      }
                    }
                    $sel->remove($fh);  
                    close $fh;
                    #close $;
                }
            }
    }
    close($socket);
   if ($file_exists eq 'yes') {
    &maintest();
  }
  #  $socket->close() or die "Close Socket failed";
}

sub maintest {
       $file = "$outfile";
       my $host = $ser_info{"ser_ip"};
    my $socket = IO::Socket::INET->new(PeerAddr  => $ser_info{"ser_ip"},
                                       PeerPort    => 9000,
                                       Proto    => 'tcp')
         or die "Couldn`t connect to $host:9000\n";                          
    if($socket){
        #当连接建立
        print"连接上了远程主机:,准备接收数据\n";
        my @Receive = <$socket>;
        open(OUT,">$file");
            binmode(OUT);
        print OUT @Receive;
        close OUT;
        
    }                                   
    close($socket);
    print"数据接收完毕\n";
}

QQ截图20130419100011.png (3.1 KB, 下载次数: 28)

QQ截图20130419100011.png

QQ截图20130419095942.png (1.91 KB, 下载次数: 22)

QQ截图20130419095942.png

QQ截图20130419095935.png (3.28 KB, 下载次数: 26)

QQ截图20130419095935.png

论坛徽章:
42
19周年集字徽章-周
日期:2019-10-14 14:35:31平安夜徽章
日期:2015-12-26 00:06:30数据库技术版块每日发帖之星
日期:2015-12-01 06:20:002015亚冠之首尔
日期:2015-11-04 22:25:43IT运维版块每日发帖之星
日期:2015-08-17 06:20:00寅虎
日期:2014-06-04 16:25:27狮子座
日期:2014-05-12 11:00:00辰龙
日期:2013-12-20 17:07:19射手座
日期:2013-10-24 21:01:23CU十二周年纪念徽章
日期:2013-10-24 15:41:34IT运维版块每日发帖之星
日期:2016-01-27 06:20:0015-16赛季CBA联赛之新疆
日期:2016-06-07 14:10:01
2 [报告]
发表于 2013-04-19 10:59 |只看该作者
my @out = <IN>;
这里的问题

perl不会立刻释放没用的内存.
而且你的内存也并非持续增长.

论坛徽章:
0
3 [报告]
发表于 2013-04-19 11:09 |只看该作者
谢谢!有好的解决方法没?我测试后的结果是持续增长。

论坛徽章:
42
19周年集字徽章-周
日期:2019-10-14 14:35:31平安夜徽章
日期:2015-12-26 00:06:30数据库技术版块每日发帖之星
日期:2015-12-01 06:20:002015亚冠之首尔
日期:2015-11-04 22:25:43IT运维版块每日发帖之星
日期:2015-08-17 06:20:00寅虎
日期:2014-06-04 16:25:27狮子座
日期:2014-05-12 11:00:00辰龙
日期:2013-12-20 17:07:19射手座
日期:2013-10-24 21:01:23CU十二周年纪念徽章
日期:2013-10-24 15:41:34IT运维版块每日发帖之星
日期:2016-01-27 06:20:0015-16赛季CBA联赛之新疆
日期:2016-06-07 14:10:01
4 [报告]
发表于 2013-04-19 11:48 |只看该作者
按一定大小分块读啊
你一次性读到内存,当然就大了.
不过300多M,还不止于崩溃.

perl有垃圾回收机制
不是线性增长就没关系

论坛徽章:
1
辰龙
日期:2014-05-15 19:37:15
5 [报告]
发表于 2013-04-19 13:59 |只看该作者
本帖最后由 iakuf 于 2013-04-19 14:01 编辑

回复 1# lhep041
不是很明白这个服务器为什么要开二次端口,第一次监听,第二次关掉第一个,然后在开一个来发文件是为什么(因为我并没见到 fork)。


   

论坛徽章:
42
19周年集字徽章-周
日期:2019-10-14 14:35:31平安夜徽章
日期:2015-12-26 00:06:30数据库技术版块每日发帖之星
日期:2015-12-01 06:20:002015亚冠之首尔
日期:2015-11-04 22:25:43IT运维版块每日发帖之星
日期:2015-08-17 06:20:00寅虎
日期:2014-06-04 16:25:27狮子座
日期:2014-05-12 11:00:00辰龙
日期:2013-12-20 17:07:19射手座
日期:2013-10-24 21:01:23CU十二周年纪念徽章
日期:2013-10-24 15:41:34IT运维版块每日发帖之星
日期:2016-01-27 06:20:0015-16赛季CBA联赛之新疆
日期:2016-06-07 14:10:01
6 [报告]
发表于 2013-04-22 09:07 |只看该作者
感觉是一个单用户ftp的模拟~~
您需要登录后才可以回帖 登录 | 注册

本版积分规则 发表回复

  

北京盛拓优讯信息技术有限公司. 版权所有 京ICP备16024965号-6 北京市公安局海淀分局网监中心备案编号:11010802020122 niuxiaotong@pcpop.com 17352615567
未成年举报专区
中国互联网协会会员  联系我们:huangweiwei@itpub.net
感谢所有关心和支持过ChinaUnix的朋友们 转载本站内容请注明原作者名及出处

清除 Cookies - ChinaUnix - Archiver - WAP - TOP