From 51d2d20f75cc967f182e47806216f75603030a62 Mon Sep 17 00:00:00 2001 From: Chen Yudong Date: Fri, 16 Dec 2022 13:51:20 +0800 Subject: [PATCH] example: add socket scripts again --- examples/protocols/sockets/README.md | 19 ++++- .../sockets/scripts/run_tcp_client.py | 50 +++++++++++ .../sockets/scripts/run_tcp_server.py | 85 +++++++++++++++++++ .../sockets/scripts/run_udp_client.py | 52 ++++++++++++ .../sockets/scripts/run_udp_server.py | 80 +++++++++++++++++ .../sockets/tcp_client/pytest_tcp_client.py | 65 ++------------ .../sockets/tcp_server/pytest_tcp_server.py | 41 +++------ .../sockets/udp_client/pytest_udp_client.py | 60 ++----------- .../sockets/udp_server/pytest_udp_server.py | 43 +++------- 9 files changed, 324 insertions(+), 171 deletions(-) create mode 100644 examples/protocols/sockets/scripts/run_tcp_client.py create mode 100644 examples/protocols/sockets/scripts/run_tcp_server.py create mode 100644 examples/protocols/sockets/scripts/run_udp_client.py create mode 100644 examples/protocols/sockets/scripts/run_udp_server.py diff --git a/examples/protocols/sockets/README.md b/examples/protocols/sockets/README.md index 871f909a30..771d642a7c 100644 --- a/examples/protocols/sockets/README.md +++ b/examples/protocols/sockets/README.md @@ -30,10 +30,25 @@ There are many host-side tools which can be used to interact with the UDP/TCP se One command line tool is [netcat](http://netcat.sourceforge.net) which can send and receive many kinds of packets. Note: please replace `192.168.0.167 3333` with desired IPV4/IPV6 address (displayed in monitor console) and port number in the following commands. -In addition to those tools, Python scripts named `pytest_xxx.py` can be found under each example directory. +In addition to those tools, There are some python scripts under `examples/protocols/sockets/scripts`. +And scripts for automated tests named `pytest_xxx.py` can be found under each example directory. -### Python scripts +### Python Scripts Socket Tools + +Python scripts under `examples/protocols/sockets/scripts` could be used to exercise the socket communication. +Command line arguments such as IP version and IP address shall be supplied. Use `python xxxx.py --help` to see how to use these scripts. + +Examples: +```bash +# python run_tcp_client.py --help +python run_tcp_client.py 192.168.1.2 [--port=3333] [--message="Data to ESP"] +python run_tcp_client.py fe80::2%eth0 [--port=3333] [--message="Data to ESP"] +# python run_tcp_server.py --help +python run_tcp_server.py [--port=3333] [--ipv6] +``` + +### Python Scripts For Automated Tests Script named `pytest_xxxx` in the application directory can be used for automated tests. They can also be run locally. Ref: [ESP-IDF Tests with Pytest Guide](https://docs.espressif.com/projects/esp-idf/en/latest/esp32/contribute/esp-idf-tests-with-pytest.html). diff --git a/examples/protocols/sockets/scripts/run_tcp_client.py b/examples/protocols/sockets/scripts/run_tcp_client.py new file mode 100644 index 0000000000..0839721c42 --- /dev/null +++ b/examples/protocols/sockets/scripts/run_tcp_client.py @@ -0,0 +1,50 @@ +# SPDX-FileCopyrightText: 2022 Espressif Systems (Shanghai) CO LTD +# SPDX-License-Identifier: Unlicense OR CC0-1.0 +import argparse +import os +import socket + +DEF_PORT = 3333 +DEF_MESSAGE = 'Data to ESP' + + +def tcp_client(address: str, port: int, payload: str) -> str: + for res in socket.getaddrinfo(address, port, socket.AF_UNSPEC, + socket.SOCK_STREAM, 0, socket.AI_PASSIVE): + family_addr, _, _, _, addr = res + try: + sock = socket.socket(family_addr, socket.SOCK_STREAM) + sock.settimeout(60.0) + except socket.error as msg: + print('Could not create socket') + print(os.strerror(msg.errno)) + raise + try: + sock.connect(addr) + except socket.error as e: + print('Could not open socket: ' + str(e)) + sock.close() + raise + sock.sendall(payload.encode()) + data = sock.recv(1024) + if not data: + return '' + print('Reply : ' + data.decode()) + sock.close() + return data.decode() + + +def main() -> None: + parser = argparse.ArgumentParser() + parser.add_argument('remote_ip', help='TCP server ip address, eg: 192.168.1.1, fe80::2%%eth0') + parser.add_argument('--port', default=DEF_PORT, type=int, help='TCP server port') + parser.add_argument('--message', default=DEF_MESSAGE, help='Message to send to the server.') + args = parser.parse_args() + + print(f'Send message to the server: {args.remote_ip}') + data = tcp_client(args.remote_ip, args.port, args.message) + print(f'Received From server: {data}') + + +if __name__ == '__main__': + main() diff --git a/examples/protocols/sockets/scripts/run_tcp_server.py b/examples/protocols/sockets/scripts/run_tcp_server.py new file mode 100644 index 0000000000..c2cb9a8c7a --- /dev/null +++ b/examples/protocols/sockets/scripts/run_tcp_server.py @@ -0,0 +1,85 @@ +# SPDX-FileCopyrightText: 2022 Espressif Systems (Shanghai) CO LTD +# SPDX-License-Identifier: Unlicense OR CC0-1.0 +import argparse +import socket +from threading import Event, Thread + +DEF_PORT = 3333 + + +class TcpServer(object): + def __init__(self, port, family_addr, persist=False, timeout=60): # type: ignore + self.port = port + self.socket = socket.socket(family_addr, socket.SOCK_STREAM) + self.socket.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1) + self.socket.settimeout(timeout) + self.shutdown = Event() + self.persist = persist + self.family_addr = family_addr + self.server_thread = None + + def __enter__(self): # type: ignore + try: + self.socket.bind(('', self.port)) + except socket.error as e: + print('Bind failed:{}'.format(e)) + raise + self.socket.listen(1) + + print('Starting server on port={} family_addr={}'.format(self.port, self.family_addr)) + self.server_thread = Thread(target=self.run_server) + self.server_thread.start() + return self + + def __exit__(self, exc_type, exc_value, traceback) -> None: # type: ignore + if self.persist: + sock = socket.socket(self.family_addr, socket.SOCK_STREAM) + sock.connect(('localhost', self.port)) + sock.sendall(b'Stop', ) + sock.close() + self.shutdown.set() + self.shutdown.set() + self.server_thread.join() + self.socket.close() + + def run_server(self) -> None: + while not self.shutdown.is_set(): + try: + conn, address = self.socket.accept() # accept new connection + print('Connection from: {}'.format(address)) + conn.setblocking(1) + data = conn.recv(1024) + if not data: + return + data = data.decode() + print('Received data: ' + data) + reply = 'OK: ' + data + conn.send(reply.encode()) + conn.close() + except socket.timeout: + print(f'socket accept timeout ({self.socket.timeout}s)') + except socket.error as e: + print('Running server failed:{}'.format(e)) + raise + if not self.persist: + break + + +def main() -> None: + parser = argparse.ArgumentParser() + parser.add_argument('--port', default=DEF_PORT, type=int, help='TCP server port') + parser.add_argument('--ipv6', action='store_true', help='Create IPv6 server.') + parser.add_argument('--timeout', default=10, type=int, help='socket accept/recv timeout.') + args = parser.parse_args() + + if args.ipv6: + family = socket.AF_INET6 + else: + family = socket.AF_INET + + with TcpServer(args.port, family, persist=True, timeout=args.timeout): + input('Server Running. Press Enter or CTRL-C to exit...\n') + + +if __name__ == '__main__': + main() diff --git a/examples/protocols/sockets/scripts/run_udp_client.py b/examples/protocols/sockets/scripts/run_udp_client.py new file mode 100644 index 0000000000..abb6c30f38 --- /dev/null +++ b/examples/protocols/sockets/scripts/run_udp_client.py @@ -0,0 +1,52 @@ +# SPDX-FileCopyrightText: 2022 Espressif Systems (Shanghai) CO LTD +# SPDX-License-Identifier: Unlicense OR CC0-1.0 +import argparse +import os +import socket + +DEF_PORT = 3333 +DEF_MESSAGE = 'Data to ESP' + + +def udp_client(address: str, port: int, payload: str) -> str: + for res in socket.getaddrinfo(address, port, socket.AF_UNSPEC, + socket.SOCK_DGRAM, 0, socket.AI_PASSIVE): + family_addr, _, _, _, addr = res + try: + sock = socket.socket(family_addr, socket.SOCK_DGRAM) + sock.settimeout(20.0) + except socket.error as msg: + print('Could not create socket') + print(os.strerror(msg.errno)) + raise + try: + sock.sendto(payload.encode(), addr) + reply, addr = sock.recvfrom(128) + if not reply: + return '' + print('Reply[' + addr[0] + ':' + str(addr[1]) + '] - ' + str(reply)) + except socket.timeout: + print('Socket operation timeout') + return '' + except socket.error as msg: + print('Error while sending or receiving data from the socket') + print(os.strerror(msg.errno)) + sock.close() + raise + return reply.decode() + + +def main() -> None: + parser = argparse.ArgumentParser() + parser.add_argument('remote_ip', help='UDP server ip address, eg: 192.168.1.1, fe80::2%%eth0') + parser.add_argument('--port', default=DEF_PORT, type=int, help='UDP server port') + parser.add_argument('--message', default=DEF_MESSAGE, help='Message to send to the server.') + args = parser.parse_args() + + print(f'Send message to the server: {args.remote_ip}') + data = udp_client(args.remote_ip, args.port, args.message) + print(f'Received From server: {data}') + + +if __name__ == '__main__': + main() diff --git a/examples/protocols/sockets/scripts/run_udp_server.py b/examples/protocols/sockets/scripts/run_udp_server.py new file mode 100644 index 0000000000..e01b19d136 --- /dev/null +++ b/examples/protocols/sockets/scripts/run_udp_server.py @@ -0,0 +1,80 @@ +# SPDX-FileCopyrightText: 2022 Espressif Systems (Shanghai) CO LTD +# SPDX-License-Identifier: Unlicense OR CC0-1.0 +import argparse +import socket +from threading import Event, Thread + +DEF_PORT = 3333 + + +class UdpServer: + + def __init__(self, port, family_addr, persist=False, timeout=60): # type: ignore + self.port = port + self.family_addr = family_addr + self.socket = socket.socket(family_addr, socket.SOCK_DGRAM) + self.socket.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1) + self.socket.settimeout(timeout) + self.shutdown = Event() + self.persist = persist + self.server_thread = None + + def __enter__(self): # type: ignore + try: + self.socket.bind(('', self.port)) + except socket.error as e: + print('Bind failed:{}'.format(e)) + raise + + print('Starting server on port={} family_addr={}'.format(self.port, self.family_addr)) + self.server_thread = Thread(target=self.run_server) + self.server_thread.start() + return self + + def __exit__(self, exc_type, exc_value, traceback): # type: ignore + if self.persist: + sock = socket.socket(self.family_addr, socket.SOCK_DGRAM) + sock.sendto(b'Stop', ('localhost', self.port)) + sock.close() + self.shutdown.set() + self.server_thread.join() + self.socket.close() + + def run_server(self) -> None: + while not self.shutdown.is_set(): + try: + data, addr = self.socket.recvfrom(1024) + print(addr) + if not data: + return + data = data.decode() + print('Reply[' + addr[0] + ':' + str(addr[1]) + '] - ' + data) + reply = 'OK: ' + data + self.socket.sendto(reply.encode(), addr) + except socket.timeout: + print(f'socket recvfrom timeout ({self.socket.timeout}s)') + except socket.error as e: + print('Running server failed:{}'.format(e)) + raise + if not self.persist: + break + + +def main() -> None: + parser = argparse.ArgumentParser() + parser.add_argument('--port', default=DEF_PORT, type=int, help='UDP server port') + parser.add_argument('--ipv6', action='store_true', help='Create IPv6 server.') + parser.add_argument('--timeout', default=10, type=int, help='socket recvfrom timeout.') + args = parser.parse_args() + + if args.ipv6: + family = socket.AF_INET6 + else: + family = socket.AF_INET + + with UdpServer(args.port, family, persist=True, timeout=args.timeout): + input('Server Running. Press Enter or CTRL-C to exit...\n') + + +if __name__ == '__main__': + main() diff --git a/examples/protocols/sockets/tcp_client/pytest_tcp_client.py b/examples/protocols/sockets/tcp_client/pytest_tcp_client.py index 25a4dba2e5..8408f5f162 100644 --- a/examples/protocols/sockets/tcp_client/pytest_tcp_client.py +++ b/examples/protocols/sockets/tcp_client/pytest_tcp_client.py @@ -3,71 +3,24 @@ import logging import socket -from threading import Event, Thread import pytest from common_test_methods import (get_env_config_variable, get_host_ip4_by_dest_ip, get_host_ip6_by_dest_ip, get_my_interface_by_dest_ip) from pytest_embedded import Dut +try: + from run_tcp_server import TcpServer +except ImportError: + import os + import sys + sys.path.append(os.path.abspath(os.path.join(os.path.dirname(__file__), '..', 'scripts'))) + from run_tcp_server import TcpServer + + PORT = 3333 -class TcpServer(object): - def __init__(self, port, family_addr, persist=False): # type: ignore - self.port = port - self.socket = socket.socket(family_addr, socket.SOCK_STREAM) - self.socket.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1) - self.socket.settimeout(60.0) - self.shutdown = Event() - self.persist = persist - self.family_addr = family_addr - - def __enter__(self): # type: ignore - try: - self.socket.bind(('', self.port)) - except socket.error as e: - print('Bind failed:{}'.format(e)) - raise - self.socket.listen(1) - - print('Starting server on port={} family_addr={}'.format(self.port, self.family_addr)) - self.server_thread = Thread(target=self.run_server) - self.server_thread.start() - return self - - def __exit__(self, exc_type, exc_value, traceback) -> None: # type: ignore - if self.persist: - sock = socket.socket(self.family_addr, socket.SOCK_STREAM) - sock.connect(('localhost', self.port)) - sock.sendall(b'Stop', ) - sock.close() - self.shutdown.set() - self.shutdown.set() - self.server_thread.join() - self.socket.close() - - def run_server(self) -> None: - while not self.shutdown.is_set(): - try: - conn, address = self.socket.accept() # accept new connection - print('Connection from: {}'.format(address)) - conn.setblocking(1) - data = conn.recv(1024) - if not data: - return - data = data.decode() - print('Received data: ' + data) - reply = 'OK: ' + data - conn.send(reply.encode()) - conn.close() - except socket.error as e: - print('Running server failed:{}'.format(e)) - raise - if not self.persist: - break - - @pytest.mark.esp32 @pytest.mark.wifi_router def test_examples_tcp_client_ipv4(dut: Dut) -> None: diff --git a/examples/protocols/sockets/tcp_server/pytest_tcp_server.py b/examples/protocols/sockets/tcp_server/pytest_tcp_server.py index 52d3d6c779..35af88a523 100644 --- a/examples/protocols/sockets/tcp_server/pytest_tcp_server.py +++ b/examples/protocols/sockets/tcp_server/pytest_tcp_server.py @@ -2,44 +2,25 @@ # SPDX-License-Identifier: Apache-2.0 import logging -import os -import socket import time import pytest from common_test_methods import get_env_config_variable, get_my_interface_by_dest_ip from pytest_embedded import Dut +try: + from run_tcp_client import tcp_client +except ImportError: + import os + import sys + sys.path.append(os.path.abspath(os.path.join(os.path.dirname(__file__), '..', 'scripts'))) + from run_tcp_client import tcp_client + + PORT = 3333 MESSAGE = 'Data to ESP' -def tcp_client(address: str, payload: str) -> str: - for res in socket.getaddrinfo(address, PORT, socket.AF_UNSPEC, - socket.SOCK_STREAM, 0, socket.AI_PASSIVE): - family_addr, socktype, proto, canonname, addr = res - try: - sock = socket.socket(family_addr, socket.SOCK_STREAM) - sock.settimeout(60.0) - except socket.error as msg: - print('Could not create socket') - print(os.strerror(msg.errno)) - raise - try: - sock.connect(addr) - except socket.error as e: - print('Could not open socket: ' + str(e)) - sock.close() - raise - sock.sendall(payload.encode()) - data = sock.recv(1024) - if not data: - return '' - print('Reply : ' + data.decode()) - sock.close() - return data.decode() - - @pytest.mark.esp32 @pytest.mark.wifi_router def test_examples_tcp_server_ipv4(dut: Dut) -> None: @@ -56,7 +37,7 @@ def test_examples_tcp_server_ipv4(dut: Dut) -> None: time.sleep(1) # test IPv4 - received = tcp_client(ipv4, MESSAGE) + received = tcp_client(ipv4, PORT, MESSAGE) if not received == MESSAGE: raise dut.expect(MESSAGE) @@ -82,7 +63,7 @@ def test_examples_tcp_server_ipv6(dut: Dut) -> None: interface = get_my_interface_by_dest_ip(ipv4) # test IPv6 - received = tcp_client('{}%{}'.format(ipv6, interface), MESSAGE) + received = tcp_client('{}%{}'.format(ipv6, interface), PORT, MESSAGE) if not received == MESSAGE: raise dut.expect(MESSAGE) diff --git a/examples/protocols/sockets/udp_client/pytest_udp_client.py b/examples/protocols/sockets/udp_client/pytest_udp_client.py index d0577390e0..fa6d7e4f59 100644 --- a/examples/protocols/sockets/udp_client/pytest_udp_client.py +++ b/examples/protocols/sockets/udp_client/pytest_udp_client.py @@ -3,7 +3,6 @@ import logging import socket -from threading import Event, Thread import pytest from common_test_methods import (get_env_config_variable, get_host_ip4_by_dest_ip, get_host_ip6_by_dest_ip, @@ -11,60 +10,19 @@ from common_test_methods import (get_env_config_variable, get_host_ip4_by_dest_i from pexpect.exceptions import TIMEOUT from pytest_embedded import Dut +try: + from run_udp_server import UdpServer +except ImportError: + import os + import sys + sys.path.append(os.path.abspath(os.path.join(os.path.dirname(__file__), '..', 'scripts'))) + from run_udp_server import UdpServer + + PORT = 3333 MAX_RETRIES = 3 -class UdpServer: - - def __init__(self, port, family_addr, persist=False): # type: ignore - self.port = port - self.family_addr = family_addr - self.socket = socket.socket(family_addr, socket.SOCK_DGRAM) - self.socket.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1) - self.socket.settimeout(60.0) - self.shutdown = Event() - self.persist = persist - - def __enter__(self): # type: ignore - try: - self.socket.bind(('', self.port)) - except socket.error as e: - print('Bind failed:{}'.format(e)) - raise - - print('Starting server on port={} family_addr={}'.format(self.port, self.family_addr)) - self.server_thread = Thread(target=self.run_server) - self.server_thread.start() - return self - - def __exit__(self, exc_type, exc_value, traceback): # type: ignore - if self.persist: - sock = socket.socket(self.family_addr, socket.SOCK_DGRAM) - sock.sendto(b'Stop', ('localhost', self.port)) - sock.close() - self.shutdown.set() - self.server_thread.join() - self.socket.close() - - def run_server(self) -> None: - while not self.shutdown.is_set(): - try: - data, addr = self.socket.recvfrom(1024) - print(addr) - if not data: - return - data = data.decode() - print('Reply[' + addr[0] + ':' + str(addr[1]) + '] - ' + data) - reply = 'OK: ' + data - self.socket.sendto(reply.encode(), addr) - except socket.error as e: - print('Running server failed:{}'.format(e)) - raise - if not self.persist: - break - - @pytest.mark.esp32 @pytest.mark.wifi_router def test_examples_udp_client_ipv4(dut: Dut) -> None: diff --git a/examples/protocols/sockets/udp_server/pytest_udp_server.py b/examples/protocols/sockets/udp_server/pytest_udp_server.py index da9533e766..addea4b883 100644 --- a/examples/protocols/sockets/udp_server/pytest_udp_server.py +++ b/examples/protocols/sockets/udp_server/pytest_udp_server.py @@ -2,46 +2,25 @@ # SPDX-License-Identifier: Apache-2.0 import logging -import os -import socket import pytest from common_test_methods import get_env_config_variable, get_my_interface_by_dest_ip from pytest_embedded import Dut +try: + from run_udp_client import udp_client +except ImportError: + import os + import sys + sys.path.append(os.path.abspath(os.path.join(os.path.dirname(__file__), '..', 'scripts'))) + from run_udp_client import udp_client + + PORT = 3333 MESSAGE = 'Data to ESP' MAX_RETRIES = 3 -def udp_client(address: str, payload: str) -> str: - for res in socket.getaddrinfo(address, PORT, socket.AF_UNSPEC, - socket.SOCK_DGRAM, 0, socket.AI_PASSIVE): - family_addr, socktype, proto, canonname, addr = res - try: - sock = socket.socket(family_addr, socket.SOCK_DGRAM) - sock.settimeout(20.0) - except socket.error as msg: - print('Could not create socket') - print(os.strerror(msg.errno)) - raise - try: - sock.sendto(payload.encode(), addr) - reply, addr = sock.recvfrom(128) - if not reply: - return '' - print('Reply[' + addr[0] + ':' + str(addr[1]) + '] - ' + str(reply)) - except socket.timeout: - print('Socket operation timeout') - return '' - except socket.error as msg: - print('Error while sending or receiving data from the socket') - print(os.strerror(msg.errno)) - sock.close() - raise - return reply.decode() - - @pytest.mark.esp32 @pytest.mark.wifi_router def test_examples_udp_server_ipv4(dut: Dut) -> None: @@ -59,7 +38,7 @@ def test_examples_udp_server_ipv4(dut: Dut) -> None: # test IPv4 for _ in range(MAX_RETRIES): print('Testing UDP on IPv4...') - received = udp_client(ipv4, MESSAGE) + received = udp_client(ipv4, PORT, MESSAGE) if received == MESSAGE: print('OK') break @@ -89,7 +68,7 @@ def test_examples_udp_server_ipv6(dut: Dut) -> None: # test IPv6 for _ in range(MAX_RETRIES): print('Testing UDP on IPv6...') - received = udp_client('{}%{}'.format(ipv6, interface), MESSAGE) + received = udp_client('{}%{}'.format(ipv6, interface), PORT, MESSAGE) if received == MESSAGE: print('OK') break