Skip to content

Instantly share code, notes, and snippets.

Created June 5, 2017 20:52
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save anonymous/f322c569534092607fbbbfbf2312324c to your computer and use it in GitHub Desktop.
Save anonymous/f322c569534092607fbbbfbf2312324c to your computer and use it in GitHub Desktop.
fff
#!/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