Создание сервера на python 3 с использованием встроенной библиотеки socket
Всех приветствую, долго думал, написать статью или нет, но все же решился поделится такой забавной темой как сервер на python.
Начнем с создания двух файлов, назовем их: server.py и client.py.
Сторона сервера
Импортируем встроенные библиотеки - socket, time
Что это за библиотека?
Данная библиотека определяет низкоуровневый интерфейс для отправки запросов и их получения. Если проще, то данный модуль позволит нам создать сокет с определенным портом и определенным протоколов подключения (TCP, UDP).
Сокет - это так называем программный интерфейс который позволяет обмениваться данными между процессами, как на одном ПК, так и на разных.
Импортирование библиотеки и создание сокета:
import socket
main_socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
main_socket.setsockopt(socket.IPPROTO_TCP, socket.TCP_NODELAY, 1)
main_socket.bind(("localhost", 5000))
main_socket.setblocking(0)
main_socket.listen(5)
clients_socket = []
Разберем каждую строку отдельно:
main_socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM) - здесь мы создаем сам сокет с такими параметрами: socket.AF_INET - данная строчка говорит сокету, о том, какого формата адреса будут подключаться: в данном примере 4 - трех значных числа (127.0.0.1). socket.SOCK_STREAM - проток подключения (TCP), для UDP - SOCK_DGRAM.
main_socket.setsockopt(socket.IPPROTO_TCP, socket.TCP_NODELAY, 1) - данная строчка позволяет отключить Алгоритм Нейгла и позволить отправлять пакеты так же быстро, как мы их и получаем. Алгоритм Нейгла, уменьшает количество получаемых пакетов, за счет создания одно большого, в котором содержаться все остальные.
main_socket.bind(("localhost", 5000)) - здесь мы указываем на каком адресе будет сервер и по какому порту можно подключится. Порт можно выбрать любой, кроме диапазона от 0 до 1023, так как эти порты зарезервированы системой. Localhost означает, что данный сервер будет на одном ПК и подключится к нему с других ПК будет невозможно.
main_socket.setblocking(0) - данная строчка, позволяет нам не блокировать сервер, в ожидании пакетов от всех пользователей, а работать дальше.
main_socket.listen(5) - эта строчка позволяет прослушивать входящие сообщения от клиентов, ну а цифра 5, означает что максимальное число прослушивания 5.
Список clients_socket, будет хранить в себе сокеты всех подключенных клиентов.
Перейдем к циклу:
while True:
#connect users
try:
new_socket, addres = main_socket.accept()
new_socket.setblocking(0)
print("Connect - ", addres)
clients_socket.append(new_socket)
except:
pass
time.sleep(0.01)
В данном цикле мы просматриваем не подключился ли кто то, без конструкции try, скрипт сразу выдаст ошибку, далее, если есть подключение, создается отдельный сокет с данными от клиента и отдельно берется его ip adress, ну и просто выводим в консоль клиент который подключился. Функция sleep в конце цикла, позволяет серверу работать, без данной функции, скрипт так же, выдаст ошибку из-за большой скорости.
Дополним цикл:
try:
for sock in clients_socket:
data = sock.recv(1024)
data = data.decode()
print(data)
except:
pass
for sock in clients_socket:
try:
sock.send('Проверка связи'.encode())
except:
clients_socket.remove(sock)
sock.close()
Пробегусь по основным методам:
recv(1024) - это обращение к сокету клиента, для чтения пакетов, которые он отправил, 1024 - это количество байт, которые хочет получить сервер от пользователя.
decode() - декодирование байтовой последовательности в привычный нами вид информации.
encode() - противоположность методу выше, позволяет строку перевести в байтовую последовательность, для успешной отправки на сокет клиента.
Сторона клиента:
import socket
sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
sock.setsockopt(socket.IPPROTO_TCP, socket.TCP_NODELAY, 1)
sock.connect(("localhost", 5000))
while True:
data = sock.recv(1024)
data = data.decode()
print(data)
Так же, создаем сокет, отключаем Алгоритм Нейгла, но, не блокируем клиент, как сервер, так как клиент зависит от сервера. Производим подключение, по адресу и порту, которые мы указали на сервере. Дальше так же, создаем цикл, в котором просто читаем что нам отправил сервер и выводим это на экран.