`
xumingyong
  • 浏览: 183413 次
  • 性别: Icon_minigender_1
  • 来自: 成都
社区版块
存档分类
最新评论

Perl实现Websocket-76的TCP并发连接服务器端

    博客分类:
  • Perl
阅读更多

直接上代码:

 

################################################################################
# Filename:
#   websocket.pl
# Description:
#   Perl mutithreaded TCP server of HTML5 Websocket-draft-76
# Test enviroment:
#   OS      - Windows XP
#   Perl    - ActivePerl 5.12.1
#   Browser - Chrome 8.0
################################################################################
#!/usr/bin/perl -w
use strict;
use warnings;
use 5.010;

use IO::Socket::INET;
use Digest::MD5 qw/md5/;
use Redis;
use POSIX ':sys_wait_h';

### main part ##################################################################
### system level options
my %VARS = (
  DEBUG => 1,
  LOG2FILE => 0
);

#common global variables
my @TIMER_TASK;   #its element is %{task_name, interval fun_ref}

### stdout to log file
if( $VARS{LOG2FILE} ){
  open LOG, ">>syslog.txt";
  select LOG;
}

### redis db initialization
my $r = Redis->new;
$r->ping or die now() . "[Server]: connect Redis failed";
$r->flushall;

my $redis_sock = $$r{sock};
$r->hset("sys:sock", "redis", $redis_sock);
say now() . " | Redis: " . $redis_sock->sockhost() . ":" . $redis_sock->sockport() .
    " <---> " . $redis_sock->peerhost() . ":" . $redis_sock->peerport();

### tcp server
my $PORT = 8000;
my $server = IO::Socket::INET->new( Proto     => 'tcp',
                                 LocalPort => $PORT,
                                 Listen    => 255,
                                 Reuse     => 1);
$server or die now() . "[Server]: Err = can't setup server";
say now() . " | Server: Listening at TCP:" . $server->sockport;

#zombie
my $zombies = 0;
$SIG{CHLD} = sub {$zombies++;};

while(my $client = $server->accept()){
  #zombie reaper
  while($zombies) {
    $zombies = 0;
    while ((my $zombie = waitpid( -1, WNOHANG)) != -1){}
  };
  $client->autoflush(1);
 
  #handshake
  sysread $client, my $handshake_req, 1024;
  my($handshake_resp,$page) = handshake($handshake_req);
  print $client $handshake_resp;
  
  close $client unless $client;
  my $client_info = $client->peerhost() . ":" . $client->peerport() . "$page";
  $r->hset("sys:sock", $client_info,$client);
  say now() . " | Client: connected from " . $client_info;
  
  #data framing
  $client->blocking(0);

  #fork child for new connection
  if(my $child = fork()){     
    $/ = "\xff";  #new line seperator
    my($req,@resp);
    while(<$client>){    
      /\x00(.*)\xff/;
      $req = $1;   
      say now() . " | ws://" . "$client_info >>> [$req]" if $VARS{DEBUG};

   
      @resp = request($req);
      foreach my $resp (@resp){
        say now() . " | ws://" . "$client_info <<< [$resp]" if $VARS{DEBUG};
        print $client "\x00$resp\xff";
      }    
    }

    return;    #go back to parent
  }
}

### sub routines ###############################################################
# Description:  Request format from webSocket
# Format:       command param1,param2, ... ,paramN
sub request{
  my @resp = ();
  $_ = shift;  
  my($cmd, @param) = split / /;
  $cmd = "req_$cmd";
  
  if(defined(&$cmd)){
    no strict 'refs';
    @resp = $cmd->(@param);
  }else{
    push @resp, "!$_";
  }
  return @resp;
}

sub req_echo{ return @_; }
sub req_random{
  $_ = shift;
  my $r;
  if(/float/){ #float
    $r = rand(100);
  }else{    #integer
    $_ = "int";
    $r = int(rand(100));
  }
  return ("random: $_ = $r");
}

sub req_showsock{
  my @socks = ();
  my %s = $r->hgetall("sys:sock");
  say "..............";
  foreach (keys %s){
    say ;
    #push @socks, $item;
  }
  return @socks;
}



sub now{
  my($sec,$min,$hour,$mday,$mon,$year,$wday,$yday,$isdst)=localtime(time);
  $year += 1900;
  return sprintf("%.4d-%.2d-%.2d %2d:%.2d:%.2d",$year,$mon,$mday,$hour,$min,$sec);
}

sub handshake{
  my $req = shift;
  ($req, my $key3) = split /\r\n\r\n/, $req;  
  my @req = split /\r\n/, $req;
  
  my $field = shift @req;
  $field =~ /GET (.*) HTTP/;
  my $page = $1;
  
  $field = shift @req;
  $field = shift @req;
  $field = shift @req;
  $field =~ /Host: (.*)/;
  my $location = "ws://" . $1 . $page;
  
  $field = shift @req;
  $field =~ /Origin: (.*)/;
  my $origin = $1;
  
  $field = shift @req;
  $field =~ /Sec-WebSocket-Key1: (.*)/;
  $field = $1;
  my @key1= $field =~ /([0-9])/g;
  my $key1 = join('', @key1) + 0;
  my @space1 = $field =~ /\x20/g;
  my $space1 = @space1 + 0;
  my $part1 = $key1 / $space1;
  my $part1_hex = pack 'L>', $part1;
  
  $field = shift @req;
  $field =~ /Sec-WebSocket-Key2: (.*)/;
  $field = $1;
  my @key2 = $field =~ /([0-9])/g;
  my $key2 = join('', @key2) + 0;
  my @space2 = $field =~ /\x20/g;
  my $space2 = @space2 + 0;
  my $part2 = $key2 / $space2;
  my $part2_hex = pack 'L>', $part2;
  
  my $challenge = md5($part1_hex, $part2_hex, $key3);
  my $resp = "HTTP/1.1 101 Web Socket Protocol Handshake\r\n" .
            "Upgrade: WebSocket\r\n" . 
            "Connection: Upgrade\r\n" .
            "Sec-WebSocket-Origin: $origin\r\n" .
            "Sec-WebSocket-Location: $location\r\n\r\n" . $challenge;  
  return ($resp, $page);
}

sub hexcode{
  my $str = unpack 'H*', shift;
  $str =~ s/(.)(.)/\U$1$2 /g;
  return $str;
}
 
分享到:
评论

相关推荐

    java开源包1

    WebSocket4J 并未实现客户端通讯协议,所以不能用它来连接 WebSocket 服务器。 Struts验证码插件 JCaptcha4Struts2 JCaptcha4Struts2 是一个 Struts2的插件,用来增加验证码的支持,使用时只需要用一个 JSP 标签 ...

    libevent libevent-2.1.8-stable.tar.gz

    在实际开发中,利用Libevent可以构建出高并发、低延迟的网络服务,例如WebSocket服务器、实时聊天系统、流媒体服务等。通过深入理解和灵活运用Libevent,开发者可以更专注于业务逻辑,而非底层的网络通信细节,从而...

    java开源包4

    WebSocket4J 并未实现客户端通讯协议,所以不能用它来连接 WebSocket 服务器。 Struts验证码插件 JCaptcha4Struts2 JCaptcha4Struts2 是一个 Struts2的插件,用来增加验证码的支持,使用时只需要用一个 JSP 标签 ...

    java开源包3

    WebSocket4J 并未实现客户端通讯协议,所以不能用它来连接 WebSocket 服务器。 Struts验证码插件 JCaptcha4Struts2 JCaptcha4Struts2 是一个 Struts2的插件,用来增加验证码的支持,使用时只需要用一个 JSP 标签 ...

    java开源包10

    WebSocket4J 并未实现客户端通讯协议,所以不能用它来连接 WebSocket 服务器。 Struts验证码插件 JCaptcha4Struts2 JCaptcha4Struts2 是一个 Struts2的插件,用来增加验证码的支持,使用时只需要用一个 JSP 标签 ...

    nginx基础和优化配置.rar

    通过设置相应的fastcgi_pass或proxy_pass,Nginx能够转发请求到相应服务,实现前后端分离。 **7. Nginx在国内知名网站的应用案例** 在中国,很多大型网站如淘宝、新浪等都采用Nginx作为其基础设施的一部分。这些...

    java开源包11

    WebSocket4J 并未实现客户端通讯协议,所以不能用它来连接 WebSocket 服务器。 Struts验证码插件 JCaptcha4Struts2 JCaptcha4Struts2 是一个 Struts2的插件,用来增加验证码的支持,使用时只需要用一个 JSP 标签 ...

    java开源包2

    WebSocket4J 并未实现客户端通讯协议,所以不能用它来连接 WebSocket 服务器。 Struts验证码插件 JCaptcha4Struts2 JCaptcha4Struts2 是一个 Struts2的插件,用来增加验证码的支持,使用时只需要用一个 JSP 标签 ...

    java开源包6

    WebSocket4J 并未实现客户端通讯协议,所以不能用它来连接 WebSocket 服务器。 Struts验证码插件 JCaptcha4Struts2 JCaptcha4Struts2 是一个 Struts2的插件,用来增加验证码的支持,使用时只需要用一个 JSP 标签 ...

    java开源包5

    WebSocket4J 并未实现客户端通讯协议,所以不能用它来连接 WebSocket 服务器。 Struts验证码插件 JCaptcha4Struts2 JCaptcha4Struts2 是一个 Struts2的插件,用来增加验证码的支持,使用时只需要用一个 JSP 标签 ...

    java开源包8

    WebSocket4J 并未实现客户端通讯协议,所以不能用它来连接 WebSocket 服务器。 Struts验证码插件 JCaptcha4Struts2 JCaptcha4Struts2 是一个 Struts2的插件,用来增加验证码的支持,使用时只需要用一个 JSP 标签 ...

    java开源包7

    WebSocket4J 并未实现客户端通讯协议,所以不能用它来连接 WebSocket 服务器。 Struts验证码插件 JCaptcha4Struts2 JCaptcha4Struts2 是一个 Struts2的插件,用来增加验证码的支持,使用时只需要用一个 JSP 标签 ...

    java开源包9

    WebSocket4J 并未实现客户端通讯协议,所以不能用它来连接 WebSocket 服务器。 Struts验证码插件 JCaptcha4Struts2 JCaptcha4Struts2 是一个 Struts2的插件,用来增加验证码的支持,使用时只需要用一个 JSP 标签 ...

    java开源包101

    WebSocket4J 并未实现客户端通讯协议,所以不能用它来连接 WebSocket 服务器。 Struts验证码插件 JCaptcha4Struts2 JCaptcha4Struts2 是一个 Struts2的插件,用来增加验证码的支持,使用时只需要用一个 JSP 标签 ...

    Java资源包01

    WebSocket4J 并未实现客户端通讯协议,所以不能用它来连接 WebSocket 服务器。 Struts验证码插件 JCaptcha4Struts2 JCaptcha4Struts2 是一个 Struts2的插件,用来增加验证码的支持,使用时只需要用一个 JSP 标签 ...

    GroupOn:GUI聊天应用

    Socket是TCP/IP协议的一部分,提供双向通信通道,而WebSocket是一种在客户端和服务器之间建立持久连接的协议,适合于实时、低延迟的交互应用,如聊天应用。GroupOn可能采用了其中的一种或结合两者,以实现高效的消息...

    Apache2.4.37

    1. **HTTP/2支持**:这个版本引入了对HTTP/2协议的支持,这是一个升级版的网络通信协议,旨在减少延迟,提高数据传输效率,通过单个TCP连接并发处理多个请求。 2. **事件模型**:Apache2.4引入了一种新的事件模型,...

Global site tag (gtag.js) - Google Analytics