Пинон vs. C
„ Програмиране с Python“, ФМИ
окиНйал ичаБиксй, фетСна енъКв, очоТ ечоТв, имиДрът имиДворт
03.06.2009
IPC
Какво е IPC?
- тръби (pipes)
- сигнали
- XSI messages
- shared memory
- а ако процесите не са на една машина?
BSD sockets
- бинарни комуникационни канали между два процеса
- може да пишем
- може да четем
- можем и двете
Въведение
- протоколи
- фамилии (AF_INET, AF_INET6, AF_UNIX)
- типове (SOCK_STREAM, SOCK_DGRAM, SOCK_RAW, …)
- адреси
Щепсели в Пайтън: клиенти
import socket
sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
sock.connect(('www.python.org', 80))
...
Щепсели в Пайтън: сървъри
import socket
sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
sock.bind(('darkstar.example.org', 1024))
sock.listen(5)
sock.accept()
...
Блокиране
Операциите върху сокети блокират по подразбиране. Може да им сложите време
за прликючване (timeout), както и въобще да не чакате
- sock.settimeout(seconds) (float)
- sock.setblocking(bool)
Писане и четене
Основно с два метода:
- send(bytes, [flags])
- recv(bufsize, [flags])
Не гарантират изпращане/получване на цялото количество информация
blocking send
send(bytes, [flags])
- връща броя на успешно изпратените байтове.
- ако данните са повече, отколкото побира буфера, блокира докато не ги изпрати
- дори да блокира може да не успее да изпрати всичко, напр. когато връзката е прекъсната
- правилното поведение в този случай е да се опитаме да изпратим оставащата част
- ако връзката наистина е прекъсната ще получим грешка
blocking recv
recv(bufsize, [flags])
- връща успешно получените данни
- опитва се веднага да върне някакви данни, съответно може да върне по-малко байтове отколкото bufsize
- освен когато няма никакви, тогава блокира
- ако не върне байтове (b'') това значи че връзката е прекъсната (за четене)
- ако укажем MSG_WAITALL, recv се държи подобно на send, блокира опитвайки се да получи всички данни
- разбира се може връзката да се разпадне и да не получим целите данни, в който случай връща каквото има
nonblocking send, recv
В неблокиращ режим, send и recv хвърлят грешка когато операцията не може да бъде изпълнена. Например
може да няма достатъчно място в буфера за изпращане, или няма никакви данни в буфера за приемане.
>>> c.send(b'0'*(2*528*1024))
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
socket.error: [Errno 11] Resource temporarily unavailable
EMSGSIZE
Някой протоколи комуникират чрез получаване и изпращане на съобщения. Те могат да имат изискване за
максимален размер на съобщението. Ако го надвишите се хвърля socket.error(errno.EMSGSIZE)
При SOCK_STREAM комуникацията се базира на поток от данни, а не на съобщения, така че при тях това
не се получава.
Съобщения
- сокетите работят със сурови данни
- данните се третират като единен поток
- пращането се разбива на части съответно информацията се получава на части
- частите нямат логическа обвързаност
Съобщения: как?
Използвайки комуникация чрез поток от данни можем да реализираме получаване/изпращане на съобщения, използвайки някое от следните:
- всяко съобщение е с фиксирана дължина
- съдържат разделяща последователност
- предава се размера на съобщението
- 1 връзка - 1 съобщение
Съобщения: пример (API)
Изпращане (блокиращo)
outgoing_message = sockmsg.Outgoing(input().encode('utf-8'))
outgoing_message.send(some_socket)
Получаване (блокиращо)
incoming_message = sockmsg.Incoming()
print( incoming_message.recv(some_socket).decode('utf-8') )
Съобщения: пример (API)
Примерно API за съобщения
- обекти за входни съобщения и изходни съобщения
- при блокиращи сокети получаваме/изпращаме съобщението с едно извикване
- при неблокиращи сокети обектите „знаят“ докъде е получено/изпратено съобщението и можем да продължим от последното прекъсване
Byte-order
- ИНДИЯНЦИИИ!
- всъщност Гъливер е виновен
- byte-order (LE, BE)
- native, network
- консистентност
Marshalling
- struct
- pickle
- проблеми със сигурността и pickle
- JSON няма проблеми със сигурността, но пък можем да използваме само примитивни Пайтън обекти
- „хитри“ съобщения които ни позволяват комуникиране директно чрез Пайтън обекти използвайки pickle или JSON
Много клиенти: реализация с нишки
По една нишка за всеки клиент. С блокиращи сокети е по-лесно.
Много клиенти: Multiplexing
Много клиенти за една нишка. Циклим между клиентите и се опитваме да правим
разни неща.
Polling
Чакаме събития за писане/четене върху файловия дескриптор:
Още въпроси?
Още интересни неща на: