rx3:index
Differences
This shows you the differences between two versions of the page.
Both sides previous revisionPrevious revisionNext revision | Previous revision | ||
rx3:index [2017/03/24 08:30] – [Serveur UDP] orel | rx3:index [2024/03/18 15:06] (current) – external edit 127.0.0.1 | ||
---|---|---|---|
Line 1: | Line 1: | ||
====== Réseau L2 Info : Socket en Python 3 ====== | ====== Réseau L2 Info : Socket en Python 3 ====== | ||
- | http:// | ||
- | ==== Client UDP ==== | + | Un peu de documentation : |
+ | |||
+ | * https:// | ||
+ | * https:// | ||
+ | * https:// | ||
+ | * https:// | ||
+ | * https:// | ||
+ | |||
+ | |||
+ | ==== Tips en Python ==== | ||
+ | |||
+ | == String vs Byte-Array == | ||
+ | |||
+ | Les fonctions de la famille send()/ | ||
+ | |||
+ | <code python> | ||
+ | string = " | ||
+ | byterray = b" | ||
+ | sock.send(bytearray) | ||
+ | </ | ||
+ | |||
+ | Pour convertir une string en byte-array (et inversement), | ||
+ | |||
+ | <code python> | ||
+ | bytearray = " | ||
+ | string = b" | ||
+ | </ | ||
+ | |||
+ | Pour convertir une string " | ||
+ | |||
+ | <code python> | ||
+ | sentence = " | ||
+ | words = sentence.split(" | ||
+ | </ | ||
+ | |||
+ | A l' | ||
+ | |||
+ | <code python> | ||
+ | sentence = " " | ||
+ | </ | ||
+ | |||
+ | ==Un mot sur les classes...== | ||
+ | |||
+ | Un mot maintenant sur les classes en Python... Plûtot qu'un long discours, voici un exemple de classe : | ||
+ | |||
+ | <code python> | ||
+ | class Dog: | ||
+ | |||
+ | def __init__(self, | ||
+ | self.name = name | ||
+ | self.age = age | ||
+ | |||
+ | def addYear(self): | ||
+ | self.age += 1 | ||
+ | |||
+ | def print(self): | ||
+ | print(" | ||
+ | |||
+ | </ | ||
+ | |||
+ | A la manière d'une structure, une classe encapsule des données (name et age). De plus, la classe permet de définir des méthodes (addYear et print), qui sont des fonctions permettant de manipuler les données de la classe (au travers la variable self, qui désigne l' | ||
+ | |||
+ | Un objet est une instance particulière de la classe, que l'on peut créer en appellant le constructeur Dog(). Ce constructeur appelle implcitement la méthode __init__ de la classe. Dans l' | ||
+ | |||
+ | <code python> | ||
+ | milou = Dog(" | ||
+ | rantanplan = Dog(" | ||
+ | milou.print() | ||
+ | rantanplan.addYear() | ||
+ | rantanplan.print() | ||
+ | </ | ||
+ | |||
+ | Pour aller plus loin : https:// | ||
+ | |||
+ | ==Un mot sur le flux TCP !== | ||
+ | |||
+ | Considérons deux sockets TCP s1 et s2, correspondant à une connexion déjà établie entre un client et un serveur. La gestion du flux TCP implique un mécanisme de bufferisation à l' | ||
+ | |||
+ | <code python> | ||
+ | # client | ||
+ | s1.send(b" | ||
+ | s1.send(b" | ||
+ | </ | ||
+ | |||
+ | On souhaiterait récupérer b" | ||
+ | |||
+ | Tout d' | ||
+ | |||
+ | <code python> | ||
+ | # client | ||
+ | s1.sendall(b" | ||
+ | s1.sendall(b" | ||
+ | </ | ||
+ | |||
+ | Côté réception, le mécanisme de bufferisation pose également des difficultés. En effet, comme les deux envois sont très proches, il est fort probable qu'ils soient bufferisés à la réception avant l' | ||
+ | |||
+ | Une astuce pour contourner ce problème consiste à acquiter les messages : | ||
+ | |||
+ | <code python> | ||
+ | # client | ||
+ | s1.sendall(b" | ||
+ | ack = s1.recv(1000) | ||
+ | s1.sendall(b" | ||
+ | ack = s1.recv(1000) | ||
+ | </ | ||
+ | |||
+ | La fonction recv() étant bloquante, l' | ||
+ | |||
+ | ==Recv non bloquant== | ||
+ | |||
+ | Par défaut, la fonction recv() des sockets est bloquante... Plus précisément, | ||
+ | |||
+ | Une première solution consiste à utiliser des sockets non bloquante, mais cela implique de gérer une exception dans le cas où il n'y a rien à recevoir ! | ||
+ | |||
+ | <code python> | ||
+ | import errno | ||
+ | sock = ... | ||
+ | sock.setBlocking(False) | ||
+ | try: | ||
+ | msg = sock.recv(1000) | ||
+ | except socket.error as e: | ||
+ | if e.args[0] == errno.EWOULDBLOCK: | ||
+ | print(" | ||
+ | else | ||
+ | print(" | ||
+ | </ | ||
+ | |||
+ | Une autre façon (plus élégante) consiste à utiliser select() avec un timeout de 0 ! | ||
+ | |||
+ | <code python> | ||
+ | import select | ||
+ | sock = ... | ||
+ | sock.setBlocking(False) | ||
+ | lsock, _, _ = select.select([sock], | ||
+ | if lsock: | ||
+ | msg = sock.recv(1000) | ||
+ | else: | ||
+ | print(" | ||
+ | </ | ||
+ | |||
+ | ==== Client | ||
<code python> | <code python> | ||
Line 23: | Line 162: | ||
- | ==== Client TCP ==== | + | ==== Client |
<code python> | <code python> | ||
# | # | ||
- | import sys | ||
import socket | import socket | ||
- | |||
- | HOST = ' | ||
- | PORT = 80 | ||
s = socket.socket(socket.AF_INET, | s = socket.socket(socket.AF_INET, | ||
- | s.connect((HOST, PORT)) | + | s.connect((" |
- | s.sendall(b' | + | s.sendall(b' |
data = s.recv(1024) | data = s.recv(1024) | ||
s.close() | s.close() | ||
Line 40: | Line 175: | ||
</ | </ | ||
- | ==== Serveur UDP ==== | + | ==== Serveur |
Voici un echo server en version UDP... | Voici un echo server en version UDP... | ||
<code python> | <code python> | ||
+ | # | ||
import socket | import socket | ||
+ | import sys | ||
HOST = '' | HOST = '' | ||
PORT = 7777 # Arbitrary non-privileged port | PORT = 7777 # Arbitrary non-privileged port | ||
- | s = socket.socket(socket.AF_INET, | + | s = socket.socket(socket.AF_INET, |
+ | # s = socket.socket(socket.AF_INET6, | ||
s.bind((HOST, | s.bind((HOST, | ||
while True: | while True: | ||
reply, addr = s.recvfrom(1500) | reply, addr = s.recvfrom(1500) | ||
- | if not reply: break | + | print (reply) |
- | s.sendto(reply, | + | s.sendto(reply, |
- | </ | + | </ |
+ | |||
+ | On utilise //netstat// pour vérifier que son serveur écoute : | ||
+ | |||
+ | netstat -ulpn | ||
+ | Proto Recv-Q Send-Q Local Address | ||
+ | udp 0 0 0.0.0.0: | ||
+ | |||
+ | |||
+ | |||
+ | |||
+ | Voici un client netcat ipv4/ | ||
+ | nc -4 -u localhost 7777 | ||
+ | | ||
+ | | ||
==== Serveur TCP ==== | ==== Serveur TCP ==== | ||
Line 63: | Line 215: | ||
<code python> | <code python> | ||
- | # Echo server program | + | #!/ |
import socket | import socket | ||
+ | |||
HOST = '' | HOST = '' | ||
- | PORT = 50007 | + | PORT = 7777 # Arbitrary non-privileged port |
s = socket.socket(socket.AF_INET, | s = socket.socket(socket.AF_INET, | ||
+ | s.setsockopt(socket.SOL_SOCKET, | ||
s.bind((HOST, | s.bind((HOST, | ||
- | s.listen(1) | + | s.listen(0) |
- | conn, addr = s.accept() | + | while True: |
- | with conn: | + | sclient, addr = s.accept() |
- | | + | print(' |
- | while True: | + | while True: |
- | data = conn.recv(1024) | + | data = sclient.recv(1500) |
- | if not data: break | + | if data == b'' |
- | | + | |
+ | sclient.sendall(data) | ||
+ | print(' | ||
+ | sclient.close() | ||
</ | </ | ||
- | ==== Documentation ==== | ||
- | * https:// | + | ==== Serveur TCP (version multithread) ==== |
- | * https:// | + | |
- | * https:// | + | |
- | * https:// | + | |
+ | <code python> | ||
+ | # | ||
+ | import socket | ||
+ | import threading | ||
+ | |||
+ | def handle(addr, | ||
+ | print(' | ||
+ | while True: | ||
+ | data = sclient.recv(1500) | ||
+ | if data == b'' | ||
+ | break | ||
+ | print(data) | ||
+ | sclient.sendall(data) | ||
+ | print(' | ||
+ | sclient.close() | ||
+ | |||
+ | |||
+ | HOST = '' | ||
+ | PORT = 7777 | ||
+ | s = socket.socket(socket.AF_INET, | ||
+ | s.setsockopt(socket.SOL_SOCKET, | ||
+ | s.bind((HOST, | ||
+ | s.listen(0) | ||
+ | while True: | ||
+ | sclient, addr = s.accept() | ||
+ | t = threading.Thread(None, | ||
+ | t.start() | ||
+ | </ | ||
+ | |||
+ | ==== Serveur Echo TCP (version select) ==== | ||
+ | |||
+ | //La version select permet de gérer de multiples clients simultanément.// | ||
+ | |||
+ | <code python> | ||
+ | # | ||
+ | import socket | ||
+ | import select | ||
+ | |||
+ | HOST = '' | ||
+ | PORT = 7777 | ||
+ | s = socket.socket(socket.AF_INET, | ||
+ | s.setsockopt(socket.SOL_SOCKET, | ||
+ | s.bind((HOST, | ||
+ | s.listen() | ||
+ | l = [] | ||
+ | l.append(s) | ||
+ | m = {} | ||
+ | |||
+ | while True: | ||
+ | l2, _, _ = select.select(l, | ||
+ | for s2 in l2: | ||
+ | # socket server (new client connection) | ||
+ | if s2 == s: | ||
+ | sclient, addr = s.accept() | ||
+ | l.append(sclient) | ||
+ | m[sclient] = addr | ||
+ | print(' | ||
+ | # socket client (new client message) | ||
+ | else: | ||
+ | while True: | ||
+ | data = s2.recv(1500) | ||
+ | print(data) | ||
+ | if data == b'' | ||
+ | print(' | ||
+ | l.remove(s2) | ||
+ | s2.close() | ||
+ | break | ||
+ | s2.sendall(data) | ||
+ | s.close() | ||
+ | </ | ||
rx3/index.txt · Last modified: 2024/03/18 15:06 by 127.0.0.1