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