задача
This commit is contained in:
parent
e1519804fc
commit
70022c0081
33
.gitignore
vendored
Normal file
33
.gitignore
vendored
Normal file
@ -0,0 +1,33 @@
|
|||||||
|
# Виртуальное окружение PyCharm
|
||||||
|
venv/
|
||||||
|
venv_*/
|
||||||
|
env/
|
||||||
|
.env/
|
||||||
|
ENV/
|
||||||
|
|
||||||
|
# Файлы PyCharm
|
||||||
|
.idea/
|
||||||
|
*.iml
|
||||||
|
.DS_Store
|
||||||
|
|
||||||
|
# Python
|
||||||
|
__pycache__/
|
||||||
|
*.py[cod]
|
||||||
|
*$py.class
|
||||||
|
*.so
|
||||||
|
.Python
|
||||||
|
|
||||||
|
# Логи и временные файлы
|
||||||
|
*.log
|
||||||
|
*.pcap
|
||||||
|
*.pcapng
|
||||||
|
|
||||||
|
# Секреты и конфиги
|
||||||
|
.env
|
||||||
|
token.txt
|
||||||
|
config.py
|
||||||
|
secrets.py
|
||||||
|
|
||||||
|
# Файлы отладки
|
||||||
|
.vscode/
|
||||||
|
*.pid
|
||||||
207
gitea_api_client.py
Normal file
207
gitea_api_client.py
Normal file
@ -0,0 +1,207 @@
|
|||||||
|
# gitea_api_client.py
|
||||||
|
import os
|
||||||
|
import requests
|
||||||
|
import json
|
||||||
|
import logging
|
||||||
|
from pathlib import Path
|
||||||
|
|
||||||
|
# Загружаем .env файл для PyCharm
|
||||||
|
try:
|
||||||
|
from dotenv import load_dotenv
|
||||||
|
|
||||||
|
# Ищем .env файл в текущей директории
|
||||||
|
env_path = Path('.') / '.env'
|
||||||
|
if env_path.exists():
|
||||||
|
load_dotenv()
|
||||||
|
logging.info("Загружен .env файл")
|
||||||
|
else:
|
||||||
|
logging.warning(".env файл не найден, используем системные переменные")
|
||||||
|
except ImportError:
|
||||||
|
logging.warning("python-dotenv не установлен, используем os.environ")
|
||||||
|
|
||||||
|
logging.basicConfig(
|
||||||
|
level=logging.INFO,
|
||||||
|
format='%(asctime)s - %(levelname)s - %(message)s'
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
|
class GiteaClient:
|
||||||
|
"""Клиент для работы с Gitea API"""
|
||||||
|
|
||||||
|
def __init__(self):
|
||||||
|
self.base_url = os.getenv('GITEA_URL', 'https://git.vyatsu.ru')
|
||||||
|
self.token = os.getenv('GITEA_TOKEN')
|
||||||
|
|
||||||
|
if not self.token:
|
||||||
|
# Пробуем альтернативные имена переменных
|
||||||
|
self.token = os.getenv('GITEA_TOKEN') or os.getenv('TOKEN')
|
||||||
|
|
||||||
|
if not self.token:
|
||||||
|
raise ValueError(
|
||||||
|
"Токен не найден!\n"
|
||||||
|
"Создайте файл .env с содержимым:\n"
|
||||||
|
"GITEA_TOKEN=ваш_токен\n"
|
||||||
|
"Или установите переменную окружения GITEA_TOKEN"
|
||||||
|
)
|
||||||
|
|
||||||
|
self.headers = {
|
||||||
|
'Authorization': f'token {self.token}',
|
||||||
|
'Content-Type': 'application/json',
|
||||||
|
'Accept': 'application/json'
|
||||||
|
}
|
||||||
|
|
||||||
|
logging.info(f"✓ Инициализирован клиент для {self.base_url}")
|
||||||
|
|
||||||
|
def get_user_info(self):
|
||||||
|
"""Получение информации о пользователе"""
|
||||||
|
try:
|
||||||
|
response = requests.get(
|
||||||
|
f"{self.base_url}/api/v1/user",
|
||||||
|
headers=self.headers,
|
||||||
|
timeout=10
|
||||||
|
)
|
||||||
|
response.raise_for_status()
|
||||||
|
|
||||||
|
user = response.json()
|
||||||
|
logging.info(f"\n👤 Информация о пользователе:")
|
||||||
|
logging.info(f" Логин: {user.get('login')}")
|
||||||
|
logging.info(f" Полное имя: {user.get('full_name', 'Не указано')}")
|
||||||
|
logging.info(f" Email: {user.get('email')}")
|
||||||
|
logging.info(f" ID: {user.get('id')}")
|
||||||
|
logging.info(f" Админ: {user.get('is_admin', False)}")
|
||||||
|
|
||||||
|
return user
|
||||||
|
|
||||||
|
except requests.exceptions.RequestException as e:
|
||||||
|
logging.error(f"Ошибка получения пользователя: {e}")
|
||||||
|
return None
|
||||||
|
|
||||||
|
def create_repository(self, name, description="", private=False):
|
||||||
|
"""Создание нового репозитория"""
|
||||||
|
try:
|
||||||
|
data = {
|
||||||
|
'name': name,
|
||||||
|
'description': description,
|
||||||
|
'private': private,
|
||||||
|
'auto_init': True
|
||||||
|
}
|
||||||
|
|
||||||
|
response = requests.post(
|
||||||
|
f"{self.base_url}/api/v1/user/repos",
|
||||||
|
headers=self.headers,
|
||||||
|
json=data,
|
||||||
|
timeout=30
|
||||||
|
)
|
||||||
|
response.raise_for_status()
|
||||||
|
|
||||||
|
repo = response.json()
|
||||||
|
logging.info(f"\n✅ Репозиторий создан: {repo['html_url']}")
|
||||||
|
logging.info(f" Название: {repo['name']}")
|
||||||
|
logging.info(f" Приватный: {repo['private']}")
|
||||||
|
|
||||||
|
return repo
|
||||||
|
|
||||||
|
except requests.exceptions.RequestException as e:
|
||||||
|
logging.error(f"Ошибка создания репозитория: {e}")
|
||||||
|
if hasattr(e, 'response') and e.response:
|
||||||
|
logging.error(f"Ответ сервера: {e.response.text}")
|
||||||
|
return None
|
||||||
|
|
||||||
|
def create_issue(self, owner, repo, title, body=""):
|
||||||
|
"""Создание issue"""
|
||||||
|
try:
|
||||||
|
data = {
|
||||||
|
'title': title,
|
||||||
|
'body': body or "Создано через API PyCharm"
|
||||||
|
}
|
||||||
|
|
||||||
|
response = requests.post(
|
||||||
|
f"{self.base_url}/api/v1/repos/{owner}/{repo}/issues",
|
||||||
|
headers=self.headers,
|
||||||
|
json=data,
|
||||||
|
timeout=30
|
||||||
|
)
|
||||||
|
response.raise_for_status()
|
||||||
|
|
||||||
|
issue = response.json()
|
||||||
|
logging.info(f"\n📝 Issue создан: {issue['html_url']}")
|
||||||
|
logging.info(f" Номер: #{issue['number']}")
|
||||||
|
logging.info(f" Заголовок: {issue['title']}")
|
||||||
|
|
||||||
|
return issue
|
||||||
|
|
||||||
|
except requests.exceptions.RequestException as e:
|
||||||
|
logging.error(f"Ошибка создания issue: {e}")
|
||||||
|
return None
|
||||||
|
|
||||||
|
|
||||||
|
def main():
|
||||||
|
"""Основная функция"""
|
||||||
|
print("=" * 50)
|
||||||
|
print("Gitea API Клиент")
|
||||||
|
print("=" * 50)
|
||||||
|
|
||||||
|
try:
|
||||||
|
client = GiteaClient()
|
||||||
|
|
||||||
|
# Получаем информацию о пользователе
|
||||||
|
user = client.get_user_info()
|
||||||
|
if not user:
|
||||||
|
return
|
||||||
|
|
||||||
|
username = user.get('login')
|
||||||
|
|
||||||
|
print("\nВыберите действие:")
|
||||||
|
print("1. Прочитать информацию")
|
||||||
|
print("2. Создать репозиторий")
|
||||||
|
print("3. Создать issue (в существующем репозитории)")
|
||||||
|
print("4. Создать репозиторий + issue (полный тест)")
|
||||||
|
|
||||||
|
choice = input("\nВаш выбор (1-4): ").strip()
|
||||||
|
|
||||||
|
if choice == '1':
|
||||||
|
client.get_user_info()
|
||||||
|
|
||||||
|
elif choice == '2':
|
||||||
|
name = input("Название репозитория: ")
|
||||||
|
desc = input("Описание: ")
|
||||||
|
private = input("Приватный? (y/n): ").lower() == 'y'
|
||||||
|
client.create_repository(name, desc, private)
|
||||||
|
|
||||||
|
elif choice == '3':
|
||||||
|
owner = input("Владелец репозитория: ")
|
||||||
|
repo = input("Название репозитория: ")
|
||||||
|
title = input("Заголовок issue: ")
|
||||||
|
body = input("Текст issue: ")
|
||||||
|
client.create_issue(owner, repo, title, body)
|
||||||
|
|
||||||
|
elif choice == '4':
|
||||||
|
repo_name = f"test-repo-{__import__('time').time()}"
|
||||||
|
print(f"\nСоздаю репозиторий {repo_name}...")
|
||||||
|
repo = client.create_repository(
|
||||||
|
name=repo_name,
|
||||||
|
description="Тестовый репозиторий из PyCharm"
|
||||||
|
)
|
||||||
|
|
||||||
|
if repo:
|
||||||
|
print("Создаю issue...")
|
||||||
|
client.create_issue(
|
||||||
|
owner=username,
|
||||||
|
repo=repo_name,
|
||||||
|
title="Тестовый issue от PyCharm",
|
||||||
|
body="Этот issue создан автоматически через Gitea API\n"
|
||||||
|
"Лабораторная работа: Работа с сетевыми соединениями"
|
||||||
|
)
|
||||||
|
|
||||||
|
except ValueError as e:
|
||||||
|
print(f"\n❌ Ошибка: {e}")
|
||||||
|
print("\nРешение:")
|
||||||
|
print("1. Создайте файл .env в корне проекта")
|
||||||
|
print("2. Добавьте в него: GITEA_TOKEN=ваш_токен")
|
||||||
|
print("3. Перезапустите программу")
|
||||||
|
except Exception as e:
|
||||||
|
print(f"\n❌ Неожиданная ошибка: {e}")
|
||||||
|
|
||||||
|
|
||||||
|
if __name__ == '__main__':
|
||||||
|
main()
|
||||||
40
http_requests_client.py
Normal file
40
http_requests_client.py
Normal file
@ -0,0 +1,40 @@
|
|||||||
|
# http_requests_client.py
|
||||||
|
import requests
|
||||||
|
import logging
|
||||||
|
|
||||||
|
logging.basicConfig(level=logging.INFO, format='%(asctime)s - %(message)s')
|
||||||
|
|
||||||
|
|
||||||
|
def http_get_requests():
|
||||||
|
"""HTTP GET запрос через библиотеку requests"""
|
||||||
|
|
||||||
|
try:
|
||||||
|
url = "http://vyatsu.ru"
|
||||||
|
|
||||||
|
# Выполняем GET запрос
|
||||||
|
logging.info(f"Запрос к {url}")
|
||||||
|
response = requests.get(url, timeout=10)
|
||||||
|
|
||||||
|
# Информация об ответе
|
||||||
|
logging.info(f"Статус код: {response.status_code} {response.reason}")
|
||||||
|
logging.info(f"Время ответа: {response.elapsed.total_seconds():.3f} сек")
|
||||||
|
logging.info(f"Размер ответа: {len(response.content)} байт")
|
||||||
|
|
||||||
|
# Заголовки ответа
|
||||||
|
logging.info("Основные заголовки:")
|
||||||
|
for header in ['content-type', 'server', 'date']:
|
||||||
|
if header in response.headers:
|
||||||
|
logging.info(f" {header}: {response.headers[header]}")
|
||||||
|
|
||||||
|
# Тело ответа (первые 500 символов)
|
||||||
|
logging.info(f"Тело ответа:\n{response.text[:500]}")
|
||||||
|
|
||||||
|
return response
|
||||||
|
|
||||||
|
except requests.exceptions.RequestException as e:
|
||||||
|
logging.error(f"Ошибка запроса: {e}")
|
||||||
|
return None
|
||||||
|
|
||||||
|
|
||||||
|
if __name__ == '__main__':
|
||||||
|
http_get_requests()
|
||||||
61
http_socket_client.py
Normal file
61
http_socket_client.py
Normal file
@ -0,0 +1,61 @@
|
|||||||
|
# http_socket_client.py
|
||||||
|
import socket
|
||||||
|
import logging
|
||||||
|
|
||||||
|
logging.basicConfig(level=logging.INFO, format='%(asctime)s - %(message)s')
|
||||||
|
|
||||||
|
|
||||||
|
def http_get_socket():
|
||||||
|
"""HTTP GET запрос через низкоуровневый socket"""
|
||||||
|
|
||||||
|
HOST = 'vyatsu.ru'
|
||||||
|
PORT = 80
|
||||||
|
|
||||||
|
# HTTP запрос вручную
|
||||||
|
request = f"""GET / HTTP/1.1
|
||||||
|
Host: {HOST}
|
||||||
|
User-Agent: PyCharm-Socket-Client
|
||||||
|
Accept: text/html
|
||||||
|
Connection: close
|
||||||
|
|
||||||
|
"""
|
||||||
|
# Заменяем переносы строк на \r\n как требует HTTP
|
||||||
|
request = request.replace('\n', '\r\n')
|
||||||
|
|
||||||
|
try:
|
||||||
|
# Создаем TCP соединение
|
||||||
|
with socket.socket(socket.AF_INET, socket.SOCK_STREAM) as client_socket:
|
||||||
|
logging.info(f"Подключение к {HOST}:{PORT}")
|
||||||
|
client_socket.connect((HOST, PORT))
|
||||||
|
|
||||||
|
logging.info("Отправка HTTP запроса...")
|
||||||
|
client_socket.sendall(request.encode())
|
||||||
|
|
||||||
|
# Получаем ответ
|
||||||
|
response = b''
|
||||||
|
while True:
|
||||||
|
chunk = client_socket.recv(4096)
|
||||||
|
if not chunk:
|
||||||
|
break
|
||||||
|
response += chunk
|
||||||
|
|
||||||
|
# Разбираем ответ
|
||||||
|
response_str = response.decode('utf-8', errors='replace')
|
||||||
|
|
||||||
|
# Разделяем заголовки и тело
|
||||||
|
if '\r\n\r\n' in response_str:
|
||||||
|
headers, body = response_str.split('\r\n\r\n', 1)
|
||||||
|
else:
|
||||||
|
headers = response_str
|
||||||
|
body = ''
|
||||||
|
|
||||||
|
logging.info(f"Статус: {headers.split(chr(10))[0]}")
|
||||||
|
logging.info(f"Заголовков получено: {len(headers)} символов")
|
||||||
|
logging.info(f"Тело ответа (первые 300 символов):\n{body[:300]}")
|
||||||
|
|
||||||
|
except Exception as e:
|
||||||
|
logging.error(f"Ошибка: {e}")
|
||||||
|
|
||||||
|
|
||||||
|
if __name__ == '__main__':
|
||||||
|
http_get_socket()
|
||||||
56
run_all.py
Normal file
56
run_all.py
Normal file
@ -0,0 +1,56 @@
|
|||||||
|
# run_all.py - универсальный запуск для PyCharm
|
||||||
|
import subprocess
|
||||||
|
import sys
|
||||||
|
import time
|
||||||
|
import os
|
||||||
|
|
||||||
|
|
||||||
|
def run_script(script_name):
|
||||||
|
"""Запуск Python скрипта"""
|
||||||
|
print(f"\n{'=' * 50}")
|
||||||
|
print(f"Запуск {script_name}")
|
||||||
|
print(f"{'=' * 50}")
|
||||||
|
|
||||||
|
result = subprocess.run([sys.executable, script_name])
|
||||||
|
return result.returncode
|
||||||
|
|
||||||
|
|
||||||
|
def main():
|
||||||
|
print("🚀 Запуск всех скриптов лабораторной работы")
|
||||||
|
print(f"Python: {sys.executable}")
|
||||||
|
|
||||||
|
scripts = [
|
||||||
|
('tcp_server.py', False), # Сервер запускаем в фоне?
|
||||||
|
('tcp_client.py', True),
|
||||||
|
('udp_server.py', False),
|
||||||
|
('udp_client.py', True),
|
||||||
|
('http_socket_client.py', True),
|
||||||
|
('http_requests_client.py', True),
|
||||||
|
('gitea_api_client.py', True),
|
||||||
|
]
|
||||||
|
|
||||||
|
# Запускаем серверы
|
||||||
|
servers = []
|
||||||
|
for script, is_client in scripts:
|
||||||
|
if not is_client:
|
||||||
|
print(f"\nЗапуск сервера: {script}")
|
||||||
|
proc = subprocess.Popen([sys.executable, script])
|
||||||
|
servers.append(proc)
|
||||||
|
time.sleep(1) # Даем серверу время на запуск
|
||||||
|
|
||||||
|
# Запускаем клиенты
|
||||||
|
for script, is_client in scripts:
|
||||||
|
if is_client:
|
||||||
|
time.sleep(0.5)
|
||||||
|
run_script(script)
|
||||||
|
|
||||||
|
# Завершаем серверы
|
||||||
|
for proc in servers:
|
||||||
|
proc.terminate()
|
||||||
|
print(f"Сервер остановлен")
|
||||||
|
|
||||||
|
print("\n✅ Все тесты завершены!")
|
||||||
|
|
||||||
|
|
||||||
|
if __name__ == '__main__':
|
||||||
|
main()
|
||||||
45
tcp_client.py
Normal file
45
tcp_client.py
Normal file
@ -0,0 +1,45 @@
|
|||||||
|
|
||||||
|
import socket
|
||||||
|
import time
|
||||||
|
|
||||||
|
|
||||||
|
def run_tcp_client():
|
||||||
|
SERVER_HOST = '127.0.0.1'
|
||||||
|
SERVER_PORT = 10000
|
||||||
|
|
||||||
|
try:
|
||||||
|
print(f"CLIENT: Подключение к {SERVER_HOST}:{SERVER_PORT}...")
|
||||||
|
client_socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
|
||||||
|
client_socket.connect((SERVER_HOST, SERVER_PORT))
|
||||||
|
print("CLIENT: ✅ Соединение установлено\n")
|
||||||
|
|
||||||
|
messages = [
|
||||||
|
"Hello, TCP Server!",
|
||||||
|
"Как дела?",
|
||||||
|
"Это тестовое сообщение",
|
||||||
|
"EXIT"
|
||||||
|
]
|
||||||
|
|
||||||
|
for i, message in enumerate(messages, 1):
|
||||||
|
print(f"CLIENT: Отправка '{message}'")
|
||||||
|
client_socket.sendall(message.encode('utf-8'))
|
||||||
|
|
||||||
|
response = client_socket.recv(1024)
|
||||||
|
print(f"CLIENT: Ответ '{response.decode('utf-8')}'\n")
|
||||||
|
|
||||||
|
time.sleep(1)
|
||||||
|
|
||||||
|
client_socket.close()
|
||||||
|
print("CLIENT: Соединение закрыто")
|
||||||
|
|
||||||
|
except ConnectionRefusedError:
|
||||||
|
print("CLIENT: ❌ Ошибка - сервер не запущен!")
|
||||||
|
print("CLIENT: Сначала запустите 'python tcp_server_fixed.py'")
|
||||||
|
except ConnectionResetError:
|
||||||
|
print("CLIENT: ❌ Ошибка - соединение разорвано сервером")
|
||||||
|
except Exception as e:
|
||||||
|
print(f"CLIENT: ❌ Ошибка: {e}")
|
||||||
|
|
||||||
|
|
||||||
|
if __name__ == '__main__':
|
||||||
|
run_tcp_client()
|
||||||
58
tcp_server.py
Normal file
58
tcp_server.py
Normal file
@ -0,0 +1,58 @@
|
|||||||
|
|
||||||
|
import socket
|
||||||
|
import logging
|
||||||
|
|
||||||
|
logging.basicConfig(level=logging.INFO, format='%(asctime)s - %(message)s')
|
||||||
|
|
||||||
|
|
||||||
|
def run_tcp_server():
|
||||||
|
HOST = '127.0.0.1'
|
||||||
|
PORT = 10000
|
||||||
|
|
||||||
|
with socket.socket(socket.AF_INET, socket.SOCK_STREAM) as server_socket:
|
||||||
|
server_socket.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
|
||||||
|
server_socket.bind((HOST, PORT))
|
||||||
|
server_socket.listen(5)
|
||||||
|
|
||||||
|
print(f"SERVER: TCP сервер запущен на {HOST}:{PORT}")
|
||||||
|
print("SERVER: Ожидание подключений...")
|
||||||
|
print("SERVER: Нажмите Ctrl+C для остановки\n")
|
||||||
|
|
||||||
|
try:
|
||||||
|
while True:
|
||||||
|
client_socket, client_address = server_socket.accept()
|
||||||
|
print(f"SERVER: Клиент {client_address} подключился")
|
||||||
|
|
||||||
|
try:
|
||||||
|
while True:
|
||||||
|
data = client_socket.recv(1024)
|
||||||
|
|
||||||
|
if not data:
|
||||||
|
print(f"SERVER: Клиент {client_address} отключился")
|
||||||
|
break
|
||||||
|
|
||||||
|
received_text = data.decode('utf-8')
|
||||||
|
print(f"SERVER: Получено '{received_text}' от {client_address}")
|
||||||
|
|
||||||
|
modified_data = data.upper()
|
||||||
|
client_socket.sendall(modified_data)
|
||||||
|
print(f"SERVER: Отправлено '{modified_data.decode('utf-8')}'")
|
||||||
|
|
||||||
|
if modified_data == b'EXIT':
|
||||||
|
print(f"SERVER: Команда EXIT от {client_address}")
|
||||||
|
break
|
||||||
|
|
||||||
|
except ConnectionResetError:
|
||||||
|
print(f"SERVER: Клиент {client_address} разорвал соединение")
|
||||||
|
except Exception as e:
|
||||||
|
print(f"SERVER: Ошибка с {client_address}: {e}")
|
||||||
|
finally:
|
||||||
|
client_socket.close()
|
||||||
|
print(f"SERVER: Соединение с {client_address} закрыто\n")
|
||||||
|
|
||||||
|
except KeyboardInterrupt:
|
||||||
|
print("\nSERVER: Остановка сервера...")
|
||||||
|
|
||||||
|
|
||||||
|
if __name__ == '__main__':
|
||||||
|
run_tcp_server()
|
||||||
43
udp_client.py
Normal file
43
udp_client.py
Normal file
@ -0,0 +1,43 @@
|
|||||||
|
# udp_client.py
|
||||||
|
import socket
|
||||||
|
import logging
|
||||||
|
|
||||||
|
logging.basicConfig(level=logging.INFO, format='%(asctime)s - %(message)s')
|
||||||
|
|
||||||
|
|
||||||
|
def run_udp_client():
|
||||||
|
"""UDP клиент - подключение без установки соединения"""
|
||||||
|
|
||||||
|
SERVER_HOST = '127.0.0.1'
|
||||||
|
SERVER_PORT = 10001
|
||||||
|
|
||||||
|
with socket.socket(socket.AF_INET, socket.SOCK_DGRAM) as client_socket:
|
||||||
|
# UDP не требует connect(), но можно вызвать для удобства
|
||||||
|
# client_socket.connect((SERVER_HOST, SERVER_PORT))
|
||||||
|
|
||||||
|
messages = [
|
||||||
|
"Hello UDP Server!",
|
||||||
|
"UDP быстрее, но ненадежнее",
|
||||||
|
"EXIT"
|
||||||
|
]
|
||||||
|
|
||||||
|
for message in messages:
|
||||||
|
logging.info(f"📤 Отправка UDP: {message}")
|
||||||
|
|
||||||
|
# Отправляем дейтаграмму
|
||||||
|
client_socket.sendto(message.encode('utf-8'), (SERVER_HOST, SERVER_PORT))
|
||||||
|
|
||||||
|
# Получаем ответ (с таймаутом)
|
||||||
|
client_socket.settimeout(2)
|
||||||
|
try:
|
||||||
|
response, server_address = client_socket.recvfrom(1024)
|
||||||
|
logging.info(f"📥 Ответ: {response.decode('utf-8')}")
|
||||||
|
except socket.timeout:
|
||||||
|
logging.warning("⚠️ Таймаут: ответ не получен")
|
||||||
|
|
||||||
|
import time
|
||||||
|
time.sleep(1)
|
||||||
|
|
||||||
|
|
||||||
|
if __name__ == '__main__':
|
||||||
|
run_udp_client()
|
||||||
42
udp_server.py
Normal file
42
udp_server.py
Normal file
@ -0,0 +1,42 @@
|
|||||||
|
# udp_server.py
|
||||||
|
import socket
|
||||||
|
import logging
|
||||||
|
|
||||||
|
logging.basicConfig(level=logging.INFO, format='%(asctime)s - %(message)s')
|
||||||
|
|
||||||
|
|
||||||
|
def run_udp_server():
|
||||||
|
"""UDP сервер без установки соединения"""
|
||||||
|
|
||||||
|
HOST = '127.0.0.1'
|
||||||
|
PORT = 10001
|
||||||
|
|
||||||
|
# Создаем UDP сокет
|
||||||
|
with socket.socket(socket.AF_INET, socket.SOCK_DGRAM) as server_socket:
|
||||||
|
server_socket.bind((HOST, PORT))
|
||||||
|
|
||||||
|
logging.info(f"🚀 UDP сервер запущен на {HOST}:{PORT}")
|
||||||
|
logging.info("UDP не требует установки соединения, просто ждет данные...")
|
||||||
|
|
||||||
|
try:
|
||||||
|
while True:
|
||||||
|
# Получаем данные и адрес отправителя
|
||||||
|
data, client_address = server_socket.recvfrom(1024)
|
||||||
|
received_text = data.decode('utf-8')
|
||||||
|
logging.info(f"📥 Получено от {client_address}: {received_text}")
|
||||||
|
|
||||||
|
# Отправляем обратно в верхнем регистре
|
||||||
|
modified_data = data.upper()
|
||||||
|
server_socket.sendto(modified_data, client_address)
|
||||||
|
logging.info(f"📤 Отправлено {client_address}: {modified_data.decode('utf-8')}")
|
||||||
|
|
||||||
|
if modified_data == b'EXIT':
|
||||||
|
logging.info("Получена команда выхода")
|
||||||
|
break
|
||||||
|
|
||||||
|
except KeyboardInterrupt:
|
||||||
|
logging.info("\nСервер остановлен")
|
||||||
|
|
||||||
|
|
||||||
|
if __name__ == '__main__':
|
||||||
|
run_udp_server()
|
||||||
Loading…
Reference in New Issue
Block a user