Network programing with python - UPCM
Network programing with python - UPCM
with Python
IPv4 and IPv6
Sébastien Tixeuil
sebastien.Tixeuil@lip6.fr
print(gethostname()) print(gethostname())
postetixeuil4.rsr.lip6.fr
print(getfqdn()) print(getfqdn())
132.227.104.15
print(gethostbyname('lip6.fr')) print(gethostbyname('lip6.fr'))
print(gethostbyaddr('132.227.104.15')) print(gethostbyaddr('132.227.104.15'))
('ww.lip6.fr', ['15.104.227.132.in-
addr.arpa'], ['132.227.104.15'])
print(gethostbyname(getfqdn())) print(gethostbyname(getfqdn()))
132.227.84.244
IPv4-IPv6 Names IPv4-IPv6 Names
infolist = getaddrinfo('lip6.fr','www') infolist = getaddrinfo('lip6.fr','www')
print(infolist) print(infolist)
[(<AddressFamily.AF_INET: 2>,
<SocketKind.SOCK_DGRAM: 2>, 17,
'', ('132.227.104.15', 80)),
info = infolist[1] info = infolist[1]
(<AddressFamily.AF_INET: 2>,
<SocketKind.SOCK_STREAM: 1>, 6,
'', ('132.227.104.15', 80))]
print(info) print(info)
(<AddressFamily.AF_INET: 2>,
<SocketKind.SOCK_STREAM: 1>, 6,
s = socket(*info[0:3]) s = socket(*info[0:3])
'', ('132.227.104.15', 80))
s.connect(info[4]) s.connect(info[4])
toSend = str.encode(‘utf-8’)
str = received.decode(‘utf-8’)
UDP Python Client UDP Python Server
from socket import * from socket import *
print(‘server ready’)
message = input(‘lowercase sentence:’).encode(‘utf-8’)
while True:
clientSocket.sendto(message,(serverName,serverPort))
message, clientAddress = serverSocket.recvfrom(2048)
modifiedMessage, serverAddress = clientSocket.recvfrom(2048)
modifiedMessage = message.decode(‘utf-8’).upper()
print(modifiedMessage.decode(‘utf-8’))
serverSocket.sendto(modifiedMessage.encode(‘utf-8’),
clientSocket.close() clientAddress)
Numbers and
print(hex(1234))
print(pack('<i',1234))
print(pack('!i',1234))
print(unpack('>i',b'\x00\x00\x04\xd2'))
print(unpack('!i',b'\x00\x00\x04\xd2'))
Byte Order over the Network
from struct import *
print(hex(1234))
0x4d2
print(pack('<i',1234))
b'\xd2\x04\x00\x00'
b'\x00\x00\x04\xd2'
Network Exceptions
print(pack('>i',1234))
b'\x00\x00\x04\xd2'
print(pack('!i',1234))
(1234,)
print(unpack('>i',b'\x00\x00\x04\xd2'))
(1234,)
print(unpack('!i',b'\x00\x00\x04\xd2'))
Send Response
Datagram Read Datagram
BLOCKING
Close Socket
clientSocket.sendto(message,(serverName,serverPort)) clientSocket.sendto(message,(serverName,serverPort))
clientSocket.settimeout(delay)
clientSocket.settimeout(delay)
try:
try:
modifiedMessage, serverAddress = clientSocket.recvfrom(2048)
modifiedMessage, serverAddress = clientSocket.recvfrom(2048)
except socket.timeout:
except socket.timeout:
delay *= 2
delay *= 2
if delay > 2.0:
else: raise RuntimeError(‘server seems down’)
break else:
print(modifiedMessage.decode(‘utf-8’)) break
clientSocket.close() print(modifiedMessage.decode(‘utf-8’))
UDP Broadcast Client
from socket import *
serverPort = 1234
clientSocket.setsockopt(SOL_SOCKET,SO_BROADCAST,1)
clientSocket.sendto(message,(serverName,serverPort))
print(modifiedMessage.decode(‘utf-8’))
clientSocket.close()
serverPort = 1234
serverSocket = socket(AF_INET,SOCK_DGRAM)
serverSocket.bind((‘’,serverPort))
print(‘server ready’)
TCP Sending
while True:
modifiedMessage = message.decode(‘utf-8’).upper()
serverSocket.sendto(modifiedMessage.encode(‘utf-8’),
clientAddress)
TCP send TCP send Loop
…
• If TCP/IP stack has enough room, send returns
message=input(‘lowercase sentence:’).encode(‘utf-8’)
immediately, and the complete message will be
handled bytes_sent = 0
TCP sendall
message = input(‘lowercase
sentence:’).encode(‘utf-8’)
TCP Receiving
clientSocket.sendall(message)
…
TCP recv TCP recvall ?
• If TCP/IP stack is full enough, recv returns
• Deciding when all data is received is application
immediately, and the specified size message will
specific
be delivered
• Fixed size messages
• If TCP/IP stack is empty, recv is blocking
• Message size is announced before data is sent
• If TCP/IP stack is not empty, recv returns
immediately, but only a fraction of the specified • Special delimiters announce end of data
size will be delivered
TCP recvall
def recvall(sock, length):
blocks = []
while length:
if not block:
length -= len(block)
blocks.append(block)
return b''.join(blocks)
Sending a Block Receiving a Block
from struct import *
from struct import *
from socket import *
from socket import *
header_struct = Struct('!I')
header_struct = Struct('!I')
def put_block(sock, message):
def get_block(sock):
block_length = len(message)
data = recvall(sock, header_struct.size)
sock.sendall(header_struct.pack(
(block_length,) = header_struct.unpack(data)
block_length))
return recvall(sock, block_length)
sock.sendall(message)
JSON
from json import *
from socket import *
print(dumps(['aéçèà',1234,[2,3,4,5,6]]))
s = socket(AF_INET,SOCK_STREAM)
try:
print(dumps(s))
except TypeError:
print("this data does not seem serializable with JSON")
JSON
from json import *
from socket import *
["a\u00e9\u00e7\u00e8\u00e0", 1234, [2, 3, 4, 5, 6]]
print(dumps(['aéçèà',1234,[2,3,4,5,6]]))
try:
print(dumps(s))
except TypeError:
print("this data does not seem serializable with JSON")
str = b'A very long test string to evaluate compression and how much it improves str = b'A very long test string to evaluate compression and how much it improves
bandwidth usage' bandwidth usage'
print(len(str)) print(len(str))
88
78
def handle_client(clientSocket):
while True:
if not received:
clientSocket.close()
Programming else:
to_send = received.decode('utf-8').upper().encode('utf-8')
clientSocket.sendall(to_send)
while True:
handle_client(connectionSocket)
TCP TCP
Wait for Incoming Wait for Incoming
Connection on Server Handshake Create Connection Connection on Server Handshake Create Connection
Socket Blocking Socket Blocking
Blocking Blocking
Create Client-specific
Thread
Send Request
Send Request Read Request from
Read Request from Blocking
Blocking Connection Socket
Connection Socket
Blocking
Blocking
Send Response to
Send Response to Connection Socket
Connection Socket Blocking Read Response
Blocking Read Response Blocking
Blocking
Close
Close Connection Socket
Connection Socket Close Socket
Close Socket
Server Sub-Process
Multi-thread TCP Server Multi-Thread TCP Server
Client 2 Process Server Process Client 1 Process
from threading import *
Create & Bind
Create Socket Create Socket
Server Socket
…
def handle_client(clientSocket):
TCP TCP
Wait for Incoming
Create Connection Handshake Connection on Server Handshake Create Connection while True:
Blocking Socket Blocking
Blocking
received = clientSocket.recv(4096)
Create Client-specific Create Client-specific
Thread Thread if not received:
Send Request Send Request
Blocking Read Request from Read Request from Blocking
Connection Socket Connection Socket clientSocket.close()
Blocking Blocking
else:
while True:
received = clientSocket.recv(4096)
Send Request Send Request
Blocking Read Request from Read Request from Blocking
Connection Socket Connection Socket if not received:
Blocking Blocking
clientSocket.close()
else:
Send Response to Send Response to
Connection Socket Connection Socket
Read Response Blocking Blocking Read Response to_send = received.decode('utf-8').upper().encode('utf-8')
Blocking Blocking
clientSocket.sendall(to_send)
Wait for
Socket-related event
Blocking sockets = {serverSocket.fileno(): serverSocket}
received = dict()
Process Incoming
Read Request from Send Response to
# bytes received from fileno, that are not yet processed
Connection on Server Close
Connection Socket Connection Socket
Socket Connection Socket
Non-Blocking Non-Blocking
Non-Blocking to_send = dict()
to_send.pop(fd) sockets[connectionSocket.fileno()] =
connectionSocket
my_poll.unregister(fd)
else:
to_send[fd] = data[n:]
my_poll.modify(fd,POLLIN|POLLOUT) my_poll.modify(fd,POLLIN)
… Server Process
while True:
Create & Bind
Server Socket
for fd, event in my_poll.poll():
… Wait for
Socket-related event
Blocking
elif sockets[fd] is serverSocket:
else:
Process Incoming
Read Request from Send Response to
if event & POLLIN: Connection on Server
Connection Socket Connection Socket
Close
Socket Connection Socket
Non-Blocking Non-Blocking
Non-Blocking
…
…
Remote Procedure Call
• The main objective is to make client-server calls
(almost) transparent to the programmer
server.register_function(quadratic)
def quadratic(a,b,c):
print("Server ready")
b24ac = sqrt(b*b - 4.0*a*c)
print(proxy.addtogether(1,2,3,4,5)) print(proxy.addtogether(1,2,3,4,5)) 15
Wireshark Wireshark
POST /RPC2 HTTP/1.1 POST /RPC2 HTTP/1.1
Host: 127.0.0.1:7001
Host: 127.0.0.1:7001 Accept-Encoding: gzip
Accept-Encoding: gzip Content-Type: text/xml
Content-Type: text/xml User-Agent: Python-xmlrpc/3.4
HTTP/1.0 200 OK Content-Length: 330
User-Agent: Python-xmlrpc/3.4 HTTP/1.0 200 OK
Server: BaseHTTP/0.6 Python/3.4.3
Content-Length: 258 <?xml version='1.0'?> Server: BaseHTTP/0.6 Python/3.4.3
Date: Mon, 18 Jan 2016 13:41:45 GMT
<methodCall> Date: Mon, 18 Jan 2016 13:41:45 GMT
Content-type: text/xml <methodName>addtogether</methodName>
<?xml version='1.0'?> Content-type: text/xml
Content-length: 129 <params>
<methodCall> Content-length: 122
<param>
<methodName>addtogether</methodName> <value><int>1</int></value>
<?xml version='1.0'?>
<params> </param> <?xml version='1.0'?>
<methodResponse> <param>
<param> <methodResponse>
<params> <value><int>2</int></value>
<value><string>x</string></value> <params>
<param> </param>
</param> <param> <param>
<value><string>xyz</string></value>
<param> <value><int>3</int></value> <value><int>15</int></value>
</param> </param>
<value><string>y</string></value> </param>
</params> <param>
</param> </params>
</methodResponse> <value><int>4</int></value>
<param> </param> </methodResponse>
<value><string>z</string></value> <param>
</param> <value><int>5</int></value>
</param>
</params> </params>
</methodCall> </methodCall>
Conclusion