Sök…


Introduktion

Många programmeringsspråk använder uttag för att kommunicera över processer eller mellan enheter. Detta ämne förklarar korrekt användning av sockelmodulen i Python för att underlätta sändning och mottagning av data via vanliga nätverksprotokoll.

parametrar

Parameter Beskrivning
socket.AF_UNIX UNIX-uttag
socket.AF_INET IPv4
socket.AF_INET6 IPv6
socket.SOCK_STREAM TCP
socket.SOCK_DGRAM UDP

Skickar data via UDP

UDP är ett anslutningsfritt protokoll. Meddelanden till andra processer eller datorer skickas utan att upprätta någon form av anslutning. Det finns ingen automatisk bekräftelse om ditt meddelande har tagits emot. UDP används vanligtvis i latenskänsliga applikationer eller i applikationer som skickar nätverkssändningar.

Följande kod skickar ett meddelande till en process som lyssnar på localhost-port 6667 med UDP

Observera att det inte finns något behov av att "stänga" uttaget efter sändningen, eftersom UDP är anslutningsfri .

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

Ta emot data via UDP

UDP är ett anslutningsfritt protokoll. Detta innebär att kamrater som skickar meddelanden inte behöver upprätta en anslutning innan du skickar meddelanden. socket.recvfrom returnerar således en tupel ( msg [meddelandet socket mottog], addr [avsändarens adress])

En UDP-server som endast använder 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))

Nedan är en alternativ implementering med 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()

Som standard blockeras sockets . Detta innebär att exekveringen av skriptet kommer att vänta tills uttaget tar emot data.

Skicka data via TCP

Att skicka data över internet görs möjligt med flera moduler. Socket-modulen ger låg åtkomst till de underliggande operativsystemoperationerna som ansvarar för att skicka eller ta emot data från andra datorer eller processer.

Följande kod skickar b'Hello' till en TCP-server som lyssnar på port 6667 på värdens lokalhost och stänger anslutningen när du är klar:

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

Socket-utgången blockeras som standard, det betyder att programmet kommer att vänta i anslutningen och skicka samtal tills åtgärden är 'klar'. För anslutning betyder det att servern faktiskt accepterar anslutningen. För sändning betyder det bara att operativsystemet har tillräckligt buffertutrymme för att köa data som ska skickas senare.

Uttag ska alltid stängas efter användning.

Multigängad TCP Socket Server

När det körs utan argument startar detta program en TCP-socket-server som lyssnar på anslutningar till 127.0.0.1 på port 5000 . Servern hanterar varje anslutning i en separat tråd.

När det körs med -c argumentet ansluter det här programmet till servern, läser klientlistan och skriver ut den. Klientlistan överförs som en JSON-sträng. Klientnamnet kan anges genom att skicka argumentet -n . Genom att ge olika namn kan effekten på klientlistan observeras.

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

Serverutgång

$ python client_list.py
Starting server...

Klientutgång

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

Mottagningsbuffertarna är begränsade till 1024 byte. Om JSON-strängrepresentationen av klientlistan överstiger denna storlek kommer den att avkortas. Detta gör att följande undantag tas upp:

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

Raw Sockets på Linux

Först inaktiverar du nätverkskortets automatiska kontrollsummning:

sudo ethtool -K eth1 tx off

Skicka sedan ditt paket med ett SOCK_RAW-uttag:

#!/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
Licensierat under CC BY-SA 3.0
Inte anslutet till Stack Overflow