Suche…


Einführung

Viele Programmiersprachen verwenden Sockets für die Kommunikation zwischen Prozessen oder zwischen Geräten. In diesem Thema wird die Verwendung des Sockets-Moduls in Python erläutert, um das Senden und Empfangen von Daten über gängige Netzwerkprotokolle zu vereinfachen.

Parameter

Parameter Beschreibung
socket.AF_UNIX UNIX-Socket
socket.AF_INET IPv4
socket.AF_INET6 IPv6
socket.SOCK_STREAM TCP
socket.SOCK_DGRAM UDP

Senden von Daten über UDP

UDP ist ein verbindungsloses Protokoll. Nachrichten an andere Prozesse oder Computer werden gesendet, ohne dass irgendeine Verbindung hergestellt wird. Es erfolgt keine automatische Bestätigung, wenn Ihre Nachricht empfangen wurde. UDP wird normalerweise in latenzempfindlichen Anwendungen oder in Anwendungen verwendet, die Broadcasts im gesamten Netzwerk senden.

Mit dem folgenden Code wird eine Nachricht an einen Prozess gesendet, der mit UDP auf dem Localhost-Port 6667 überwacht wird

Beachten Sie, dass der Socket nach dem Senden nicht "geschlossen" werden muss, da UDP verbindungslos ist .

from socket import socket, AF_INET, SOCK_DGRAM
s = socket(AF_INET, SOCK_DGRAM)
msg = ("Hello you there!").encode('utf-8')  # socket.sendto() takes bytes as input, hence we must encode the string first.
s.sendto(msg, ('localhost', 6667)) 

Daten über UDP empfangen

UDP ist ein verbindungsloses Protokoll. Dies bedeutet, dass Peers, die Nachrichten senden, vor dem Senden von Nachrichten keine Verbindung herstellen müssen. socket.recvfrom also ein Tupel zurück ( msg [die Nachricht, die der Socket empfangen hat], addr [die Adresse des Absenders])

Ein UDP-Server, der ausschließlich das socket Modul verwendet:

from socket import socket, AF_INET, SOCK_DGRAM
sock = socket(AF_INET, SOCK_DGRAM)
sock.bind(('localhost', 6667))

while True:
    msg, addr = sock.recvfrom(8192)  # This is the amount of bytes to read at maximum
    print("Got message from %s: %s" % (addr, msg))

Nachfolgend finden Sie eine alternative Implementierung mit socketserver.UDPServer :

from socketserver import BaseRequestHandler, UDPServer

class MyHandler(BaseRequestHandler):
    def handle(self):
        print("Got connection from: %s" % self.client_address)
        msg, sock = self.request
        print("It said: %s" % msg)
        sock.sendto("Got your message!".encode(), self.client_address) # Send reply

serv = UDPServer(('localhost', 6667), MyHandler)
serv.serve_forever()

Standardmäßig blockieren sockets . Dies bedeutet, dass die Ausführung des Skripts wartet, bis der Socket Daten empfängt.

Senden von Daten über TCP

Der Versand von Daten über das Internet wird durch mehrere Module ermöglicht. Das Sockets-Modul ermöglicht einen einfachen Zugriff auf die zugrunde liegenden Betriebssystemvorgänge, die für das Senden oder Empfangen von Daten von anderen Computern oder Prozessen verantwortlich sind.

Der folgende Code sendet die b'Hello' an einen TCP-Server, der Port 6667 auf dem Host localhost b'Hello' und schließt die Verbindung, wenn er fertig ist:

from socket import socket, AF_INET, SOCK_STREAM
s = socket(AF_INET, SOCK_STREAM)
s.connect(('localhost', 6667))  # The address of the TCP server listening
s.send(b'Hello')
s.close()

Die Socket-Ausgabe blockiert standardmäßig, dh das Programm wartet auf die Verbindung und sendet Aufrufe, bis die Aktion abgeschlossen ist. Für connect bedeutet dies, dass der Server die Verbindung tatsächlich annimmt. Für das Senden bedeutet dies nur, dass das Betriebssystem über genügend Pufferplatz verfügt, um die später zu sendenden Daten in die Warteschlange zu stellen.

Steckdosen sollten nach Gebrauch immer geschlossen sein.

TCP-Socket-Server mit mehreren Threads

Wenn es ohne Argumente ausgeführt wird, startet dieses Programm einen TCP-Socket-Server, der auf Port 5000 Verbindungen zu 127.0.0.1 5000 . Der Server behandelt jede Verbindung in einem separaten Thread.

Wenn dieses Programm mit dem Argument -c , stellt es eine Verbindung zum Server her, liest die Clientliste und druckt es aus. Die Clientliste wird als JSON-String übertragen. Der Clientname kann angegeben werden, indem das Argument -n . Durch die Übergabe verschiedener Namen kann der Effekt auf die Kundenliste beobachtet werden.

client_list.py

import argparse
import json
import socket
import threading

def handle_client(client_list, conn, address):
    name = conn.recv(1024)
    entry = dict(zip(['name', 'address', 'port'], [name, address[0], address[1]]))
    client_list[name] = entry
    conn.sendall(json.dumps(client_list))
    conn.shutdown(socket.SHUT_RDWR)
    conn.close()

def server(client_list):
    print "Starting server..."
    s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
    s.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
    s.bind(('127.0.0.1', 5000))
    s.listen(5)
    while True:
        (conn, address) = s.accept()
        t = threading.Thread(target=handle_client, args=(client_list, conn, address))
        t.daemon = True
        t.start()

def client(name):
    s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
    s.connect(('127.0.0.1', 5000))
    s.send(name)
    data = s.recv(1024)
    result = json.loads(data)
    print json.dumps(result, indent=4)

def parse_arguments():
    parser = argparse.ArgumentParser()
    parser.add_argument('-c', dest='client', action='store_true')
    parser.add_argument('-n', dest='name', type=str, default='name')
    result = parser.parse_args()
    return result

def main():
    client_list = dict()
    args = parse_arguments()
    if args.client:
        client(args.name)
    else:
        try:
            server(client_list)
        except KeyboardInterrupt:
            print "Keyboard interrupt"

if __name__ == '__main__':
    main()

Server-Ausgabe

$ python client_list.py
Starting server...

Client-Ausgabe

$ python client_list.py -c -n name1
{
    "name1": {
        "address": "127.0.0.1", 
        "port": 62210, 
        "name": "name1"
    }
}

Die Empfangspuffer sind auf 1024 Byte begrenzt. Wenn die JSON-Zeichenfolgendarstellung der Clientliste diese Größe überschreitet, wird sie abgeschnitten. Dadurch wird die folgende Ausnahme ausgelöst:

ValueError: Unterminated string starting at: line 1 column 1023 (char 1022)

Raw Sockets unter Linux

Deaktivieren Sie zunächst die automatische Prüfsumme Ihrer Netzwerkkarte:

sudo ethtool -K eth1 tx off

Senden Sie dann Ihr Paket mit einem SOCK_RAW-Socket:

#!/usr/bin/env python
from socket import socket, AF_PACKET, SOCK_RAW
s = socket(AF_PACKET, SOCK_RAW)
s.bind(("eth1", 0))

# We're putting together an ethernet frame here, 
# but you could have anything you want instead
# Have a look at the 'struct' module for more 
# flexible packing/unpacking of binary data
# and 'binascii' for 32 bit CRC
src_addr = "\x01\x02\x03\x04\x05\x06"
dst_addr = "\x01\x02\x03\x04\x05\x06"
payload = ("["*30)+"PAYLOAD"+("]"*30)
checksum = "\x1a\x2b\x3c\x4d"
ethertype = "\x08\x01"

s.send(dst_addr+src_addr+ethertype+payload+checksum)


Modified text is an extract of the original Stack Overflow Documentation
Lizenziert unter CC BY-SA 3.0
Nicht angeschlossen an Stack Overflow