Введение

Примеры

Отправка данных через UDP

UDP - это протокол без установления соединения. Сообщения другим процессам или компьютерам отправляются без установления какого-либо соединения. Там нет автоматического подтверждения, если ваше сообщение было получено. UDP обычно используется в приложениях, чувствительных к задержке, или в приложениях, отправляющих широковещательные сообщения в сети.

Следующий код отправляет сообщение процессу, прослушивающему порт localhost 6667 с использованием UDP

Обратите внимание , что нет никакой необходимости «закрыть» сокет после отправки, поскольку UDP является установление соединения .

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


 

Получение данных через UDP

UDP - это протокол без установления соединения. Это означает, что одноранговые отправляющие сообщения не требуют установления соединения перед отправкой сообщений. socket.recvfrom , таким образом , возвращает кортеж ( msg [сообщение сокет получил], addr [адрес отправителя])

UDP - сервер , использующий исключительно 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))


 

Ниже приводится альтернативная реализация с использованием 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 блока. Это означает, что выполнение скрипта будет ожидать, пока сокет не получит данные.

Отправка данных через TCP

Отправка данных через Интернет возможна с помощью нескольких модулей. Модуль сокетов обеспечивает низкоуровневый доступ к операциям базовой операционной системы, отвечающим за отправку или получение данных с других компьютеров или процессов.

Следующий код посылает строку байт b'Hello' на сервер TCP на порту 6667 на хосте локального хоста и закрывает соединение после завершения:

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

 

По умолчанию вывод сокетов блокируется, это означает, что программа будет ожидать подключения и отправлять вызовы, пока действие не будет «завершено». Для подключения это означает, что сервер фактически принимает соединение. Для отправки это означает только то, что в операционной системе достаточно буферного пространства, чтобы поставить в очередь данные для последующей отправки.

Розетки всегда должны быть закрыты после использования.

Многопоточный сокет-сервер TCP

При запуске без аргументов, эта программа запускается сервер сокета TCP , который прослушивает для подключения к 127.0.0.1 на порт 5000 . Сервер обрабатывает каждое соединение в отдельном потоке.

При запуске с -c аргументом, эта программа подключается к серверу, считывает список клиентов, и выводит его. Список клиентов передается в виде строки JSON. Имя клиента может быть определен путем пропускания -n аргумент. Передавая разные имена, можно наблюдать влияние на список клиентов.

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

 

Выход сервера

 $ python client_list.py
Starting server...

 

Выход клиента

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

 

Приемные буферы ограничены 1024 байтами. Если строковое представление JSON списка клиентов превышает этот размер, оно будет усечено. Это приведет к возникновению следующего исключения:

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

Сырые сокеты в Linux

Сначала вы отключите автоматическую контрольную сумму вашей сетевой карты:

 sudo ethtool -K eth1 tx off
 

Затем отправьте свой пакет, используя сокет SOCK_RAW: `` `

! / usr / bin / env python

из сокета импорта сокета, AF_PACKET, SOCK_RAW s = сокет (AF_PACKET, SOCK_RAW) s.bind (("eth1", 0))

Мы собираем кадр Ethernet,

но вы могли бы иметь все, что вы хотите вместо

Посмотрите на модуль "struct" для более

гибкая упаковка / распаковка двоичных данных

и «binascii» для 32-битной CRC

src_addr = "\ x01 \ x02 \ x03 \ x04 \ x05 \ x06" dst_addr = "\ x01 \ x02 \ x03 \ x04 \ x05 \ x06" полезная нагрузка = ( "[" 30) + "ПОЛЕЗНОЙ" + ( "]" 30 ) контрольная сумма = "\ x1a \ x2b \ x3c \ x4d" ethertype = "\ x08 \ x01"

s.send (dst_addr + src_addr + Ethertype + полезная нагрузка + контрольная сумма)

Синтаксис

Параметры

Примечания