Created
June 5, 2017 20:52
-
-
Save anonymous/f322c569534092607fbbbfbf2312324c to your computer and use it in GitHub Desktop.
fff
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#!/usr/bin/python3 | |
import socket | |
import struct | |
import sys | |
import time | |
# Функция, для получения N байт из сокета | |
def recv_n_bytes(sock, n): | |
# b'', а не '' - потому, что из сокета приходят байты, а | |
# не символы. Т.е. нам нужен не str, а bytes | |
buf = b'' | |
left = n | |
# работаем пока не набрали достаточно | |
while left: | |
# читаем из сокета НЕ БОЛЕЕ left байт | |
# recv(10) может вернуть от 1 до 10 байт включительно | |
got = sock.recv(left) | |
# еще может вернуть 0 байт - признак того, что сокет закрыли с той | |
# стороны. Паникуем и кидаем ошибку - т.к. закрытия в этот момент | |
# не должно быть | |
if not got: | |
raise Exception('Клиент сосет хуи') | |
# обновляем буфер и счетчик | |
buf += got | |
left -= len(got) | |
return buf | |
def server(): | |
# делаем сокет - по умолчнию это будет потоковый (SOCK_STREAM) сокет для | |
# интернетов (AF_INET), т.е. TCP/IP | |
sock = socket.socket() | |
# Просто эту хуйню желательно сделать сразу после создания сокета, | |
# предназначенного для получения соединений. Иначе потом может вылезти | |
# ошибка 'Address already in use'. НЕ ПЫТАЙСЯ ПОНЯТЬ. | |
sock.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1) | |
# устанавливаем локальный адрес сокета - порт 1488 на любом интерфейсе ('') | |
sock.bind(('', 1488)) | |
# начинаем принимать соединения по установленному адресу. Соединения будут | |
# ставится в очередь в ОС. 3 - максимальная длинна этой очереди. Т.е. если | |
# в очереди на подключение к порту 1488 уже 3 клиента - остальные будут | |
# посланы нахуй самой ОС | |
sock.listen(3) | |
# работаем, пока не заебет (до Ctrl-C или ошибки) | |
while True: | |
# вынимаем одно соединение из очереди (ждем, если никого нет) | |
# conn - новый сокет для этого подлючения | |
# addr - адрес клиента | |
print('Waiting for incoming connection...') | |
conn, addr = sock.accept() | |
print('Got connection from:', addr) | |
# получаем от клиента заголовок | |
header_buf = recv_n_bytes(conn, 8) | |
# сейчаас header_buf - просто кусок байт, его надо разобрать в | |
# питоновские значения. Укавзываем, что в header_buf лежат | |
# два беззнаковых числа по 32 бита каждое ('L' дважды) | |
# а порядок байт - big-endian ('>'). Питон их прочитает и вернет | |
file_name_len, data_len = struct.unpack('>LL', header_buf) | |
# ограничиваем длинну имени и фаила здравым смыслом | |
if file_name_len > 1024: | |
raise Exception('Клиент охуел') | |
if data_len > 100*1024*1024: | |
raise Exception('Клиент охуел') | |
# получаем имя фаила | |
file_name = recv_n_bytes(conn, file_name_len) | |
print ('File name:', file_name) | |
# получаем данные (все сразу в память) | |
data = recv_n_bytes(conn, data_len) | |
# На проверку имени фаила пока забиваем. Пишем что угодно, куда | |
# угодно. Но вообще так делать не надо. | |
# Б - безопасность | |
# Открываем фаил для записи ('w') байт ('b') | |
file = open(file_name, 'wb') | |
# пишем | |
file.write(data) | |
# закрываем | |
file.close() | |
# посылаем ответ клиенту | |
conn.send(b'OK') | |
# закрываем сокет | |
conn.close() | |
print('Done') | |
def client(local_file_name, ip): | |
# Что и куда пишем | |
# Имя фаила делаем по шаблону от текущего времени - что бы нескучно было | |
file_name_str = '/tmp/говно-{}'.format(int(time.time())) | |
# Делаем из строки (т.е. символов unicode) байты (согласно кодировке) | |
file_name = file_name_str.encode('utf-8') | |
# Читаем локальный фаил | |
file = open(local_file_name, 'rb') | |
data = file.read() | |
file.close() | |
# формируем заголовок в нужном формате | |
header_buf = struct.pack('>LL', len(file_name), len(data)) | |
# создаем сокет | |
# bind тут не нужен - нам посрать на исходящий интерфейс/порт | |
sock = socket.socket() | |
# подключаемся к серверу | |
print("Sending to:", ip, "File name:", file_name_str) | |
sock.connect((ip, 1488)) | |
# шлем туда все, что надо | |
sock.send(header_buf) | |
sock.send(file_name) | |
sock.send(data) | |
# получаем ответ | |
resp = recv_n_bytes(sock, 2) | |
if resp != b'OK': | |
raise Exception('Сервер шлет говно') | |
print('Done') | |
if __name__=='__main__': | |
# sys.argv - агрументы командной строки. sys.argv[0] - имя скрипта, | |
# 1 и далее - собственно аргументы | |
if len(sys.argv) == 1: | |
print ("python3 file_catcher.py server - сервер - принимать файлы") | |
print ("python3 file_catcher.py client SERVER_IP SERVER_IP ... - отправить") | |
elif sys.argv[1] == 'server': | |
print('Сервер') | |
server() | |
elif sys.argv[1] == 'client': | |
for ip in sys.argv[2:]: | |
# посылаем сам скрипт | |
client(sys.argv[0], ip) | |
else: | |
print('lolwut') |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment