Metode komunikasi umum berdasarkan Ajax (http) antara klien Web dan server dibagi menjadi koneksi pendek dan polling panjang .
Koneksi pendek: Setiap kali klien dan server melakukan operasi HTTP, koneksi dibuat, dan koneksi diakhiri ketika tugas selesai.
Polling panjang: Klien meminta data dari server seperti polling tradisional. Namun, jika server tidak memiliki data yang dapat segera dikembalikan ke klien, server tidak akan langsung mengembalikan hasil kosong, namun akan membiarkan permintaan menunggu data tiba (atau batas waktu yang sesuai: kurang dari batas waktu ajax) , dan kemudian mengembalikan data sebagai hasilnya.
Mekanisme long polling ditunjukkan pada gambar di bawah ini:
2. Konsep dasar WebsocketWebSocket adalah protokol untuk komunikasi dupleks penuh pada satu koneksi TCP yang mulai disediakan oleh HTML5.
WebSocket membuat pertukaran data antara klien dan server menjadi lebih sederhana, memungkinkan server untuk secara aktif mengirimkan data ke klien. Di WebSocket API, browser dan server hanya perlu menyelesaikan jabat tangan, dan koneksi persisten dapat dibuat langsung antara keduanya untuk transmisi data dua arah.
Pada WebSocket API, browser dan server hanya perlu melakukan tindakan jabat tangan, kemudian saluran cepat terbentuk antara browser dan server. Data dapat ditransmisikan secara langsung antara keduanya.
Saat ini, untuk mengimplementasikan teknologi push, banyak website yang menggunakan polling Ajax. Polling adalah ketika browser mengeluarkan permintaan HTTP ke server pada interval waktu tertentu (misalnya setiap 1 detik), dan kemudian server mengembalikan data terbaru ke browser klien. Model tradisional ini memiliki kekurangan yang jelas, yaitu browser harus terus mengirimkan permintaan ke server. Namun, permintaan HTTP mungkin berisi header yang panjang, di mana data valid yang sebenarnya mungkin hanya sebagian kecil, yang jelas merupakan pemborosan. .Banyak bandwidth dan sumber daya lainnya.
Protokol WebSocket yang ditentukan oleh HTML5 dapat menghemat sumber daya dan bandwidth server dengan lebih baik, serta memungkinkan komunikasi yang lebih real-time.
Browser mengirimkan permintaan ke server untuk membuat koneksi WebSocket melalui JavaScript. Setelah koneksi dibuat, klien dan server dapat langsung bertukar data melalui koneksi TCP.
Setelah Anda mendapatkan koneksi Web Socket, Anda dapat mengirim data ke server melalui metode send(), dan menerima data yang dikembalikan oleh server melalui acara onmessage.
3. Prinsip jabat tangan websocket:Prinsip jabat tangan Websocket secara kasar dapat dibagi menjadi beberapa langkah berikut:
Implementasi kode:
import socket, base64, hashlib# Buat koneksi soket sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)# Ikat alamat akhir dan nomor port sock.bind(('127.0.0.1', 9527))# Dengarkan sock.listen (5)# Dapatkan koneksi objek soket klien, alamat = sock.accept()# Dapatkan informasi [jabat tangan] klien data = conn.recv(1024)print(data)def get_headers(data): Hapus nilai yang sesuai dengan Sec-WebSocket-Key dari header permintaan dan kembalikan header_dict = {} header_str = data.decode ( utf8) untuk saya di header_str.split(/r/n): if str(i).startswith(Sec-WebSocket-Key): kembali i.split(:)[1].strip()# Dapatkan nilai yang sesuai dengan Sec-WebSocket-Key ws_key = get_headers(data)# String ajaib string ajaib adalah: 258EAFA5-E914-47DA-95CA-C5AB0DC85B11magic_string = '258EAFA5 - E914-47DA-95CA-C5AB0DC85B11'# Penyambungan socket_str = ws_key + magic_string# enkripsi sha1 socket_str_sha1 = hashlib.sha1(socket_str.encode(utf8)).digest()# enkripsi base64 socket_str_base64 = base64.b64encode(socket_str_sha1)# Penyambungan header respons respond_tpl = HTTP/1.1 101 Peralihan Protokol/r/n / Peningkatan:websocket/r/n / Koneksi: Peningkatan/r/n / Detik-WebSocket-Terima: %s/r/n / WebSocket-Lokasi: ws://127.0.0.1:9527/r /n/r/n % (socket_str_base64.decode(utf8))# Server mengirimkan header respons ke klien conn.send(response_tpl.encode(utf8))# Klien dan server membuat koneksi yang panjang untuk menerima dan mengirim data dalam satu lingkaran sementara True: msg = conn.recv(8096) print( pesan)
<!DOCTYPE html><html lang=en><head> <meta charset=UTF-8> <title>Judul</title></head><body></body><script type=text/javascript> ws = WebSocket baru(ws://127.0.0.1:9527); ws.onmessage = function (ev) { console.log(ev)//untuk menerima data}</script></html>
Terlampir adalah header permintaan untuk permintaan HTTP yang diinisiasi oleh klien:
b'GET /ws/ HTTP/1.1Host: 127.0.0.1:9527Koneksi: PeningkatanPragma: tanpa cacheKontrol Cache: tanpa cacheAgen Pengguna: Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.3...Peningkatan: websocketOrigin : http://localhost:63342Sec-WebSocket-Versi: 13Accept-Encoding: gzip, deflate, brAccept-Bahasa: zh-CN,zh;q=0.9Sec-WebSocket-Key: kJXuOKsrl3AR1KeFngRElQ==Sec-WebSocket-Extensions: permessage- mengempis; klien_max_window_bits'4. Metode enkripsi dan dekripsi Websocket:
Metode dekripsi:
# 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'# Lakukan operasi bit pada byte kedua, yaitu /x87 bit 9-16, dan 127 payload = hashstr[1] & 127# Bila hasil operasi bit sama dengan 127, maka 3-10 byte tersebut adalah panjang data# Byte 11-14 adalah string yang diperlukan untuk dekripsi mask #Data dari byte ke-15 hingga akhir jika payload == 127: extend_payload_len = hashstr[2:10] mask = hashstr[10:14] decode = hashstr[14:]# Bila hasil operasi bit sama dengan 126, maka 3-4 byte adalah panjang data # 5-8 byte adalah string yang diperlukan untuk dekripsi mask # Kemudian data Dari byte ke-9 sampai akhir if payload == 126: extend_payload_len = hashstr[2:4] mask = hashstr[4:8] decode = hashstr[8:]# Bila hasil operasi bit kurang dari atau sama dengan 125, maka angka ini adalah panjang data # 3-6 byte adalah string yang diperlukan untuk dekripsi mask # Data dari byte ke-7 sampai akhir jika payload <= 125: extend_payload_len = Tidak ada mask = hashstr[2:6] didekodekan = hashstr[6:]str_byte = bytearray()untuk i dalam rentang(len(didekodekan)): byte = didekodekan[i] ^ mask[i % 4] str_byte.append(byte)print(str_byte.decode(utf8))
Metode enkripsi:
import structmsg_bytes = 5555555.encode(utf8)token = b/x81length = len(msg_bytes)jika panjang < 126: token += struct.pack(B, length)elif length == 126: token += struct.pack(!BH , 126, panjang)lainnya: token += struct.pack(!BQ, 127, panjang)msg = token + pesan_bytesprint(pesan)4. Contoh komunikasi link klien dan server berdasarkan framework flask dan protokol Websocket:
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(): # Dapatkan tautan pengguna user_socket = request.environ. dapatkan(wsgi.websocket) # ketik:WebSocket print (akses berhasil) sementara True: msg = user_socket.receive() #Terima pesan print(msg) user_socket.send(msg) #Kirim pesan if __name__ == '__main__': # Tentukan alamat dan nomor port yang akan dituju buka Layanan Websocket http_serv = WSGIServer((127.0.0.1, 8001), aplikasi, handler_class=WebSocketHandler) # Mulai layanan Websocket http_serv.serve_forever()
berkas html:
<!DOCTYPE html><html lang=en><head> <meta charset=UTF-8> <title>Judul</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()>Klik untuk membuat tautan</botton><br><p>Silakan masukkan pesan: <input type=text placeholder=Input message id=msg></p><buttom class=btn btn- sukses onclick =kirim_msg()>Kirim pesan</buttom><script> var ws = null; function createocket() { ws = baru WebSocket(ws://127.0.0.1:8001/ws); ws.onmessage = fungsi (data) { console.log(pesan diterima dari server=,data.data); dokumen.getElementById(msg).value; ws.send(to_msg) }</script></body></html>
klien.png
Sisi server.png
Dengan cara ini, kami cukup mengimplementasikan komunikasi client-server melalui protokol Websocket. Dan kita dapat membuat banyak tautan untuk berkomunikasi dengan sisi server secara bersamaan.
5. Menerapkan pesan instan (IM) berdasarkan Websocket:Kode server:
dari labu impor Labu, permintaandari geventwebsocket.websocket impor WebSocketdari gevent.pywsgi impor WSGIServerdari geventwebsocket.handler impor WebSocketHandlerdari geventwebsocket.pengecualian impor WebSocketErrorimport jsonapp = Flask(__name__)user_socket_dict = {}@app.route(/ws/<nama pengguna>)def websocket(nama pengguna): # Dapatkan link pengguna user_socket = request.environ.get(wsgi.websocket) # type:WebSocket user_socket_dict[username] = user_socket print(nama pengguna+link berhasil!) while True: msg = user_socket.receive() # Terima pesan untuk soket di user_socket_dict.values(): # type:WebSocket if user_socket != socket:# Jika Anda mengirim pesan sendiri, server tidak akan membalas Anda. coba: socket.send(json.dumps({sender: username, msg: msg})) kecuali: continueif __name__ == '__main__ ': # Tentukan alamat dan nomor port untuk membuka layanan Websocket http_serv = WSGIServer((127.0.0.1, 8001), app, handler_class=WebSocketHandler) # Mulai layanan Websocket http_serv.serve_forever()
kode html:
<!DOCTYPE html><html lang=en><head> <meta charset=UTF-8> <title>Judul</title> <link href=https://cdnjs.cloudflare.com/ajax/libs/twitter- bootstrap/3.3.7/css/bootstrap.css rel=stylesheet></head><body><p>Silakan masukkan nama panggilan Anda:<input type=text id=username></p><botton class=btn btn-default onclick=createsocket()>Klik untuk membuat tautan</botton><br><p>Silakan masukkan pesan: <input type=text id=msg >< /p><buttom class=btn btn-success onclick=send_msg()>Kirim pesan</buttom><br><br><br><div style=border: 2px solid; lebar: 500px; tinggi: 800px; id=text_div></div><script> var ws = null; var nama pengguna = null; WebSocket(ws://127.0.0.1:8001/ws + / + nama pengguna); (data) { var text_div = dokumen.getElementById(text_div); var obj_data = JSON.parse(data.data); var add_msg = <p> + obj_data.sender + : + obj_data.msg + </p>; innerHTML += add_msg; } } fungsi kirim_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 + : + nama pengguna + </p>; = tambahkan_pesan; ws.kirim(ke_pesan);
Klien01.png
Klien02.png
Sisi server.png
Kode ini adalah kode demonstrasi, dengan bug dan bug. Ini terutama digunakan untuk pembelajaran saat ini, jadi tidak diperbolehkan melakukan nitpicking. Bagi yang berminat bisa lebih mengoptimalkannya! ! !
Di atas adalah keseluruhan isi artikel ini, saya harap dapat bermanfaat untuk pembelajaran semua orang. Saya juga berharap semua orang mendukung VeVb Wulin Network.