Common communication methods based on Ajax (http) between Web clients and servers are divided into short connections and long polling .
Short connection: Every time the client and server perform an HTTP operation, a connection is established, and the connection is terminated when the task is completed.
Long polling: The client requests data from the server like traditional polling. However, if the server does not have data that can be returned to the client immediately, it will not return an empty result immediately, but will keep the request waiting for the data to arrive (or an appropriate timeout: less than the ajax timeout), and then return the data as a result. client.
The long polling mechanism is shown in the figure below:
2. Basic concepts of WebsocketWebSocket is a protocol for full-duplex communication on a single TCP connection that HTML5 began to provide.
WebSocket makes data exchange between the client and the server simpler, allowing the server to actively push data to the client. In the WebSocket API, the browser and the server only need to complete a handshake, and a persistent connection can be created directly between the two for bidirectional data transmission.
In the WebSocket API, the browser and the server only need to perform a handshake action, and then a fast channel is formed between the browser and the server. Data can be transmitted directly between the two.
Nowadays, in order to implement push technology, many websites use Ajax polling. Polling is when the browser issues an HTTP request to the server at a specific time interval (such as every 1 second), and then the server returns the latest data to the client's browser. This traditional model brings obvious shortcomings, that is, the browser needs to continuously send requests to the server. However, the HTTP request may contain a long header, in which the real valid data may only be a small part, which is obviously a waste. A lot of bandwidth and other resources.
The WebSocket protocol defined by HTML5 can better save server resources and bandwidth, and enable more real-time communication.
The browser sends a request to the server to establish a WebSocket connection through JavaScript. After the connection is established, the client and the server can directly exchange data through the TCP connection.
After you obtain the Web Socket connection, you can send data to the server through the send() method, and receive data returned by the server through the onmessage event.
3. Websocket handshake principle:The handshake principle of Websocket can be roughly divided into the following steps:
Code implementation:
import socket, base64, hashlib# Create a socket connection sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)# Bind the end address and port number sock.bind(('127.0.0.1', 9527))# Listen to sock.listen (5)# Get the client socket object conn, address = sock.accept()# Get the client's [handshake] information data = conn.recv(1024)print(data)def get_headers(data): Remove the value corresponding to Sec-WebSocket-Key from the request header and return header_dict = {} header_str = data.decode( utf8) for i in header_str.split(/r/n): if str(i).startswith(Sec-WebSocket-Key): return i.split(:)[1].strip()# Get the value corresponding to Sec-WebSocket-Key ws_key = get_headers(data)# The magic string magic string is: 258EAFA5-E914-47DA-95CA-C5AB0DC85B11magic_string = '258EAFA5- E914-47DA-95CA-C5AB0DC85B11'# Splicing socket_str = ws_key + magic_string# sha1 encryption socket_str_sha1 = hashlib.sha1(socket_str.encode(utf8)).digest()# base64 encryption socket_str_base64 = base64.b64encode(socket_str_sha1)# Splicing response header response_tpl = HTTP/1.1 101 Switching Protocols/r/n / Upgrade:websocket/r/n / Connection: Upgrade/r/n / Sec-WebSocket-Accept: %s/r/n / WebSocket-Location: ws://127.0.0.1:9527/r /n/r/n % (socket_str_base64.decode(utf8))# The server sends the response header to the client conn.send(response_tpl.encode(utf8))# The client and server establish a long connection to receive and send data in a loop while True: msg = conn.recv(8096) print(msg)
<!DOCTYPE html><html lang=en><head> <meta charset=UTF-8> <title>Title</title></head><body></body><script type=text/javascript> ws = new WebSocket(ws://127.0.0.1:9527); ws.onmessage = function (ev) { console.log(ev)//for receiving data}</script></html>
Attached is the request header for the HTTP request initiated by the client:
b'GET /ws/ HTTP/1.1Host: 127.0.0.1:9527Connection: UpgradePragma: no-cacheCache-Control: no-cacheUser-Agent: Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.3...Upgrade: websocketOrigin : http://localhost:63342Sec-WebSocket-Version: 13Accept-Encoding: gzip, deflate, brAccept-Language: zh-CN,zh;q=0.9Sec-WebSocket-Key: kJXuOKsrl3AR1KeFngRElQ==Sec-WebSocket-Extensions: permessage- deflate; client_max_window_bits'4. Websocket encryption and decryption methods:
Decryption method:
# b'/x81/x87/x0e/xc3/xf3/xcd;/xf6/xc6/xf8;/xf6/xc6'==========5555555hashstr = b'/x81/x87/x0e/xc3 /xf3/xcd;/xf6/xc6/xf8;/xf6/xc6'# Perform a bit operation on the second byte, which is /x87 bits 9-16, and 127 payload = hashstr[1] & 127# When the bit operation result is equal to 127, the 3-10 bytes are the data length# Bytes 11-14 are the string required for mask decryption #The data is from the 15th byte to the end if payload == 127: extend_payload_len = hashstr[2:10] mask = hashstr[10:14] decoded = hashstr[14:]# When the bit operation result is equal to 126, then the 3-4 bytes are the data length # The 5-8 bytes are the string required for mask decryption # Then the data From the 9th byte to the end if payload == 126: extend_payload_len = hashstr[2:4] mask = hashstr[4:8] decoded = hashstr[8:]# When the bit operation result is less than or equal to 125, then this number is the length of the data # The 3-6 bytes are the string required for mask decryption # The data is from the 7th byte to the end if payload <= 125: extend_payload_len = None mask = hashstr[2:6] decoded = hashstr[6:]str_byte = bytearray()for i in range(len(decoded)): byte = decoded[i] ^ mask[i % 4] str_byte.append(byte)print(str_byte.decode(utf8))
Encryption method:
import structmsg_bytes = 5555555.encode(utf8)token = b/x81length = len(msg_bytes)if length < 126: token += struct.pack(B, length)elif length == 126: token += struct.pack(!BH , 126, length)else: token += struct.pack(!BQ, 127, length)msg = token + msg_bytesprint(msg)4. Examples of client and server link communication based on the flask framework and Websocket protocol:
pip3 install gevent-websocket
from flask import Flask, requestfrom geventwebsocket.websocket import WebSocketfrom gevent.pywsgi import WSGIServerfrom geventwebsocket.handler import WebSocketHandlerapp = Flask(__name__)@app.route(/ws)def websocket(): # Get the user's link user_socket = request.environ. get(wsgi.websocket) # type:WebSocket print (access successful) while True: msg = user_socket.receive() #Receive message print(msg) user_socket.send(msg) #Send message if __name__ == '__main__': # Specify the address and port number to open Websocket Service http_serv = WSGIServer((127.0.0.1, 8001), app, handler_class=WebSocketHandler) # Start the Websocket service http_serv.serve_forever()
html file:
<!DOCTYPE html><html lang=en><head> <meta charset=UTF-8> <title>Title</title> <link href=https://cdnjs.cloudflare.com/ajax/libs/twitter- bootstrap/3.3.7/css/bootstrap.css rel=stylesheet></head><body><botton class=btn btn-default onclick=createsocket()>Click to create a link</botton><br><p>Please enter a message: <input type=text placeholder=Input message id=msg></p><buttom class=btn btn-success onclick =send_msg()>Send message</buttom><script> var ws = null; function createsocket() { ws = new WebSocket(ws://127.0.0.1:8001/ws); ws.onmessage = function (data) { console.log(message received from the server=,data.data); } } function send_msg() { var to_msg = document.getElementById(msg).value; ws.send(to_msg) }</script></body></html>
client.png
Server side.png
In this way, we simply implement client-server communication through the Websocket protocol. And we can create multiple links to communicate with the server side at the same time.
5. Implement instant messaging (IM) based on Websocket:Server code:
from flask import Flask, requestfrom geventwebsocket.websocket import WebSocketfrom gevent.pywsgi import WSGIServerfrom geventwebsocket.handler import WebSocketHandlerfrom geventwebsocket.exceptions import WebSocketErrorimport jsonapp = Flask(__name__)user_socket_dict = {}@app.route(/ws/<username>)def websocket(username): # Get the user's link user_socket = request.environ.get(wsgi.websocket) # type:WebSocket user_socket_dict[username] = user_socket print(username+link successful!) while True: msg = user_socket.receive() # Accept messages for socket in user_socket_dict.values(): # type:WebSocket if user_socket != socket:# If you send a message yourself, the server will not reply to you. try: socket.send(json.dumps({sender: username, msg: msg})) except: continueif __name__ == '__main__': # Specify the address and port number to open the Websocket service http_serv = WSGIServer((127.0.0.1, 8001), app, handler_class=WebSocketHandler) # Start the Websocket service http_serv.serve_forever()
html code:
<!DOCTYPE html><html lang=en><head> <meta charset=UTF-8> <title>Title</title> <link href=https://cdnjs.cloudflare.com/ajax/libs/twitter- bootstrap/3.3.7/css/bootstrap.css rel=stylesheet></head><body><p>Please enter your nickname:<input type=text id=username></p><botton class=btn btn-default onclick=createsocket()>Click to create the link</botton><br><p>Please enter the message: <input type=text id=msg>< /p><buttom class=btn btn-success onclick=send_msg()>Send message</buttom><br><br><br><div style=border: 2px solid; width: 500px; height: 800px; id=text_div></div><script> var ws = null; var username = null; function createsocket() { username = document.getElementById(username).value; ws = new WebSocket(ws://127.0.0.1:8001/ws + / + username); ws.onmessage = function (data) { var text_div = document.getElementById(text_div); var obj_data = JSON.parse(data.data); var add_msg = <p> + obj_data.sender + : + obj_data.msg + </p>; text_div. innerHTML += add_msg; } } function send_msg() { var to_msg = document.getElementById(msg).value; var text_div = document.getElementById(text_div); var add_msg = <p style='text-align: right'> + to_msg + : + username + </p>; text_div.innerHTML + = add_msg; ws.send(to_msg); }</script></body></html>
Client01.png
Client02.png
Server side.png
The code is a demonstration code, with bugs and bugs. It is mainly used for learning at the moment, so no nitpicking is allowed. Those who are interested can further optimize! ! !
The above is the entire content of this article. I hope it will be helpful to everyone’s study. I also hope everyone will support VeVb Wulin Network.