当前位置:   article > 正文

【python socket】实现websocket服务端_python websocket 服务端

python websocket 服务端

一、获取握手信息

首先通过如下代码,我们使用socket来获取客户端的握手信息

  1. import socket
  2. sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
  3. sock.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
  4. sock.bind(("127.0.0.1", 8002))
  5. sock.listen(5)
  6. conn, address = sock.accept() # 获取客户端的socket对象和地址
  7. msg = conn.recv(1024) # 获取客户端的握手信息
  8. print(msg)

我们可以通过http://www.websocket-test.com/来作为websocket客户端

当连接上服务端时,服务端打印如下信息

二、格式化websocket请求头

将上述打印信息转为JSON格式:

  1. def get_headers(data):
  2. """
  3. 将请求头格式化成字典
  4. :param data:
  5. :return:
  6. """
  7. header_dict = {}
  8. data = str(data, encoding='utf-8')
  9. # for i in data.split('\r\n'):
  10. # print(i)
  11. header, body = data.split('\r\n\r\n', 1)
  12. header_list = header.split('\r\n')
  13. for i in range(0, len(header_list)):
  14. if i == 0:
  15. if len(header_list[i].split(' ')) == 3:
  16. header_dict['method'], header_dict['url'], header_dict['protocol'] = header_list[i].split(' ')
  17. else:
  18. k, v = header_list[i].split(':', 1)
  19. header_dict[k] = v.strip()
  20. return header_dict

调用上述方法可以将服务端收到的握手信息转为Json格式:

三、提取key并加密

  1. key = headers_dict["Sec-WebSocket-Key"] # 提取key
  2. # 对key进行加密
  3. magic_string = '258EAFA5-E914-47DA-95CA-C5AB0DC85B11'
  4. value = key + magic_string
  5. ac = base64.b64encode(hashlib.sha1(value.encode('utf-8')).digest())
  6. # print(ac)

四、将加密的结果返回客户端

  1. # 将加密的结果返回客户端
  2. response_tpl = "HTTP/1.1 101 Switching Protocols\r\n" \
  3. "Upgrade:websocket\r\n" \
  4. "Connection: Upgrade\r\n" \
  5. "Sec-WebSocket-Accept: %s\r\n" \
  6. "WebSocket-Location: ws://%s%s\r\n\r\n"
  7. response_str = response_tpl % (ac.decode('utf-8'), headers_dict['Host'], headers_dict['url'])
  8. conn.send(response_str.encode("utf-8"))

五、和客户端建立连接后的操作

这里建立连接后,将客户端发送的信息再返回给客户端

  1. while True:
  2. try:
  3. info = conn.recv(8096)
  4. except Exception as e:
  5. info = None
  6. if not info:
  7. break
  8. payload_len = info[1] & 127
  9. if payload_len == 126:
  10. extend_payload_len = info[2:4]
  11. mask = info[4:8]
  12. decoded = info[8:]
  13. elif payload_len == 127:
  14. extend_payload_len = info[2:10]
  15. mask = info[10:14]
  16. decoded = info[14:]
  17. else:
  18. extend_payload_len = None
  19. mask = info[2:6]
  20. decoded = info[6:]
  21. bytes_list = bytearray()
  22. for i in range(len(decoded)):
  23. chunk = decoded[i] ^ mask[i % 4]
  24. bytes_list.append(chunk)
  25. body = str(bytes_list, encoding='utf-8')
  26. send_msg(conn, body.encode('utf-8'))

服务端完整代码

实现了服务端接收与发送的分离;

当服务端接收到指定字符串时("exit"),服务端主动断开连接。

  1. import socket,base64,hashlib,time,threading
  2. def get_headers(data):
  3. """
  4. 将请求头格式化成字典
  5. :param data:
  6. :return:
  7. """
  8. header_dict = {}
  9. data = str(data, encoding='utf-8')
  10. # for i in data.split('\r\n'):
  11. # print(i)
  12. header, body = data.split('\r\n\r\n', 1)
  13. header_list = header.split('\r\n')
  14. for i in range(0, len(header_list)):
  15. if i == 0:
  16. if len(header_list[i].split(' ')) == 3:
  17. header_dict['method'], header_dict['url'], header_dict['protocol'] = header_list[i].split(' ')
  18. else:
  19. k, v = header_list[i].split(':', 1)
  20. header_dict[k] = v.strip()
  21. return header_dict
  22. def send_msg(conn, msg_bytes):
  23. """
  24. WebSocket服务端向客户端发送消息
  25. :param conn: 客户端连接到服务器端的socket对象,即: conn,address = socket.accept()
  26. :param msg_bytes: 向客户端发送的字节
  27. :return:
  28. """
  29. import struct
  30. token = b"\x81"
  31. length = len(msg_bytes)
  32. if length < 126:
  33. token += struct.pack("B", length)
  34. elif length <= 0xFFFF:
  35. token += struct.pack("!BH", 126, length)
  36. else:
  37. token += struct.pack("!BQ", 127, length)
  38. msg = token + msg_bytes
  39. conn.send(msg)
  40. return True
  41. def recv_msg(conn):
  42. while True:
  43. try:
  44. info = conn.recv(8096)
  45. except Exception as e:
  46. info = None
  47. if not info:
  48. break
  49. payload_len = info[1] & 127
  50. if payload_len == 126:
  51. extend_payload_len = info[2:4]
  52. mask = info[4:8]
  53. decoded = info[8:]
  54. elif payload_len == 127:
  55. extend_payload_len = info[2:10]
  56. mask = info[10:14]
  57. decoded = info[14:]
  58. else:
  59. extend_payload_len = None
  60. mask = info[2:6]
  61. decoded = info[6:]
  62. bytes_list = bytearray()
  63. for i in range(len(decoded)):
  64. chunk = decoded[i] ^ mask[i % 4]
  65. bytes_list.append(chunk)
  66. global body
  67. body = str(bytes_list, encoding='utf-8')
  68. print(body)
  69. if body == "exit":
  70. conn.close()
  71. break
  72. sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
  73. sock.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
  74. sock.bind(("127.0.0.1", 8002))
  75. sock.listen(5)
  76. conn, address = sock.accept() # 获取客户端的socket对象和地址
  77. data = conn.recv(1024) # 获取客户端的握手信息
  78. headers_dict = get_headers(data)
  79. key = headers_dict["Sec-WebSocket-Key"] # 提取key
  80. # 对key进行加密
  81. magic_string = '258EAFA5-E914-47DA-95CA-C5AB0DC85B11'
  82. value = key + magic_string
  83. ac = base64.b64encode(hashlib.sha1(value.encode('utf-8')).digest())
  84. # print(ac)
  85. # 将加密的结果返回客户端
  86. response_tpl = "HTTP/1.1 101 Switching Protocols\r\n" \
  87. "Upgrade:websocket\r\n" \
  88. "Connection: Upgrade\r\n" \
  89. "Sec-WebSocket-Accept: %s\r\n" \
  90. "WebSocket-Location: ws://%s%s\r\n\r\n"
  91. response_str = response_tpl % (ac.decode('utf-8'), headers_dict['Host'], headers_dict['url'])
  92. conn.send(response_str.encode("utf-8"))
  93. # 和客户端建立连接后的操作
  94. # 启动接收客户端信息的线程
  95. thread_obj = threading.Thread(target=recv_msg, args=(conn,))
  96. thread_obj.daemon = True
  97. thread_obj.start()
  98. # 不断给客户端发送信息
  99. while True:
  100. if getattr(conn, "_closed") == False: # 客户端没有关闭
  101. send_msg(conn, str("你好").encode('utf-8'))
  102. time.sleep(1)
  103. else: # 客户端关闭
  104. break

参考视频链接:https://www.bilibili.com/video/BV1tf4y1K7Ww?p=8&spm_id_from=pageDriver&vd_source=36a3e35639c44bb339f59760641390a8

参考文章:https://www.cnblogs.com/wupeiqi/p/6558766.html

声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/盐析白兔/article/detail/85406
推荐阅读
相关标签
  

闽ICP备14008679号