A TCP server is basically an application that creates a listening socket, and then listens on the socket for incoming connections. When an incoming connection request is received, tit must be accepted before communication can begin. A web server is an example of a TCP server. A web server listens on port number 80 for incoming connections. Once a connection is established, the web browser sends a GET request to the web server, which then sends the requested information and terminates the connection.
To connect to a TCP server you must specify a port number. A port number is a 16-bit value. Since you must know the port number before connecting, many port numbers have been defined for common protocols, and are called well-known port numbers. Some of these values are shown below:
FTP 21
Telnet 23
SMTP 25
DNS 53
TFTP 69
HTTP 80
POP3 110
NTP 123
NetBurner TCP Server Basics
When creating a TCP server with the NetBurner you will use the following functions:
listen()
: Open a listening socket on a specific port number
accept()
: Accept a connection request on a listening port
- I/O functions to send and receive data such as
read(), write(), fdprintf(), writestring()
, etc.
close()
: Close a network socket
Simple TCP Server Example
This example is located in \nburn\examples\TCP
. It will listen on port 23 for incoming connections, send a sign on message to the client when a connection is made, and display all received data to the debug serial port. A telnet program on a host PC can be used to connect to the server.
#include <predef.h>
#include <stdio.h>
#include <fdprintf.h>
const char *AppName = "Simple TCP Server Example";
#define TCP_LISTEN_PORT 23
#define RX_BUFSIZE (4096)
char RXBuffer[RX_BUFSIZE];
uint32_t TcpServerTaskStack[USER_TASK_STK_SIZE];
void TcpServerTask(void * pd)
{
int listenPort = (int) pd;
int fdListen =
listen(INADDR_ANY, listenPort, 5);
if (fdListen > 0)
{
uint16_t clientPort;
while(1)
{
iprintf( "Waiting for connection on port %d...\n", listenPort );
int32_t fdAccept =
accept(fdListen, &clientAddress, &clientPort, 0);
writestring(fdAccept,
"Welcome to the NetBurner TCP Server\r\n");
while (fdAccept > 0)
{
int n = 0;
do
{
n =
read( fdAccept, RXBuffer, RX_BUFSIZE );
RXBuffer[n] = '\0';
iprintf( "Read %d bytes: %s\n", n, RXBuffer );
} while ( n > 0 );
fdAccept = 0;
}
}
}
}
void UserMain(void * pd)
{
(void *)TCP_LISTEN_PORT,
&TcpServerTaskStack[USER_TASK_STK_SIZE] ,
TcpServerTaskStack,
MAIN_PRIO - 1,
"TCP Server" );
while (1)
{
}
}
Used to hold and manipulate IPv4 and IPv6 addresses in dual stack mode.
Definition: ipv6_addr.h:40
int read(int fd, char *buf, int nbytes)
Read data from a file descriptor (fd). This function will block forever until at least one byte is av...
Definition: fileio.cpp:269
int close(int fd)
Close the specified file descriptor and free the associated resources.
Definition: fileio.cpp:102
int writestring(int fd, const char *str)
Write a null terminated ascii string to the stream associated with a file descriptor (fd)....
Definition: iosys.cpp:395
uint8_t OSTaskCreatewName(void(*task)(void *dptr), void *data, void *pstktop, void *pstkbot, uint8_t prio, const char *name)
This function creates a new task.
void OSTimeDly(uint32_t to_count)
Delay the task until the specified value of the system timer ticks. The number of system ticks per se...
Definition: nbrtos.h:1451
uint16_t GetSocketRemotePort(int fd)
Returns the port number of the remote host associated with the connection.
Definition: tcp.cpp:1971
int accept(int listening_socket, IPADDR *address, uint16_t *port, uint16_t timeout)
Accept an incoming connection from a listening socket.
Definition: tcp.cpp:1013
IPADDR GetSocketRemoteAddr(int fd)
Returns the IP address of the remote host associated with the specified file descriptor.
Definition: tcp.h:536
int listen(const IPADDR &addr, uint16_t port, uint8_t maxpend=5)
Listen for incoming connections on the specified network interface IP address.
Definition: tcp.h:247
void init()
System initialization. Normally called at the beginning of all applications.
Definition: init.cpp:27
NetBurner System Initialization Header File.
NetBurner I/O System Library API.
NetBurner Real-Time Operating System API.
This is an extremely simple example designed to illustrate how the accept()
and listen()
calls can be used. It only listens to a single port number, and processes a single connection at a time. Any information sent from the Client will be displayed in the MTTTY window. The application does not have the capability to terminate the incoming connection.
There are #define
options for the TCP listen port number and the incoming TCP buffer storage array size. RXBuffer[]
is then declared and will hold the received data. The listen()
function call sets up a socket to listen for an incoming connection from any IP address on port number 23, the telnet port number.
If the listen()
succeeds in creating a listening socket, we then enter a second while loop. The application will block at the accept()
function call until an incoming connection request is received, such as when the telnet program on a PC attempts to connect. When the connection is established, the accept()
function returns and the sign-on message is sent to the telnet application.
We now enter the do loop: while(n > 0)
. The read()
function will block until data is received or an error occurs such as the client terminating the connection. When data is sent from the telnet application, the read()
function will return with the data in the RXBuffer[]
array. The application will stay in this while loop until the connection is terminated by the telnet client (or you reset the NetBurner device). If the connection is broken by the telnet client, the application will then loop back to the accept()
function call and wait for another incoming connection.
Advanced TCP Server for Multiple Connections
In the previous example the TCP server processed only a single incoming connection. The select()
function has the ability to pend on multiple file descriptors, which can used for TCP or serial connections. The example below demonstrates how the TCP Server can be written using select()
.
#include <predef.h>
#include <utils.h>
#include <stdio.h>
#include <ctype.h>
#include <ipshow.h>
const char* AppName = "TCP Multiple Sockets Example";
#define listenPort (23)
#define maxConnections (10)
#define readBufferSize (1024)
int32_t fdArray[maxConnections];
void UserMain( void* pd )
{
showIpAddresses();
int32_t fdListen =
listen( INADDR_ANY, listenPort, 5 );
iprintf( "Listening for incoming connections on port %d\r\n", listenPort );
while ( 1 )
{
fd_set readFds;
fd_set errorFds;
for ( int32_t i = 0; i < maxConnections; i++ )
{
if ( fdArray[i] )
{
FD_SET( fdArray[i], &readFds );
FD_SET( fdArray[i], &errorFds );
}
}
FD_SET( fdListen, &errorFds );
select( FD_SETSIZE, &readFds, ( fd_set * )0, &errorFds, 0 );
{
uint16_t clientPort;
int fdAccept =
accept( fdListen, &clientIp, &clientPort, 0 );
if ( fdAccept > 0 )
{
for ( int32_t i = 0; i < maxConnections; i++ )
{
if ( fdArray[i] == 0 )
{
fdArray[i] = fdAccept;
writestring( fdAccept,
"Welcome to the NetBurner Multi-Socket TCP Server! 'Q' to quit." );
iprintf( "Added connection on fd[%d] = %d, Client IP: %I:%d\r\n",
fdAccept = 0;
break;
}
}
}
if ( fdAccept )
{
writestring( fdAccept,
"I am sorry, but the server is full\r\n" );
iprintf("Server Full\r\n");
}
}
{
fdListen =
listen( INADDR_ANY, listenPort, 5 );
}
for ( int32_t i = 0; i < maxConnections; i++ )
{
if ( fdArray[i] )
{
{
char buffer[readBufferSize];
int rv =
read( fdArray[i], buffer, readBufferSize );
if ( rv > 0 )
{
buffer[rv] = 0;
if ( buffer[0] == 'Q' )
{
iprintf( "Closing connection fd[%d]\r\n", i );
fdArray[i] = 0;
}
else
{
iprintf( "Read \"%s\" from fd[%d]\r\n", buffer, i );
sniprintf( buffer, readBufferSize, "Server read %d byte(s)\r\n", rv );
}
}
else
{
iprintf( "Read Error on fd[%d]\r\n", fdArray[i] );
FD_SET( fdArray[i], &errorFds );
}
}
if (
FD_ISSET( fdArray[i], &errorFds ) )
{
iprintf( "Error on fd[%d], closing connection\r\n", i );
fdArray[i] = 0;
}
}
}
}
}
NetBurner System Constants.
int FD_ISSET(int fd, fd_set *pfds)
A fd_set (file descriptor set) holds a set of file descriptors (fds). This function checks whether or...
Definition: iosys.cpp:252
void FD_SET(int fd, fd_set *pfds)
A fd_set (file descriptor set) holds a set of file descriptors (fds). This function sets or adds a sp...
Definition: iosys.cpp:242
int select(int nfds, fd_set *readfds, fd_set *writefds, fd_set *errorfds, unsigned long timeout)
Wait for events to occur on one or more I/O resources associated with a set of file descriptors (fds)...
Definition: iosys.cpp:369
void FD_ZERO(fd_set *pfds)
Clear (set to 0) a fd_set (file descriptor set) so no file descriptors (fds) are selected.
Definition: iosys.cpp:221
bool WaitForActiveNetwork(uint32_t ticks_to_wait=120 *TICKS_PER_SECOND, int interface=-1)
Wait for an active network connection on at least one interface.
Definition: dhcpc.cpp:1554
NetBurner System Functions.