Распространенные методы связи на основе Ajax (http) между веб-клиентами и серверами делятся на короткие соединения и длинный опрос .
Короткое соединение: каждый раз, когда клиент и сервер выполняют операцию HTTP, соединение устанавливается и разрывается после завершения задачи.
Длинный опрос: клиент запрашивает данные с сервера, как при традиционном опросе. Однако, если у сервера нет данных, которые могут быть немедленно возвращены клиенту, он не будет немедленно возвращать пустой результат, а будет держать запрос в ожидании прибытия данных (или соответствующего тайм-аута: меньшего, чем тайм-аут ajax). , а затем вернуть данные в результате client.
Механизм длинного опроса показан на рисунке ниже:
2. Основные понятия WebsocketWebSocket — это протокол полнодуплексной связи по одному TCP-соединению, который начал обеспечивать HTML5.
WebSocket упрощает обмен данными между клиентом и сервером, позволяя серверу активно передавать данные клиенту. В API WebSocket браузеру и серверу нужно только завершить рукопожатие, и между ними может быть создано постоянное соединение для двунаправленной передачи данных.
В API WebSocket браузеру и серверу достаточно выполнить действие рукопожатия, после чего между браузером и сервером формируется быстрый канал. Данные могут передаваться напрямую между ними.
Сегодня для реализации технологии push многие сайты используют опрос Ajax. Опрос — это когда браузер отправляет HTTP-запрос серверу через определенный интервал времени (например, каждую 1 секунду), а затем сервер возвращает последние данные браузеру клиента. Эта традиционная модель имеет очевидные недостатки: браузеру необходимо постоянно отправлять запросы на сервер. Однако HTTP-запрос может содержать длинный заголовок, в котором реальные действительные данные могут составлять лишь небольшую часть, что, очевидно, является пустой тратой. . Много пропускной способности и других ресурсов.
Протокол WebSocket, определенный HTML5, может лучше экономить ресурсы сервера и пропускную способность, а также обеспечивать более эффективное взаимодействие в реальном времени.
Браузер отправляет серверу запрос на установление соединения WebSocket через JavaScript. После того, как соединение установлено, клиент и сервер могут напрямую обмениваться данными через TCP-соединение.
После получения соединения через веб-сокет вы можете отправлять данные на сервер с помощью метода send() и получать данные, возвращаемые сервером, с помощью события onmessage.
3. Принцип установления связи через веб-сокет:Принцип рукопожатия Websocket можно условно разделить на следующие этапы:
Реализация кода:
import Socket, base64, hashlib# Создать соединение через сокет sock.listen (5)# Получить объект клиентского сокета conn, адрес = sock.accept()# Получите информацию о [рукопожатии] клиента data = conn.recv(1024)print(data)def get_headers(data): удалите значение, соответствующее Sec-WebSocket-Key, из заголовка запроса и верните header_dict = {} header_str = data.decode ( utf8) для i в header_str.split(/r/n): if str(i).startswith(Sec-WebSocket-Key): return i.split(:)[1].strip()# Получите значение, соответствующее Sec-WebSocket-Key ws_key = get_headers(data)# Магическая строка: 258EAFA5-E914-47DA-95CA-C5AB0DC85B11magic_string = '258EAFA5 - E914-47DA-95CA-C5AB0DC85B11'# Сращивание socket_str = ws_key + Magic_string# шифрование sha1 socket_str_sha1 = hashlib.sha1(socket_str.encode(utf8)).digest()# шифрование base64 socket_str_base64 = base64.b64encode(socket_str_sha1)# Сращивание заголовка ответа response_tpl = HTTP/1.1 101 Переключение Протоколы/r/n/Обновление:websocket/r/n/Соединение: Обновление/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))# Сервер отправляет заголовок ответа клиенту conn.send(response_tpl.encode(utf8))# Клиент и сервер устанавливают длинное соединение для получения и отправки данных в цикле, пока True: msg = conn.recv(8096) print( сообщение)
<!DOCTYPE html><html lang=en><head> <meta charset=UTF-8> <title>Title</title></head><body></body><script type=text/javascript> ws = новый WebSocket(ws://127.0.0.1:9527); ws.onmessage = function (ev) { console.log(ev)//для получения данных</script></html>
Прикреплен заголовок HTTP-запроса, инициированного клиентом:
b'GET /ws/ HTTP/1.1Хост: 127.0.0.1:9527Соединение: ОбновлениеPragma: no-cacheCache-Control: no-cacheПользовательский агент: Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.3...Обновление: 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- сдуть client_max_window_bits';4. Методы шифрования и дешифрования веб-сокетов:
Метод расшифровки:
# 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'# Выполните битовую операцию со вторым байтом, то есть /x87 биты 9–16, и полезная нагрузка 127 = hashstr[1] & 127#. Когда результат битовой операции равен 127, байты 3–10 представляют собой длину данных# Байтов 11-14 — строка, необходимая для расшифровки маски #Данные идут с 15-го байта до конца, если полезная нагрузка == 127: Extend_payload_len = hashstr[2:10] маска = hashstr[10:14] decoded = hashstr[14:]# Если результат битовой операции равен 126, то 3-4 байта - это длина данных # 5-8 байты - это строка, необходимая для расшифровки маски # Тогда данные С 9-го байта до конца, если полезная нагрузка == 126: Extend_payload_len = hashstr[2:4] маска = hashstr[4:8] декодированная = hashstr[8:]# Если результат битовой операции меньше или равен 125, то это число является длиной данных # 3-6 байтов — это строка, необходимая для расшифровки маски # Данные идут с 7-го байта до конца, если полезная нагрузка <= 125: Extend_payload_len = Нет маска = hashstr[2:6] декодировано = hashstr[6:]str_byte = bytearray() для i в диапазоне (len(декодировано)): byte = декодировано[i] ^ маска[i % 4] str_byte.append(byte)print(str_byte.decode(utf8))
Метод шифрования:
import structmsg_bytes = 5555555.encode(utf8)token = b/x81length = len(msg_bytes)if length < 126: токен += struct.pack(B, length)elif length == 126: token += struct.pack(!BH) , 126, длина)else: токен += struct.pack(!BQ, 127, длина)msg = токен + msg_bytesprint(msg)4. Примеры связи между клиентом и сервером на основе инфраструктуры flask и протокола 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(): # Получите ссылку пользователя user_socket = request.environ. get(wsgi.websocket) # type:WebSocket print (доступ успешен), пока True: msg = user_socket.receive() #Получить сообщение print(msg) user_socket.send(msg) #Отправить сообщение if __name__ == '__main__': # Укажите адрес и номер порта для откройте службу Websocket http_serv = WSGIServer((127.0.0.1, 8001), приложение, handler_class=WebSocketHandler) # Запуск службы Websocket http_serv.serve_forever()
HTML-файл:
<!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()>Нажмите, чтобы создать ссылку</botton><br><p>Введите сообщение: <input type=text Placeholder=Input message id=msg></p><buttom class=btn btn- успех onclick =send_msg()>Отправить сообщение</buttom><script> var ws = null; функция createocket() { ws = new WebSocket(ws://127.0.0.1:8001/ws); ws.onmessage = function (data) { console.log(сообщение, полученное от сервера =,data.data } } function send_msg() { var to_msg =); document.getElementById(msg).value; ws.send(to_msg) </script></body></html>
клиент.png
Серверная часть.png
Таким образом, мы просто реализуем связь клиент-сервер через протокол Websocket. И мы можем создать несколько ссылок для одновременного взаимодействия с серверной частью.
5. Реализовать обмен мгновенными сообщениями (IM) на основе Websocket:Код сервера:
из колбы 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): # Получаем ссылку пользователя user_socket = request.environ.get(wsgi.websocket) # type:WebSocket user_socket_dict[username] = user_socket print(username+ссылка успешна!) while True: msg = user_socket.receive() # Принимаем сообщения для сокета в user_socket_dict.values(): # type:WebSocket if user_socket != socket:# Если вы отправите сообщение самостоятельно, сервер не ответит вам, попробуйте: socket.send(json.dumps({sender: username, msg: msg})) за исключением: continueif __name__ == '__main__. ': # Укажите адрес и номер порта для открытия службы Websocket http_serv = WSGIServer((127.0.0.1, 8001), app, handler_class=WebSocketHandler) # Запуск службы Websocket http_serv.serve_forever()
HTML-код:
<!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>Пожалуйста, введите свой никнейм:<input type=text id=username></p><botton class=btn btn-default onclick=createsocket()>Нажмите, чтобы создать ссылку</botton><br><p>Введите сообщение: <input type=text id=msg >< /p><buttom class=btn btn-success onclick=send_msg()>Отправить сообщение</buttom><br><br><br><div style=border: 2px сплошной; ширина: 500 пикселей; высота: 800 пикселей; id = text_div></div><script> var ws = null; var username = null; WebSocket(ws://127.0.0.1:8001/ws +/+ имя пользователя); (данные) {вар text_div = document.getElementById(text_div); вар obj_data = JSON.parse(data.data); вар add_msg = <p> + obj_data.sender + : + obj_data.msg + </p>; внутреннийHTML += add_msg } } функция 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>; = add_msg; ws.send(to_msg); </script></body></html>
Клиент01.png
Клиент02.png
Серверная часть.png
Код представляет собой демонстрационный код, с ошибками и ошибками. На данный момент он в основном используется для обучения, поэтому никакие придирки не допускаются. Желающие могут дополнительно оптимизировать! ! !
Выше приведено все содержание этой статьи. Я надеюсь, что она будет полезна для изучения всеми. Я также надеюсь, что все поддержат сеть VeVb Wulin.