samples: sockets: Add async echo server example
Implements asynchronous TCP echo server using non-blocking sockets and poll, with concurrent connections support. Signed-off-by: Paul Sokolovsky <paul.sokolovsky@linaro.org>
This commit is contained in:
parent
2c2e8b26b4
commit
00e8309f03
6 changed files with 199 additions and 0 deletions
18
samples/net/sockets/echo_async/Makefile
Normal file
18
samples/net/sockets/echo_async/Makefile
Normal file
|
@ -0,0 +1,18 @@
|
||||||
|
# Makefile - asynchronous socket-based echo server
|
||||||
|
|
||||||
|
#
|
||||||
|
# Copyright (c) 2017 Linaro Limited
|
||||||
|
#
|
||||||
|
# SPDX-License-Identifier: Apache-2.0
|
||||||
|
#
|
||||||
|
|
||||||
|
BOARD ?= qemu_x86
|
||||||
|
CONF_FILE ?= prj_$(BOARD).conf
|
||||||
|
|
||||||
|
include $(ZEPHYR_BASE)/Makefile.inc
|
||||||
|
|
||||||
|
ifeq ($(CONFIG_NET_L2_BLUETOOTH), y)
|
||||||
|
QEMU_EXTRA_FLAGS = -serial unix:/tmp/bt-server-bredr
|
||||||
|
else
|
||||||
|
include $(ZEPHYR_BASE)/samples/net/common/Makefile.ipstack
|
||||||
|
endif
|
4
samples/net/sockets/echo_async/Makefile.posix
Normal file
4
samples/net/sockets/echo_async/Makefile.posix
Normal file
|
@ -0,0 +1,4 @@
|
||||||
|
# This makefile builds sample for POSIX system, like Linux
|
||||||
|
|
||||||
|
socket_echo: src/socket_echo.c
|
||||||
|
$(CC) $^ -o $@
|
26
samples/net/sockets/echo_async/prj_qemu_x86.conf
Normal file
26
samples/net/sockets/echo_async/prj_qemu_x86.conf
Normal file
|
@ -0,0 +1,26 @@
|
||||||
|
# General config
|
||||||
|
CONFIG_NEWLIB_LIBC=y
|
||||||
|
|
||||||
|
# Networking config
|
||||||
|
CONFIG_NETWORKING=y
|
||||||
|
CONFIG_NET_IPV4=y
|
||||||
|
CONFIG_NET_IPV6=n
|
||||||
|
CONFIG_NET_TCP=y
|
||||||
|
CONFIG_NET_SOCKETS=y
|
||||||
|
CONFIG_NET_SOCKETS_POSIX_NAMES=y
|
||||||
|
|
||||||
|
# Network driver config
|
||||||
|
CONFIG_NET_SLIP_TAP=y
|
||||||
|
CONFIG_TEST_RANDOM_GENERATOR=y
|
||||||
|
|
||||||
|
# Without CONFIG_NET_BUF_LOG printf() doesn't work
|
||||||
|
CONFIG_NET_BUF_LOG=y
|
||||||
|
|
||||||
|
# Network address config
|
||||||
|
CONFIG_NET_APP_SETTINGS=y
|
||||||
|
CONFIG_NET_APP_MY_IPV4_ADDR="192.0.2.1"
|
||||||
|
CONFIG_NET_APP_PEER_IPV4_ADDR="192.0.2.2"
|
||||||
|
|
||||||
|
# Network debug config
|
||||||
|
#CONFIG_NET_DEBUG_SOCKETS=y
|
||||||
|
CONFIG_SYS_LOG_NET_LEVEL=2
|
8
samples/net/sockets/echo_async/sample.yaml
Normal file
8
samples/net/sockets/echo_async/sample.yaml
Normal file
|
@ -0,0 +1,8 @@
|
||||||
|
sample:
|
||||||
|
description: BSD Sockets API TCP echo server sample using non-blocking sockets
|
||||||
|
name: socket_echo_async
|
||||||
|
tests:
|
||||||
|
- test:
|
||||||
|
build_only: true
|
||||||
|
platform_whitelist: qemu_x86
|
||||||
|
tags: net
|
3
samples/net/sockets/echo_async/src/Makefile
Normal file
3
samples/net/sockets/echo_async/src/Makefile
Normal file
|
@ -0,0 +1,3 @@
|
||||||
|
include $(ZEPHYR_BASE)/samples/net/common/Makefile.common
|
||||||
|
|
||||||
|
obj-y += socket_echo.o
|
140
samples/net/sockets/echo_async/src/socket_echo.c
Normal file
140
samples/net/sockets/echo_async/src/socket_echo.c
Normal file
|
@ -0,0 +1,140 @@
|
||||||
|
/*
|
||||||
|
* Copyright (c) 2017 Linaro Limited
|
||||||
|
*
|
||||||
|
* SPDX-License-Identifier: Apache-2.0
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include <stdio.h>
|
||||||
|
|
||||||
|
#ifndef __ZEPHYR__
|
||||||
|
|
||||||
|
#include <netinet/in.h>
|
||||||
|
#include <sys/socket.h>
|
||||||
|
#include <arpa/inet.h>
|
||||||
|
#include <unistd.h>
|
||||||
|
#include <fcntl.h>
|
||||||
|
#include <poll.h>
|
||||||
|
|
||||||
|
#define init_net()
|
||||||
|
|
||||||
|
#else
|
||||||
|
|
||||||
|
#include <sys/fcntl.h>
|
||||||
|
#include <net/socket.h>
|
||||||
|
#include <kernel.h>
|
||||||
|
#include <net/net_app.h>
|
||||||
|
|
||||||
|
void init_net(void)
|
||||||
|
{
|
||||||
|
int ret = net_app_init("socket_echo", NET_APP_NEED_IPV4, K_SECONDS(3));
|
||||||
|
|
||||||
|
if (ret < 0) {
|
||||||
|
printf("Application init failed\n");
|
||||||
|
k_panic();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/* Number of simultaneous connections will be minus 1 */
|
||||||
|
#define NUM_FDS 4
|
||||||
|
|
||||||
|
struct pollfd pollfds[NUM_FDS];
|
||||||
|
int pollnum;
|
||||||
|
|
||||||
|
static void nonblock(int fd)
|
||||||
|
{
|
||||||
|
int fl = fcntl(fd, F_GETFL, 0);
|
||||||
|
fcntl(fd, F_SETFL, fl | O_NONBLOCK);
|
||||||
|
}
|
||||||
|
|
||||||
|
int pollfds_add(int fd)
|
||||||
|
{
|
||||||
|
int i;
|
||||||
|
if (pollnum < NUM_FDS) {
|
||||||
|
i = pollnum++;
|
||||||
|
} else {
|
||||||
|
for (i = 0; i < NUM_FDS; i++) {
|
||||||
|
if (pollfds[i].fd < 0) {
|
||||||
|
goto found;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
found:
|
||||||
|
pollfds[i].fd = fd;
|
||||||
|
pollfds[i].events = POLLIN;
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
void pollfds_del(int fd)
|
||||||
|
{
|
||||||
|
for (int i = 0; i < pollnum; i++) {
|
||||||
|
if (pollfds[i].fd == fd) {
|
||||||
|
pollfds[i].fd = -1;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
int main(void)
|
||||||
|
{
|
||||||
|
int serv;
|
||||||
|
struct sockaddr_in bind_addr;
|
||||||
|
|
||||||
|
init_net();
|
||||||
|
|
||||||
|
serv = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
|
||||||
|
|
||||||
|
bind_addr.sin_family = AF_INET;
|
||||||
|
bind_addr.sin_addr.s_addr = htonl(INADDR_ANY);
|
||||||
|
bind_addr.sin_port = htons(4242);
|
||||||
|
bind(serv, (struct sockaddr *)&bind_addr, sizeof(bind_addr));
|
||||||
|
|
||||||
|
nonblock(serv);
|
||||||
|
pollfds_add(serv);
|
||||||
|
|
||||||
|
listen(serv, 5);
|
||||||
|
|
||||||
|
while (1) {
|
||||||
|
struct sockaddr_in client_addr;
|
||||||
|
socklen_t client_addr_len = sizeof(client_addr);
|
||||||
|
char addr_str[32];
|
||||||
|
|
||||||
|
poll(pollfds, pollnum, -1);
|
||||||
|
for (int i = 0; i < pollnum; i++) {
|
||||||
|
if (!(pollfds[i].revents & POLLIN)) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
int fd = pollfds[i].fd;
|
||||||
|
if (fd == serv) {
|
||||||
|
int client = accept(serv, (struct sockaddr *)&client_addr,
|
||||||
|
&client_addr_len);
|
||||||
|
inet_ntop(client_addr.sin_family, &client_addr.sin_addr,
|
||||||
|
addr_str, sizeof(addr_str));
|
||||||
|
printf("Connection from %s fd=%d\n", addr_str, client);
|
||||||
|
if (pollfds_add(client) < 0) {
|
||||||
|
static char msg[] = "Too many connections\n";
|
||||||
|
send(client, msg, sizeof(msg) - 1, 0);
|
||||||
|
close(client);
|
||||||
|
} else {
|
||||||
|
nonblock(client);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
char buf[128];
|
||||||
|
int len = recv(fd, buf, sizeof(buf), 0);
|
||||||
|
if (len == 0) {
|
||||||
|
pollfds_del(fd);
|
||||||
|
close(fd);
|
||||||
|
printf("Connection fd=%d closed\n", fd);
|
||||||
|
} else {
|
||||||
|
/* We assume this won't be short write, d'oh */
|
||||||
|
send(fd, buf, len, 0);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
Loading…
Add table
Add a link
Reference in a new issue