Add lab3 network examples
This commit is contained in:
commit
e66d4fa927
7
.gitignore
vendored
Normal file
7
.gitignore
vendored
Normal file
@ -0,0 +1,7 @@
|
||||
.venv/
|
||||
__pycache__/
|
||||
*.pyc
|
||||
.env
|
||||
.idea/
|
||||
.vscode/
|
||||
|
||||
130
README.md
Normal file
130
README.md
Normal file
@ -0,0 +1,130 @@
|
||||
# Лабораторная работа 3
|
||||
|
||||
Тема: работа с сетевыми соединениями в Python.
|
||||
|
||||
В проекте реализованы простые примеры TCP, UDP, HTTP-запросов через `socket` и `requests`, а также пример запроса к API Gitea.
|
||||
|
||||
## Подготовка
|
||||
|
||||
Создать и активировать виртуальное окружение:
|
||||
|
||||
```powershell
|
||||
python -m venv .venv
|
||||
.\.venv\Scripts\Activate.ps1
|
||||
```
|
||||
|
||||
Установить зависимости:
|
||||
|
||||
```powershell
|
||||
pip install -r requirements.txt
|
||||
```
|
||||
|
||||
## TCP
|
||||
|
||||
Сервер:
|
||||
|
||||
```powershell
|
||||
python tcp_server.py
|
||||
```
|
||||
|
||||
Клиент:
|
||||
|
||||
```powershell
|
||||
python tcp_client.py "hello server"
|
||||
```
|
||||
|
||||
Чтобы остановить TCP-сервер:
|
||||
|
||||
```powershell
|
||||
python tcp_client.py EXIT
|
||||
```
|
||||
|
||||
TCP-сервер работает на порту `10000`. Он принимает сообщение, переводит его в верхний регистр и возвращает клиенту.
|
||||
|
||||
Фильтр Wireshark:
|
||||
|
||||
```text
|
||||
tcp.port==10000
|
||||
```
|
||||
|
||||
## UDP
|
||||
|
||||
Сервер:
|
||||
|
||||
```powershell
|
||||
python udp_server.py
|
||||
```
|
||||
|
||||
Клиент:
|
||||
|
||||
```powershell
|
||||
python udp_client.py "hello server"
|
||||
```
|
||||
|
||||
Чтобы остановить UDP-сервер:
|
||||
|
||||
```powershell
|
||||
python udp_client.py EXIT
|
||||
```
|
||||
|
||||
UDP-сервер работает на порту `10001`. Он принимает сообщение, переворачивает строку и возвращает клиенту.
|
||||
|
||||
Фильтр Wireshark:
|
||||
|
||||
```text
|
||||
udp.port==10001
|
||||
```
|
||||
|
||||
## HTTP через socket
|
||||
|
||||
```powershell
|
||||
python http_socket_client.py
|
||||
```
|
||||
|
||||
Программа вручную открывает TCP-соединение с `vyatsu.ru` на порту `80`, отправляет HTTP-запрос и выводит часть ответа.
|
||||
При проверке сервер вернул ответ `301 Moved Permanently`, потому что сайт перенаправляет запрос на HTTPS-версию.
|
||||
|
||||
Фильтр Wireshark:
|
||||
|
||||
```text
|
||||
tcp.port==80
|
||||
```
|
||||
|
||||
## HTTP через requests
|
||||
|
||||
```powershell
|
||||
python http_requests_client.py
|
||||
```
|
||||
|
||||
`requests` сам формирует HTTP-запрос, обрабатывает ответ и предоставляет удобный объект `response`.
|
||||
При проверке `requests` автоматически обработал перенаправление и получил итоговый статус `200`.
|
||||
|
||||
## Gitea API
|
||||
|
||||
Токен нельзя хранить в коде. Нужно создать файл `.env`:
|
||||
|
||||
```text
|
||||
GITEA_TOKEN=ваш_токен
|
||||
```
|
||||
|
||||
Файл `.env` добавлен в `.gitignore`, поэтому он не должен попасть в коммит.
|
||||
|
||||
Запуск:
|
||||
|
||||
```powershell
|
||||
python gitea_api.py
|
||||
```
|
||||
|
||||
Программа выполняет запрос к:
|
||||
|
||||
```text
|
||||
https://git.vyatsu.ru/api/v1/user
|
||||
```
|
||||
|
||||
## Выводы
|
||||
|
||||
TCP устанавливает соединение перед передачей данных. В Wireshark можно увидеть трехстороннее рукопожатие: `SYN`, `SYN-ACK`, `ACK`. При завершении соединения видны пакеты `FIN` и `ACK`.
|
||||
|
||||
UDP не устанавливает соединение перед отправкой данных. В Wireshark видны отдельные UDP-пакеты без handshake и без подтверждений доставки.
|
||||
|
||||
При работе через `socket` HTTP-запрос нужно составлять вручную. В примере через `socket` виден ответ `301 Moved Permanently`. Библиотека `requests` делает больше действий автоматически: формирует заголовки, обрабатывает ответ и переходит по перенаправлению, поэтому итоговый ответ получился со статусом `200`.
|
||||
42
gitea_api.py
Normal file
42
gitea_api.py
Normal file
@ -0,0 +1,42 @@
|
||||
import os
|
||||
|
||||
import requests
|
||||
|
||||
|
||||
API_URL = "https://git.vyatsu.ru/api/v1"
|
||||
|
||||
|
||||
def load_token() -> str:
|
||||
token = os.getenv("GITEA_TOKEN")
|
||||
if token:
|
||||
return token
|
||||
|
||||
if os.path.exists(".env"):
|
||||
with open(".env", "r", encoding="utf-8") as file:
|
||||
for line in file:
|
||||
line = line.strip()
|
||||
if line.startswith("GITEA_TOKEN="):
|
||||
return line.split("=", 1)[1].strip()
|
||||
|
||||
return ""
|
||||
|
||||
|
||||
token = load_token()
|
||||
if not token:
|
||||
print("Token not found. Create .env file with GITEA_TOKEN=your_token")
|
||||
raise SystemExit(1)
|
||||
|
||||
headers = {"Authorization": f"token {token}"}
|
||||
|
||||
response = requests.get(f"{API_URL}/user", headers=headers, timeout=10)
|
||||
print(f"Status code: {response.status_code}")
|
||||
|
||||
if response.ok:
|
||||
user = response.json()
|
||||
print("Gitea user information:")
|
||||
print(f"Login: {user.get('login')}")
|
||||
print(f"Full name: {user.get('full_name')}")
|
||||
print(f"Email: {user.get('email')}")
|
||||
else:
|
||||
print(response.text)
|
||||
|
||||
8
http_requests_client.py
Normal file
8
http_requests_client.py
Normal file
@ -0,0 +1,8 @@
|
||||
import requests
|
||||
|
||||
|
||||
response = requests.get("http://vyatsu.ru", timeout=10)
|
||||
|
||||
print(f"Status code: {response.status_code}")
|
||||
print(response.text[:500])
|
||||
|
||||
33
http_socket_client.py
Normal file
33
http_socket_client.py
Normal file
@ -0,0 +1,33 @@
|
||||
import socket
|
||||
|
||||
|
||||
HOST = "vyatsu.ru"
|
||||
PORT = 80
|
||||
|
||||
|
||||
client = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
|
||||
client.connect((HOST, PORT))
|
||||
|
||||
request = (
|
||||
"GET / HTTP/1.1\r\n"
|
||||
"Host: vyatsu.ru\r\n"
|
||||
"User-Agent: python-socket-lab3\r\n"
|
||||
"Accept: text/html\r\n"
|
||||
"Connection: close\r\n"
|
||||
"\r\n"
|
||||
)
|
||||
|
||||
client.sendall(request.encode("utf-8"))
|
||||
|
||||
response_parts = []
|
||||
while True:
|
||||
data = client.recv(4096)
|
||||
if not data:
|
||||
break
|
||||
response_parts.append(data)
|
||||
|
||||
client.close()
|
||||
|
||||
response = b"".join(response_parts)
|
||||
print(response.decode("utf-8", errors="replace")[:2000])
|
||||
|
||||
2
requirements.txt
Normal file
2
requirements.txt
Normal file
@ -0,0 +1,2 @@
|
||||
requests
|
||||
|
||||
21
tcp_client.py
Normal file
21
tcp_client.py
Normal file
@ -0,0 +1,21 @@
|
||||
import socket
|
||||
import sys
|
||||
|
||||
|
||||
HOST = "127.0.0.1"
|
||||
PORT = 10000
|
||||
|
||||
|
||||
message = "hello server"
|
||||
if len(sys.argv) > 1:
|
||||
message = " ".join(sys.argv[1:])
|
||||
|
||||
client = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
|
||||
client.connect((HOST, PORT))
|
||||
client.sendall(message.encode("utf-8"))
|
||||
|
||||
data = client.recv(1024)
|
||||
print(f"Response from server: {data.decode('utf-8')}")
|
||||
|
||||
client.close()
|
||||
|
||||
39
tcp_server.py
Normal file
39
tcp_server.py
Normal file
@ -0,0 +1,39 @@
|
||||
import socket
|
||||
|
||||
|
||||
HOST = "0.0.0.0"
|
||||
PORT = 10000
|
||||
|
||||
|
||||
def process_message(message: str) -> str:
|
||||
return f"TCP server received: {message.upper()}"
|
||||
|
||||
|
||||
server = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
|
||||
server.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
|
||||
server.bind((HOST, PORT))
|
||||
server.listen(1)
|
||||
|
||||
print(f"TCP server started on port {PORT}")
|
||||
print("Send EXIT from client to stop the server")
|
||||
|
||||
while True:
|
||||
conn, addr = server.accept()
|
||||
print(f"Connection from {addr}")
|
||||
|
||||
data = conn.recv(1024)
|
||||
if not data:
|
||||
conn.close()
|
||||
continue
|
||||
|
||||
message = data.decode("utf-8")
|
||||
response = process_message(message)
|
||||
conn.sendall(response.encode("utf-8"))
|
||||
conn.close()
|
||||
|
||||
if message.strip().upper() == "EXIT":
|
||||
print("TCP server stopped")
|
||||
break
|
||||
|
||||
server.close()
|
||||
|
||||
20
udp_client.py
Normal file
20
udp_client.py
Normal file
@ -0,0 +1,20 @@
|
||||
import socket
|
||||
import sys
|
||||
|
||||
|
||||
HOST = "127.0.0.1"
|
||||
PORT = 10001
|
||||
|
||||
|
||||
message = "hello server"
|
||||
if len(sys.argv) > 1:
|
||||
message = " ".join(sys.argv[1:])
|
||||
|
||||
client = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
|
||||
client.sendto(message.encode("utf-8"), (HOST, PORT))
|
||||
|
||||
data, _ = client.recvfrom(1024)
|
||||
print(f"Response from server: {data.decode('utf-8')}")
|
||||
|
||||
client.close()
|
||||
|
||||
31
udp_server.py
Normal file
31
udp_server.py
Normal file
@ -0,0 +1,31 @@
|
||||
import socket
|
||||
|
||||
|
||||
HOST = "0.0.0.0"
|
||||
PORT = 10001
|
||||
|
||||
|
||||
def process_message(message: str) -> str:
|
||||
return f"UDP server received: {message[::-1]}"
|
||||
|
||||
|
||||
server = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
|
||||
server.bind((HOST, PORT))
|
||||
|
||||
print(f"UDP server started on port {PORT}")
|
||||
print("Send EXIT from client to stop the server")
|
||||
|
||||
while True:
|
||||
data, addr = server.recvfrom(1024)
|
||||
message = data.decode("utf-8")
|
||||
print(f"Message from {addr}: {message}")
|
||||
|
||||
response = process_message(message)
|
||||
server.sendto(response.encode("utf-8"), addr)
|
||||
|
||||
if message.strip().upper() == "EXIT":
|
||||
print("UDP server stopped")
|
||||
break
|
||||
|
||||
server.close()
|
||||
|
||||
Loading…
Reference in New Issue
Block a user