Добавил:
Опубликованный материал нарушает ваши авторские права? Сообщите нам.
Вуз: Предмет: Файл:

отчет лаба 1 Гаранин

.docx
Скачиваний:
0
Добавлен:
12.02.2026
Размер:
996.51 Кб
Скачать

ФЕДЕРАЛЬНОЕ АГЕНСТВО ВОЗДУШНОГО ТРАНСПОРТА

(РОСАВИАЦИЯ)

ФЕДЕРАЛЬНОЕ ГОСУДАРСТВЕННОЕ БЮДЖЕТНОЕ ОБРАЗОВАТЕЛЬНОЕ УЧРЕЖДЕНИЕ ВЫСШЕГО ОБРАЗОВАНИЯ

«МОСКОВСКИЙ ГОСУДАРСТВЕННЫЙ ТЕХНИЧЕСКИЙ УНИВЕРСИТЕТ ГРАЖДАНСКОЙ АВИАЦИИ» (МГТУ ГА)

Кафедра вычислительных машин, комплексов, сетей и систем.

Лабораторная работа защищена с оценкой ____________________

____________________

(подпись преподавателя, дата)

ЛАБОРАТОРНАЯ РАБОТА №1

по дисциплине «Программирование сетевых приложений».

Тема: «Разработка многопоточного TCP-сервера и клиента для обмена текстовыми сообщениями.»

Выполнила студентка группы ИС221

Магальник Екатерина Борисовна

Руководитель: Гаранин Сергей Александрович

МОСКВА – 2025

Цель работы.

  • Закрепить теоретические знания о модели клиент-сервер и работе с сокетами.

  • Приобрести практические навыки программирования TCP-сокетов на языке Python (или C/C++ по выбору).

  • Освоить принципы обработки множественных подключений с помощью потоков (threading).

  • Научиться проектировать и реализовывать простой прикладной протокол.

Задание.

Разработать программу, состоящую из двух частей:

  • Серверное приложение (server.py).

  • Клиентское приложение (client.py).

Листинг.

Код сервера:

import socket import threading from http.client import responses # Глобальный список для хранения всех подключенных клиентов connected_clients = [] def broadcast_message(message, sender_socket=None): """Отправка сообщения всем клиентам, кроме отправителя""" disconnected_clients = [] for client in connected_clients[:]: # Используем копию списка для безопасной итерации try: if client != sender_socket: # Не отправляем сообщение отправителю client.sendall(message) except (BrokenPipeError, ConnectionResetError, OSError): # Клиент отключился disconnected_clients.append(client) # Удаляем отключенных клиентов for client in disconnected_clients: if client in connected_clients: connected_clients.remove(client) print(f"Клиент удален из списка (всего клиентов: {len(connected_clients)})") def handle_client(client_socket, client_address): """Обработка соединения с клиентом""" print(f'{client_address} подключился') # Добавляем клиента в список connected_clients.append(client_socket) print(f"Всего подключенных клиентов: {len(connected_clients)}") # Отправляем приветственное сообщение welcome_msg = f"Вы подключились к чату. Участников: {len(connected_clients)}".encode('utf-8') client_socket.sendall(welcome_msg) # Уведомляем других клиентов о новом участнике join_msg = f"Новый участник присоединился к чату ({client_address[0]}:{client_address[1]})".encode('utf-8') broadcast_message(join_msg, client_socket) with client_socket: while True: try: data = client_socket.recv(1024) if not data: break decode_data = data.decode('utf-8') print(f'Принято от {client_address}: {decode_data}') # Формируем сообщение для broadcast message_to_send = f"[{client_address[0]}:{client_address[1]}]: {decode_data}".encode('utf-8') # Отправляем сообщение всем клиентам, кроме отправителя broadcast_message(message_to_send, client_socket) # Отправляем подтверждение отправителю confirmation = "Сообщение доставлено".encode('utf-8') client_socket.sendall(confirmation) except ConnectionResetError: print(f'Соединение с {client_address} разорвано') break except Exception as e: print(f'Ошибка с клиентом {client_address}: {e}') break # Удаляем клиента при отключении if client_socket in connected_clients: connected_clients.remove(client_socket) # Уведомляем о выходе клиента leave_msg = f"Участник покинул чат ({client_address[0]}:{client_address[1]})".encode('utf-8') broadcast_message(leave_msg) print(f'{client_address} отключился. Осталось клиентов: {len(connected_clients)}') def run_server(): server_socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM) server_socket.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1) try: server_address = ('192.168.43.119', 55555) server_socket.bind(server_address) server_socket.listen(5) # Увеличиваем очередь подключений print(f"Сервер чата запущен на {server_address}") print("Ожидание подключений...") while True: client_socket, client_address = server_socket.accept() print(f'Новое подключение от {client_address}') # Создаем поток для обработки клиента client_thread = threading.Thread( target=handle_client, args=(client_socket, client_address) ) client_thread.daemon = True client_thread.start() except KeyboardInterrupt: print('\nСервер остановлен') except Exception as e: print(f'Ошибка сервера: {e}') finally: # Закрываем все соединения при завершении работы for client in connected_clients: try: client.close() except: pass server_socket.close() print("Сервер завершил работу") if __name__ == '__main__': run_server()

Код клиента:

import socket import threading def receive_messages(client_socket): """Функция для приема сообщений в отдельном потоке""" while True: try: response = client_socket.recv(1024) if not response: print("Соединение с сервером разорвано") break print(f'\n{response.decode("utf-8")}') print('Введите сообщение: ', end='', flush=True) except (ConnectionResetError, BrokenPipeError): print("\nСоединение с сервером разорвано") break except Exception as e: print(f"\nОшибка приема сообщения: {e}") break def run_client(): client_socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM) try: server_address = ('127.0.0.1', 55555) # Измените на IP сервера если нужно client_socket.connect(server_address) print("Подключение к чату...") # Сначала получаем запрос на никнейм nickname_prompt = client_socket.recv(1024).decode('utf-8') nickname = input(nickname_prompt) client_socket.sendall(nickname.encode('utf-8')) # Получаем приветственное сообщение welcome_msg = client_socket.recv(1024).decode('utf-8') print(f"\n{welcome_msg}") # Может прийти список участников try: client_socket.settimeout(0.5) # Таймаут для дополнительных сообщений participants_msg = client_socket.recv(1024).decode('utf-8') print(participants_msg) client_socket.settimeout(None) # Убираем таймаут except socket.timeout: pass # Нет дополнительных сообщений print("\nЧат запущен! Пишите сообщения:") print("=" * 50) # Запускаем поток для приема сообщений receive_thread = threading.Thread(target=receive_messages, args=(client_socket,)) receive_thread.daemon = True receive_thread.start() while True: mess = input('') if mess.lower() == 'exit': break client_socket.sendall(mess.encode('utf-8')) # Получаем подтверждение отправки try: confirmation = client_socket.recv(1024).decode('utf-8') # print(f' {confirmation}') # Можно раскомментировать для отладки except: pass except Exception as e: print(f'Ошибка: {e}') finally: client_socket.close() print('Отключено от сервера') if __name__ == '__main__': run_client()

Результат работы программы.

Сервер:

Клиент 1:

Клиент 2: