[读书笔记]WebSocket服务篇

1.1.1 WebSocket概述
WebSockets通过一次握手建立连接,服务器就可以主动地向客户端发送消息。
一举淘汰了Comet和Ajax轮询(polling),长轮询(long-polling),已经流(streaming)解决方案的。 在全双工的实时浏览器通信中,大大减少了网络流量并降低了网络延迟。


1.1.2 传统实时HTTP应用程序的复杂性
如图所示
传统的实时,体验的代价非常高,包括额外的时间延迟,不必要的网络流量和CPU性能消耗。

1.1.3 WebSocket握手
为了建立WebSocket通信,客户端和服务器在初始握手时,将HTTP协议升级到WebSocket协议

1.2 简单的WebSocket服务器
#!/usr/bin/env python
# -*- coding: utf-8 -*-

import  asyncore
import  socket
import  struct
import  time
from  hashlib  import  sha1
from  base64  import  encodestring

class  WebSocketConnection ( asyncore  . dispatcher_with_send ):

     #初始化类
     def  __init__ ( self  ,  conn ,  server ):
        asyncore  . dispacher_with_send . __init__ ( self  ,  conn )  #每一个WebSocket连接都是一个支持缓冲发送的一步套接字包装程序
       
        self  . server  =  server
        self  . server .  session . append  ( self )
        self  . readystat  =  "connecting"
        self  . buffer  =  ""

     #读取来自客户端的数据   
     def  handle_read ( self  ):
        data  =  self .  recv ( 1024  )  #接受客户端发来的数据
        self  . buffer  +=  data     #接收到的数据添加到缓冲区中
         if  self .  readystat  ==  "connecting" :
            self  . parse_connnecting ()  #如果是连接状态,则进行连接数据解析
         elif  self .  readystat  ==  "open" :
            selft  . parse_frametype ()  #如果是打开状态, 解析数据帧类型

     #关闭连接       
     def  handle_close ( self  ):
        self  . server .  sessions . remove  ( self )
        self  . close ()
       
     #解客户端的连接数据
     def  parse_connnecting ( self  ):
        header_end  =   self . buffer . find  ( "\r\n\r\n" )  #计算数据结束的位置
         if  header_end  ==  - 1  :
             return
         else :
            header  =  self .  buffer [: header_end  ]  #取开头的数据
           
            self  . buffer  =  self . buffer  [ header_end  +  4 :]  #删除开头的数据及\r\n\r\n
            header_lines  =  header . split ( "\r\n"  )
            headers  =  {}

             #HTTP请求header数据类似
             #GET /chat HTTP/1.1   (第一行数据)
             #Host: example.com
             #...
            method  ,  path ,  protocal  =  header_lines  [ 0 ].  split ( " "  )
             if  method  !=  "GET"  or  protocal  !=  "HTTP/1.1"  or  path [  0 ]  !=  "/" :
                self  . terminate ()  #格式有误,终止连接
                 return

             #解析头部信息key,value,类似Host: example.com
             for  line  in  header_lines [ 1  :]:
                key  ,  value  =  line . split  ( ": " )
                headers  [ key ]  =  value

            headers  [ "Location" ]  =  "ws://"  +  headers [ "Host"  ]  +  path

            self  . readystate  =  "open"
            self  . handler  =  self . server  . handlers . get ( path  ,  None  )( self )

             if  "Sec-WebSocket-Key1"  in  headers . keys  ():
                self  . send_server_handshake_76 ( headers )
             else :
                self  . send_server_handshake_75 ( headers )

     #终止连接       
     def  terminate ( self  ):
        self  . ready_state  =  "closed"
        self  . close ()

     #v.76版本的websocket协议返回信息  
     def  send_server_handshake_76 ( self  ,  headers ):
         """
        Send the WebSocket Protocol v.76 handshake response
        """

        key1  =  headers [ "Sec-WebSocket-Key1"  ]
        key2  =  headers [ "Sec-WebSocket-Key2"  ]
         # read additional 8 bytes from buffer
        key3  ,  self .  buffer  =  self  . buffer [:  8 ],  self  . buffer [  8 :]

         #应答的token
        response_token  =  self .  calculate_key ( key1  ,  key2 ,  key3 )

         # write out response headers
        self  . send_bytes ( "HTTP/1.1 101 Web Socket Protocol Handshake\r\n" )
        self  . send_bytes ( "Upgrade: WebSocket\r\n"  )
        self  . send_bytes ( "Connection: Upgrade\r\n"  )
        self  . send_bytes ( "Sec-WebSocket-Origin: %s\r\n"  %  headers [ "Origin" ])
        self  . send_bytes ( "Sec-WebSocket-Location: %s\r\n"  %  headers [ "Location" ])

         if  "Sec-WebSocket-Protocol"  in  headers :
            protocol  =  headers [ "Sec-WebSocket-Protocol"  ]
            self  . send_bytes ( "Sec-WebSocket-Protocol: %s\r\n"  %  protocol )

        self  . send_bytes ( "\r\n"  )
         # write out hashed response token
        self  . send_bytes ( response_token )

     #计算key
     def  calculate_key ( self  ,  key1 ,  key2 ,  key3  ):
         # parse keys 1 and 2 by extracting numerical characters
        num1  =  int (  "" . join  ([ digit  for  digit  in  list  ( key1 )  if  digit . isdigit ()]))
        spaces1  =  len ([  char  for  char  in  list (  key1 )  if  char  ==  " "  ])
        num2  =  int (  "" . join  ([ digit  for  digit  in  list  ( key2 )  if  digit . isdigit ()]))
        spaces2  =  len ([  char  for  char  in  list (  key2 )  if  char  ==  " "  ])

        combined  =  struct . pack ( ">II"  ,  num1 /  spaces1 ,  num2  / spaces2 )  +  key3
         # md5 sum the combined bytes
         return  hashlib . md5 ( combined  ). digest ()

     #v.75版本的websocket协议返回信息  
     def  send_server_handshake_75 ( self  ,  headers ):
         """
        Send the WebSocket Protocol v.75 handshake response
        """

        self  . send_bytes ( "HTTP/1.1 101 Web Socket Protocol Handshake\r\n" )
        self  . send_bytes ( "Upgrade: WebSocket\r\n"  )
        self  . send_bytes ( "Connection: Upgrade\r\n"  )
        self  . send_bytes ( "WebSocket-Origin: %s\r\n"  %  headers [ "Origin"  ])
        self  . send_bytes ( "WebSocket-Location: %s\r\n"  %  headers [ "Location" ])

         if  "Protocol"  in  headers :
            self  . send_bytes ( "WebSocket-Protocol: %s\r\n"  %  headers [ "Protocol" ])

        self  . send_bytes ( "\r\n"  )

     #解析 数据帧类型
     def  parse_frametype ( self  ):
         while  len (  self . buffer  ):
            type_byte  =  self .  buffer [ 0  ]
             if  type_byte  ==  "\x00" :
                 if  not  self . parse_textframe  ():
                     return

     #解析 文本帧
     def  parse_textframe ( self  ):
        terminator_index  =  self .  buffer . find  ( "\xFF" )
         if  terminator_index  !=  - 1  :
            frame  =  self .  buffer [ 1  : terminator_index ]
            self  . buffer  =  self . buffer  [ terminator_index + 1 :]
            s  =  frame .  decode ( "UTF8"  )
            self  . handler . dispatch ( s  )
             return  True
         else :
             # incomplete frame
             return  false

     #发送数据
     def  send ( self  ,  s ):
         if  self .  readystate  ==  "open" :  #打开状态下,才发送
            self  . send_bytes ( "\x00"  )  #发送数据头部
            self  . send_bytes ( s . encode  ( "UTF8" ))
            self  . send_bytes ( "\xFF"  )  #发送数据尾部

     def  send_bytes ( self  ,  bytes ):
        asyncore  . dispatcher_with_send . send ( self  ,  bytes )

#输出控制器
class  EchoHandler ( object  ):
     """
    The EchoHandler repeats each incoming string to the same websocket
    """
     def  __init__ ( self  ,  conn ):
        self  . conn  =  conn
       
     def  dispatch ( self  ,  data ):
         try :
            self  . conn .  send ( data  )  #发送数据
         except :
             pass

#web服务      
class  WebSocketServer ( asyncore  . dispatcher ):
     def  __init__ ( self  ,  port =  80 ,  handlers  = None ):
        asyncore  . dispatcher . __init__ ( self  )
        self  . handlers  =  handlers
        self  . sessions  =  []
        self  . port  =  port
        self  . create_socket ( socket . AF_INET  ,  socket . SOCK_STREAM )
        self  . set_reuse_addr ()
        self  . bind ((  "" ,  port  ))
        self  . listen (  5 )

     def  handle_accept ( self  ):
        conn  ,  addr  =  self . accept  ()
        session  =  WebSocketConnection ( conn ,  self  )  #处理websocket服务

#主函数
if  __name__  ==  "__main__" :
     print  "Starting WebSocket Server"
    WebSocketServer ( port  = 8080 ,  handlers ={ "/echo"  :  EchoHandler })
    asyncore . loop  ()

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值