Zoeken…


Invoering

Veel programmeertalen gebruiken sockets om over processen of tussen apparaten te communiceren. In dit onderwerp wordt het juiste gebruik van de sockets-module in Python uitgelegd om het verzenden en ontvangen van gegevens via algemene netwerkprotocollen te vergemakkelijken.

parameters

Parameter Beschrijving
socket.AF_UNIX UNIX-aansluiting
socket.AF_INET IPv4
socket.AF_INET6 IPv6
socket.SOCK_STREAM TCP
socket.SOCK_DGRAM UDP

Gegevens verzenden via UDP

UDP is een verbindingsloos protocol. Berichten naar andere processen of computers worden verzonden zonder een verbinding tot stand te brengen. Er is geen automatische bevestiging als uw bericht is ontvangen. UDP wordt meestal gebruikt in latentiegevoelige toepassingen of in toepassingen die netwerkbrede uitzendingen verzenden.

De volgende code verzendt een bericht naar een proces dat luistert op localhost-poort 6667 met behulp van UDP

Merk op dat het niet nodig is om de socket na het verzenden te "sluiten", omdat UDP geen verbinding heeft .

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)) 

Gegevens ontvangen via UDP

UDP is een verbindingsloos protocol. Dit betekent dat peers die berichten verzenden geen verbinding hoeven te maken voordat ze berichten verzenden. socket.recvfrom retourneert dus een tuple ( msg [het bericht dat de socket heeft ontvangen], addr [het adres van de afzender])

Een UDP-server die alleen de socket :

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))

Hieronder is een alternatieve implementatie met 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()

sockets blokkeren standaard. Dit betekent dat de uitvoering van het script zal wachten tot de socket gegevens ontvangt.

Gegevens verzenden via TCP

Gegevens verzenden via internet wordt mogelijk gemaakt met behulp van meerdere modules. De socketmodule biedt toegang op laag niveau tot de onderliggende bewerkingen van het besturingssysteem die verantwoordelijk zijn voor het verzenden of ontvangen van gegevens van andere computers of processen.

De volgende code verzendt de bytetekenreeks b'Hello' naar een TCP-server die luistert op poort 6667 op de host-host en sluit de verbinding wanneer deze is voltooid:

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()

Socketuitgang wordt standaard geblokkeerd, wat betekent dat het programma in de verbinding wacht en oproepen verzendt totdat de actie is 'voltooid'. Voor verbinden betekent dit dat de server de verbinding daadwerkelijk accepteert. Voor verzenden betekent dit alleen dat het besturingssysteem voldoende bufferruimte heeft om de gegevens in de wachtrij te plaatsen om later te worden verzonden.

Contactdozen moeten na gebruik altijd worden gesloten.

Multi-threaded TCP Socketserver

Als dit programma zonder argumenten wordt uitgevoerd, start dit programma een TCP-socket-server die luistert naar verbindingen met 127.0.0.1 op poort 5000 . De server verwerkt elke verbinding in een afzonderlijke thread.

Wanneer het wordt uitgevoerd met het argument -c , maakt dit programma verbinding met de server, leest het de clientlijst en drukt het af. De clientlijst wordt overgedragen als een JSON-string. De clientnaam kan worden opgegeven door het argument -n door te geven. Door verschillende namen door te geven, kan het effect op de klantenlijst worden waargenomen.

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()

Serveruitvoer

$ python client_list.py
Starting server...

Clientuitvoer

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

De ontvangstbuffers zijn beperkt tot 1024 bytes. Als de JSON-stringrepresentatie van de clientlijst deze grootte overschrijdt, wordt deze afgekapt. Dit zal leiden tot de volgende uitzondering:

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

Raw Sockets op Linux

Eerst schakelt u de automatische controlesom van uw netwerkkaart uit:

sudo ethtool -K eth1 tx off

Stuur vervolgens uw pakket met behulp van een 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
Licentie onder CC BY-SA 3.0
Niet aangesloten bij Stack Overflow