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