Потоки. Передача файлов. Клиент-серверный чат¶
Потоки¶
Потоки (thread) в Python позволяет одновременно запускать разные подпрограммы, таким образом становится возможно выполнять несколько подпрограмм в одно и то же время. thread - это отдельный поток выполнения.
На самом деле подпрограммы даже при использовании потоков не выполняются одновременно:
Работа с потоками - это не работа с разными ядрами процесса, мы фактически работаем внутри того же процесса, что и без потоков, только дробим его на подзадачи, так что о более эффективном распределении ресурсов речи не идёт.
В Python для обеспечения стабильности и снижения конфликтов работает специальный шлюз - Global Interpreter Lock (GIL). Он и контролирует потоки.
GIL переключает потоки по умолчанию раз в 5 миллисекунд, так что потоки работают не одновременно, а последовательно, постоянно сменяя друга.
Самая близкая идея работе потоков в Питоне - сеанс одновременной игры в шахматы, когда один шахматист играет с несколькими. Сеанс хоть и называется “одновременным”, но фактически шахматист обходит всех по очереди и делает свой ход в каждой партии.
Для работы с потоками используются модули _thread и threading (более новый).
Рассмотрим простой код для работы с потоками.:
import threading
import time
def thread_function(number):
print(f"Thread {number}: starting\n")
time.sleep(2)
print(f"Thread {number}: finishing\n")
threads = list()
for index in range(3):
print(f"Create and start thread {index}\n")
x = threading.Thread(target=thread_function, args=(index,))
threads.append(x)
x.start()
for i,thread in enumerate (threads):
print (f'Join thread {i} \n')
thread.join()
Передача файлов¶
- Передачу файлов с помощью сокетов можно реализовать по следующей схеме:
Настраиваем сокет, устанавливаем соединение.
На отправляющей стороне:
открываем файл на чтение в режиме байтового чтения (
'rb').построчно передаём файл принимающей стороне.
На принимающей стороне:
открываем файл на запись в режиме байтовой записи (
'wb').построчно пишем в файл всё, что получаем от передающей стороны.
Закрываем файлы и соединение.
Передача файлов байтовыми строками позволяет пересылать любые файлы, независимо от их типа, расширения и т.п.
Пример кода для отправки файла с клиента серверу.
Сервер:
import socket
import sys
# создаём сокет и связываем его с IP-адресом и портом
sock = socket.socket()
ip = "localhost"
port = 9999
sock.bind((ip, port))
# сервер ожидает передачи информации
sock.listen(10)
while True:
# начинаем принимать соединения
conn, addr = sock.accept()
# выводим информацию о подключении
print('connected:', addr)
# получаем название файла
name_f = (conn.recv(1024)).decode ('UTF-8')
# открываем файл в режиме байтовой записи в отдельной папке 'sent'
f = open('sent/' + name_f,'wb')
while True:
# получаем байтовые строки
l = conn.recv(1024)
# пишем байтовые строки в файл на сервере
f.write(l)
if not l:
break
f.close()
conn.close()
print('File received')
sock.close()
Клиент:
import socket
import sys
ip = "localhost"
port = 9999
# создаём сокет для подключения
sock = socket.socket()
sock.connect((ip,port))
# запрашиваем имя файла и отправляем серверу
f_name = input ('File to send: ')
sock.send((bytes(f_name, encoding = 'UTF-8')))
# открываем файл в режиме байтового чтения
f = open (f_name, "rb")
# читаем строку
l = f.read(1024)
while (l):
# отправляем строку на сервер
sock.send(l)
l = f.read(1024)
f.close()
sock.close()
Задания¶
Используя код из урока, реализуйте возможность отправлять файл с сервера клиенту.
Реализуйте возможность передачи файлов как от клиента серверу, так и от сервера клиенту:
должна быть возможность выбрать режим передачи (1 - от клиента серверу, 2 - от сервера клиенту);
оформите код с помощью функций;
добавьте графический интерфейс с помощью модуля easygui.
Используя потоки напишите клиент-серверный чат, который будет принимать и отправлять сообщения. Для этого потребуется оформить код в функции.