Отправка данных через 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: `` `