美文网首页
Python | WebSocketServer

Python | WebSocketServer

作者: T_K_233 | 来源:发表于2018-12-22 17:19 被阅读0次
    '''
    Host a multiplayer sever via WebSocket protocol
    https://developer.mozilla.org/en-US/docs/Web/API/WebSockets_API/Writing_WebSocket_servers
    '''
    
    import base64
    import hashlib
    import socket
    from struct import pack, unpack
    import threading
    import json
    
    
    class WebSocketConn:
        def __init__(self, conn):
            self.conn = conn
            request = self.conn.recv(1024).strip().decode('utf-8', 'ignore').split('\r\n')
    
            # parse headers into dict
            self.headers = dict([line.split(': ', 1) for line in request[1:]])
    
            # perform WebSocket handshake
            self._handshake()
    
        def _handshake(self):
            key = self.headers.get('Sec-WebSocket-Key') + '258EAFA5-E914-47DA-95CA-C5AB0DC85B11'
            resp_key = base64.standard_b64encode(hashlib.sha1(key.encode()).digest()).decode()
            res_header = {
                'Upgrade': 'websocket',
                'Connection': 'Upgrade',
                'Sec-WebSocket-Accept': resp_key,
                }
            response = 'HTTP/1.1 101 Switching Protocols\r\n'
            for i in res_header:
                response += '%s: %s\r\n' % (i, res_header[i]) 
            response += '\r\n'
            self.conn.send(response.encode())
    
        def recv(self):
            '''
            retrieve data from the client.
            '''
            buffer = self.conn.recv(2)
            if buffer:
                # read the three possible content-length number
                length = buffer[1] - 2**7
                if length == 126:
                    length, = unpack('>H', self.conn.recv(2))
                elif length == 127:
                    length, = unpack('>Q', self.conn.recv(8))
    
                # get the masking key for the content
                mask = self.conn.recv(4)
    
                # encoded content
                buffer = self.conn.recv(length)
    
                decoded = ''
                for i in range(length):
                    # decode the content
                    decoded += chr(buffer[i] ^ mask[i % 4])
                return decoded
    
        def send(self, data):
            '''
            send content in form of WebSocket data frame.
            '''
            buffer = b''
            # initial 4 bits
            buffer += pack('>B', 129)
    
            # length of the content
            if len(data) > 126:
                if len(data) < 2 ** 10:
                    buffer += pack('>BH', 126, len(data))
                else:
                    buffer += pack('>BQ', 127, len(data))
            else:
                buffer += pack('>B', len(data))
    
            # append content
            buffer += data.encode()
            
            self.conn.send(buffer)
    
        def close(self):
            '''
            close the connection.
            '''
            self.conn.close()
    
    class WebSocket:
        def __init__(self, addr):
            '''
            a WebSocket socket.
            @param addr: the address to bind with, i.e. (host, port)
            '''
            self.sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM, 0)
            self.sock.bind(addr)
            
        def listen(self, num):
            '''
            maximum clients to listen to.
            '''
            self.sock.listen(num)
            
        def accept(self):
            '''
            accept the connection from a client.
            '''
            conn, self.addr = self.sock.accept()
            self.conn = WebSocketConn(conn)
            return self.conn, self.addr
    
    
    class WebSocketServer:
        def __init__(self, sock):
            '''
            a WebSocket server class with multithreading.
            '''
            self.sock = sock
            self.player_pool = []
    
        def run(self):
            '''
            run server.
            '''
            # lock for controlling the player pool
            lock = threading.Lock()
            while True:
                conn, addr = self.sock.accept()
                threading.Thread(target=self.handle, args=(conn, addr, lock)).start()
    
        def handle(self, conn, addr, lock):
            while True:
                try:
                    buffer = conn.recv()
                    if buffer:
                        try:
                            req = json.loads(buffer.strip())
                        except Exception as e:
                            print(e)
                        if req.get('init'):
                            conn.send(json.dumps({'init': 1, 'id': len(self.player_pool)}))
                        else:
                            if req.get('id') >= len(self.player_pool):
    
                                lock.acquire()
                                self.player_pool.append(req)
                                lock.release()
                            else:
                                self.player_pool[req.get('id')] = req
                            conn.send(json.dumps(self.player_pool))
                        
                except Exception as e:
                    conn.close()
                    return 0
    
    
    if name == '__main__':
        sock = WebSocket(('0.0.0.0', 10002))
        sock.listen(10)
        server = WebSocketServer(sock)
        server.run()
    
    
    <!DOCTYPE html>
    <html>
    <head>
      <meta name="viewport" content="width=device-width, initial-scale=1.0">
      <meta name="author" content="-T.K.-">
      <meta name="copyright" content="-T.K.-">
      <title>Untitled Page</title>
      <script src="https://cdn.bootcss.com/jquery/3.3.1/jquery.min.js"></script>
    </head>
    <body>
    <canvas id="myCanvas" width="800" height="600" style="border:1px solid #000000;"></canvas>
    <script>
      var Vec3 = function(x, y, z) {
        this.x = x;
        this.y = y;
        this.z = z;
      };
    
      var Player = function(id) {
        this.id = id;
        this.pos = new Vec3(0, 0, 0);
        
        this.get_data = function() {
          return JSON.stringify({id: this.id, pos: this.pos});
        }
      };
    </script>
    <script>
      var ws;
      $(document).ready(function() {
        if('WebSocket' in window) console.log('broswer support');
        
        ws = new WebSocket('ws://192.168.1.8:10002');
        ws.onopen = function() {
          console.log('socket connection established');
          ws.send(JSON.stringify({init: 1}));
          setInterval(function(){
            ws.send(player.get_data());
          }, 50);
        };
        ws.onmessage = function(res) {
          data = JSON.parse(res.data);
          console.log(data);
          if(data.init) {
            player = new Player(data.id);
          } else {
            ctx.clearRect(0, 0, c.width, c.height);
            for(p in data) {
              ctx.fillRect(data[p].pos.x, data[p].pos.y, 64, 64);
            }
          }
        };
        ws.onclose = function() {
          console.log('sock closed');
        };
      });
    </script>
    <script>
      var player;
      var status = 4;
    
      var c = document.getElementById('myCanvas');
      var ctx = c.getContext('2d');
      ctx.fillStyle = '#FF0000';
    
      $(document).keydown(function(e) {
        switch(e.keyCode) {
          case 37:
            player.pos.x -= 10;
            break;
          case 39:
            player.pos.x += 10;
            break;
          case 38:
            player.pos.y -= 10;
            break;
          case 40:
            player.pos.y += 10;
            break;
        }
      });
    </script>
    

    相关文章

      网友评论

          本文标题:Python | WebSocketServer

          本文链接:https://www.haomeiwen.com/subject/alxwkqtx.html