zoukankan      html  css  js  c++  java
  • websocket draft15 服务端握手Demo的perl实现

    websocket这个坑爹的项目一直都在草案中,而且有时的更新变化还挺大的。目前最新的版本要先握手,信任后再发送相应数据,数据还掩码了。这次先实现了握手功能,其原理如下:

    1.客端向服务器端发送类似这样的HTTP头:

            GET / HTTP/1.1
            Upgrade: websocket
            Connection: Upgrade
            Host: localhost:8000
            Sec-WebSocket-Origin: null
            Sec-WebSocket-Key: FcJ21uh+iiDs7haoaG1cKQ==
            Sec-WebSocket-Version: 8

    其中

        Upgrade:wesocket 描述了该信息是websocket协议,

        Host:localhost:8000 这个就是请求的主机地址和端口号,

        Sec-WebSocket-Version:8 是版本号,这里是8,用的chrome14作的测试

        Sec-WebSocket-Key: FcJ21uh+iiDs7haoaG1cKQ== 这条是很重要的,FcJ21uh+iiDs7haoaG1cKQ==是客户端提供的握手所用的key,需要服务器端根据该key作相应计算后返回一个对应的key来完成握手,具体的计算方法马上就会说到。

    2. 服务器端

            服务器端接收到请求的数据后,先根据头来判断是否为websocket协议,是的话就会先作握手处理,然后再进行数据的相互发送,这里先只讨论握手,数据发送的内容下次再说了。。。。

                握手步骤:

          (1)服务器端获取到客户端发送过来的 Sec-WebSocket-Key 值(比如这里的 FcJ21uh+iiDs7haoaG1cKQ== );

          (2)将获取到的key值与一个magic string “258EAFA5-E914-47DA-95CA-C5AB0DC85B11” 连接成一个新的key串 "FcJ21uh+iiDs7haoaG1cKQ==258EAFA5-E914-47DA-95CA-C5AB0DC85B11",这个magic string为标准里给出的值,可以看作为一个唯一ID序列;

          (3)将新生成的串进行SHA1编码,生成一个由多组两位16进制数构成的加密串,比如这里的 "FcJ21uh+iiDs7haoaG1cKQ==258EAFA5-E914-47DA-95CA-C5AB0DC85B11" 将生成 "11a8a543955aaf7f9a266c55b2a9cda3151cdec5";

          (4)把加密串按2位16进制数字分隔,进行base64编码生成最终的key:base64编码(11 a8 a5 43 95 5a af 7f 9a 26 6c 55 b2 a9 cd a3 15 1c de c5);

          (5)将最终生成的key以Sec-WebSocket-Accept:key值 整合到返回头中返回给客户端(该例子的key计算结果为 EailQ5Var3+aJmxVsqnNoxUc3sU=):

                HTTP/1.1 101 Web Socket Protocol Handshake
                Upgrade: websocket
                Connection: Upgrade
                Sec-WebSocket-Accept: EailQ5Var3+aJmxVsqnNoxUc3sU=
                WebSocket-Origin: localhost
                WebSocket-Location: ws://localhost:8000

    服务端应答后就完成了这一次的握手,完整代码如下:

    #!perl -w
    use strict;

    use IO::Handle;
    use Socket;
    use Digest::SHA1 qw(sha1 sha1_hex sha1_base64);
    use MIME::Base64;

    my $buff;
    my $port=8000;
    my $host='localhost';
    my $packhost=inet_aton($host);
    my $address=sockaddr_in($port,$packhost);
    my $msg="";
    my $magicString="258EAFA5-E914-47DA-95CA-C5AB0DC85B11";
    my $serverKey="";

    sub getClientKey{
        my $ret="";
        if($_[0]=~m"Sec-WebSocket-Key: ([^\s]*)"s){
            $ret=$1;
        }else{
            #print "no matched";
        }
        
        $ret=~s/\s//g;
        return $ret;
    }

    sub formatSHA1Hex{
        my $ret="";
        my $len=length($_[0]);
        my $i;

        for($i=0;$i<$len;$i+=2){
            $ret.=chr(oct("0x".substr($_[0],$i,2)));
        }

        return $ret;
    }

    socket(SERVER,AF_INET,SOCK_STREAM,getprotobyname('tcp'));
    bind(SERVER,$address);
    listen(SERVER,10);

    while(1){
        accept(CLIENT,SERVER);
        sysread(CLIENT,$buff,1000);
        $serverKey=encode_base64(formatSHA1Hex(sha1_hex(getClientKey($buff).$magicString)));
        print "$buff\n";

        $msg="HTTP/1.1 101 Web Socket Protocol Handshake\r\n".
                "Upgrade: websocket\r\n".
                "Connection: Upgrade\r\n".
                "Sec-WebSocket-Accept: ".$serverKey."\r\n".
                "WebSocket-Origin: $host\r\n".
                "WebSocket-Location: ws://$host:$port\r\n\r\n";

        CLIENT->autoflush(1);
        syswrite(CLIENT,$msg);
        close CLIENT;
    }
    close SERVER;
    exit 1;

    为了让代码尽量简单,省去了websockt协议验证之类的细节部分,只列出了核心功能。而且此次只实现了握手部分,而且比较简单,数据相互通信的部分看哪天又闲得蛋疼的时候再写了。。。

  • 相关阅读:
    http header Contenttype
    SharePoint 2010 文档库中直接打开文档
    玩转Google开源C++单元测试框架Google Test系列(gtest)(总)
    最近感兴趣的二三事
    最近遭遇的两个VS配置
    环游世界,走遍读过的每一个国家和城镇
    趣题一则:如何快速过桥?
    NASA庆祝地球日:50年地球最精美图片亮相(转载)
    Silverlight,Windows 8应用开发实例教程系列汇总
    Windows 8实例教程系列 数据绑定高级实例
  • 原文地址:https://www.cnblogs.com/Random/p/2194812.html
Copyright © 2011-2022 走看看