mirror of
https://github.com/RIOT-OS/RIOT.git
synced 2024-12-29 04:50:03 +01:00
Merge pull request #16739 from benpicco/examples/tcp_echo
examples: add TCP echo server & client from documentation
This commit is contained in:
commit
1976e68177
41
examples/sock_tcp_echo/Makefile
Normal file
41
examples/sock_tcp_echo/Makefile
Normal file
@ -0,0 +1,41 @@
|
|||||||
|
# name of your application
|
||||||
|
APPLICATION = sock_tcp_echo
|
||||||
|
|
||||||
|
# If no BOARD is found in the environment, use this default:
|
||||||
|
BOARD ?= native
|
||||||
|
|
||||||
|
# default to using GNRC
|
||||||
|
LWIP ?= 0
|
||||||
|
|
||||||
|
# This has to be the absolute path to the RIOT base directory:
|
||||||
|
RIOTBASE ?= $(CURDIR)/../..
|
||||||
|
|
||||||
|
USEMODULE += sock_tcp
|
||||||
|
USEMODULE += netdev_default
|
||||||
|
|
||||||
|
USEMODULE += shell
|
||||||
|
USEMODULE += shell_cmds_default
|
||||||
|
USEMODULE += ps
|
||||||
|
USEMODULE += netutils
|
||||||
|
|
||||||
|
ifeq (1, $(LWIP))
|
||||||
|
USEMODULE += ipv6_addr
|
||||||
|
USEMODULE += lwip_ipv6_autoconfig
|
||||||
|
USEMODULE += lwip_netdev
|
||||||
|
else
|
||||||
|
USEMODULE += auto_init_gnrc_netif
|
||||||
|
USEMODULE += gnrc_ipv6_default
|
||||||
|
# we want to be able to open two sockets
|
||||||
|
CFLAGS += -DCONFIG_GNRC_TCP_RCV_BUFFERS=2
|
||||||
|
endif
|
||||||
|
|
||||||
|
# Comment this out to disable code in RIOT that does safety checking
|
||||||
|
# which is not needed in a production environment but helps in the
|
||||||
|
# development process:
|
||||||
|
DEVELHELP ?= 1
|
||||||
|
|
||||||
|
# As there is a .config we want to explicitly disable Kconfig by setting
|
||||||
|
# the variable to empty
|
||||||
|
SHOULD_RUN_KCONFIG ?=
|
||||||
|
|
||||||
|
include $(RIOTBASE)/Makefile.include
|
42
examples/sock_tcp_echo/Makefile.ci
Normal file
42
examples/sock_tcp_echo/Makefile.ci
Normal file
@ -0,0 +1,42 @@
|
|||||||
|
BOARD_INSUFFICIENT_MEMORY := \
|
||||||
|
arduino-duemilanove \
|
||||||
|
arduino-leonardo \
|
||||||
|
arduino-mega2560 \
|
||||||
|
arduino-nano \
|
||||||
|
arduino-uno \
|
||||||
|
atmega328p \
|
||||||
|
atmega328p-xplained-mini \
|
||||||
|
atmega8 \
|
||||||
|
atxmega-a3bu-xplained \
|
||||||
|
bluepill-stm32f030c8 \
|
||||||
|
derfmega128 \
|
||||||
|
i-nucleo-lrwan1 \
|
||||||
|
im880b \
|
||||||
|
m1284p \
|
||||||
|
microduino-corerf \
|
||||||
|
msb-430 \
|
||||||
|
msb-430h \
|
||||||
|
nucleo-c031c6 \
|
||||||
|
nucleo-f030r8 \
|
||||||
|
nucleo-f031k6 \
|
||||||
|
nucleo-f042k6 \
|
||||||
|
nucleo-f303k8 \
|
||||||
|
nucleo-f334r8 \
|
||||||
|
nucleo-l011k4 \
|
||||||
|
nucleo-l031k6 \
|
||||||
|
nucleo-l053r8 \
|
||||||
|
olimex-msp430-h1611 \
|
||||||
|
olimex-msp430-h2618 \
|
||||||
|
samd10-xmini \
|
||||||
|
slstk3400a \
|
||||||
|
stk3200 \
|
||||||
|
stm32f030f4-demo \
|
||||||
|
stm32f0discovery \
|
||||||
|
stm32g0316-disco \
|
||||||
|
stm32l0538-disco \
|
||||||
|
telosb \
|
||||||
|
waspmote-pro \
|
||||||
|
weact-g030f6 \
|
||||||
|
z1 \
|
||||||
|
zigduino \
|
||||||
|
#
|
20
examples/sock_tcp_echo/README.md
Normal file
20
examples/sock_tcp_echo/README.md
Normal file
@ -0,0 +1,20 @@
|
|||||||
|
TCP Echo Server / Client
|
||||||
|
========================
|
||||||
|
|
||||||
|
This is a simple TCP echo server / client that uses the SOCK API.
|
||||||
|
It can make use of both the GNRC and the LWIP network stack.
|
||||||
|
The default is GNRC, to chose LWIP set `LWIP=1` when compiling the example.
|
||||||
|
|
||||||
|
## Echo Server
|
||||||
|
|
||||||
|
The echo server will echo back any data that it receives.
|
||||||
|
To start the echo server on port 12345 run
|
||||||
|
|
||||||
|
listen 12345
|
||||||
|
|
||||||
|
## Echo Client
|
||||||
|
|
||||||
|
The echo client will connect to a server, send some data and wait for the reply.
|
||||||
|
To send data with the echo client to a server running on 2001:db8::1 run
|
||||||
|
|
||||||
|
send 2001:db8::1 12345 some data
|
163
examples/sock_tcp_echo/main.c
Normal file
163
examples/sock_tcp_echo/main.c
Normal file
@ -0,0 +1,163 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (C) 2016 Freie Universität Berlin
|
||||||
|
*
|
||||||
|
* This file is subject to the terms and conditions of the GNU Lesser
|
||||||
|
* General Public License v2.1. See the file LICENSE in the top level
|
||||||
|
* directory for more details.
|
||||||
|
*/
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @{
|
||||||
|
*
|
||||||
|
* @file
|
||||||
|
* @author Martine Lenders <m.lenders@fu-berlin.de>
|
||||||
|
* @author Benjamin Valentin <benjamin.valentin@ml-pa.com>
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include <stdio.h>
|
||||||
|
|
||||||
|
#include "net/sock/tcp.h"
|
||||||
|
#include "net/ipv6/addr.h"
|
||||||
|
#include "net/utils.h"
|
||||||
|
#include "shell.h"
|
||||||
|
|
||||||
|
#define SOCK_QUEUE_LEN 1
|
||||||
|
|
||||||
|
static char _echo_server_stack[THREAD_STACKSIZE_DEFAULT];
|
||||||
|
|
||||||
|
static int _cmd_tcp_send(int argc, char **argv)
|
||||||
|
{
|
||||||
|
int res;
|
||||||
|
sock_tcp_t sock;
|
||||||
|
sock_tcp_ep_t remote;
|
||||||
|
netif_t *netif;
|
||||||
|
char buf[128];
|
||||||
|
|
||||||
|
if (argc < 4) {
|
||||||
|
printf("usage: %s <addr> <port> <data>\n", argv[0]);
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (netutils_get_ipv6((ipv6_addr_t *)&remote.addr,
|
||||||
|
&netif, argv[1]) < 0) {
|
||||||
|
printf("can't resolve %s\n", argv[1]);
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
remote.family = AF_INET6;
|
||||||
|
remote.netif = netif ? netif_get_id(netif) : 0;
|
||||||
|
remote.port = atoi(argv[2]);
|
||||||
|
|
||||||
|
if (remote.port == 0) {
|
||||||
|
printf("Invalid port: %s\n", argv[2]);
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
if ((res = sock_tcp_connect(&sock, &remote, 0, 0)) < 0) {
|
||||||
|
printf("Error connecting sock: %s\n", strerror(-res));
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
if ((res = sock_tcp_write(&sock, argv[3], strlen(argv[3]))) < 0) {
|
||||||
|
printf("Errored on write: %s\n", strerror(-res));
|
||||||
|
goto error;
|
||||||
|
}
|
||||||
|
|
||||||
|
if ((res = sock_tcp_read(&sock, &buf, sizeof(buf), SOCK_NO_TIMEOUT)) <= 0) {
|
||||||
|
printf("Disconnected: %s\n", strerror(-res));
|
||||||
|
goto error;
|
||||||
|
}
|
||||||
|
|
||||||
|
buf[res] = 0;
|
||||||
|
printf("Read: \"%s\"\n", buf);
|
||||||
|
|
||||||
|
error:
|
||||||
|
sock_tcp_disconnect(&sock);
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
SHELL_COMMAND(send, "send data over TCP", _cmd_tcp_send);
|
||||||
|
|
||||||
|
static void *_run_echo_server(void *ctx)
|
||||||
|
{
|
||||||
|
sock_tcp_t sock_queue[SOCK_QUEUE_LEN];
|
||||||
|
char buf[128];
|
||||||
|
uint16_t port = (uintptr_t)ctx;
|
||||||
|
|
||||||
|
sock_tcp_ep_t local = SOCK_IPV6_EP_ANY;
|
||||||
|
sock_tcp_queue_t queue;
|
||||||
|
local.port = port;
|
||||||
|
if (sock_tcp_listen(&queue, &local, sock_queue, SOCK_QUEUE_LEN, 0) < 0) {
|
||||||
|
puts("Error creating listening queue");
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
printf("Listening on port %u\n", port);
|
||||||
|
while (1) {
|
||||||
|
sock_tcp_t *sock;
|
||||||
|
if (sock_tcp_accept(&queue, &sock, SOCK_NO_TIMEOUT) < 0) {
|
||||||
|
puts("Error accepting new sock");
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
int res = 0;
|
||||||
|
puts("Reading data");
|
||||||
|
while (res >= 0) {
|
||||||
|
res = sock_tcp_read(sock, &buf, sizeof(buf), SOCK_NO_TIMEOUT);
|
||||||
|
if (res <= 0) {
|
||||||
|
printf("Disconnected: %s\n", strerror(-res));
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
buf[res] = 0;
|
||||||
|
printf("Read: \"%s\"\n", buf);
|
||||||
|
if ((res = sock_tcp_write(sock, &buf, res)) < 0) {
|
||||||
|
printf("Errored on write: %s\n", strerror(-res));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
sock_tcp_disconnect(sock);
|
||||||
|
}
|
||||||
|
sock_tcp_stop_listen(&queue);
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int _cmd_tcp_listen(int argc, char **argv)
|
||||||
|
{
|
||||||
|
static kernel_pid_t pid;
|
||||||
|
uint16_t port;
|
||||||
|
|
||||||
|
if (argc < 2) {
|
||||||
|
printf("usage: %s <port>\n", argv[0]);
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (pid) {
|
||||||
|
puts("server already running");
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
port = atoi(argv[1]);
|
||||||
|
|
||||||
|
if (port == 0) {
|
||||||
|
printf("invalid port: %s\n", argv[1]);
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
pid = thread_create(_echo_server_stack, sizeof(_echo_server_stack),
|
||||||
|
THREAD_PRIORITY_MAIN - 1, 0,
|
||||||
|
_run_echo_server, (void*)(uintptr_t)port, "echo_server");
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
SHELL_COMMAND(listen, "start echo server", _cmd_tcp_listen);
|
||||||
|
|
||||||
|
int main(void)
|
||||||
|
{
|
||||||
|
puts("RIOT TCP client example application");
|
||||||
|
|
||||||
|
/* start shell */
|
||||||
|
puts("All up, running the shell now");
|
||||||
|
char line_buf[SHELL_DEFAULT_BUFSIZE];
|
||||||
|
shell_run(NULL, line_buf, SHELL_DEFAULT_BUFSIZE);
|
||||||
|
|
||||||
|
/* should be never reached */
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
/** @} */
|
Loading…
Reference in New Issue
Block a user