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:
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>
const char *AppName = "Simple TCP Server Example";
#define TCP_LISTEN_PORT 23
#define RX_BUFSIZE (4096)
char RXBuffer[RX_BUFSIZE];
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,
"TCP Server" );
while (1)
{
}
}
Used to hold and manipulate IPv4 and IPv6 addresses in dual stack mode.
Definition ipv6_addr.h:41
NetBurner functions to printf to a file descriptor.
#define TICKS_PER_SECOND
System clock ticks per second.
Definition nbrtos/include/constants.h:41
#define MAIN_PRIO
Recommend UserMain priority.
Definition nbrtos/include/constants.h:97
int fdprintf(int fc, const char *format,...)
printf to a file descriptor
int read(int fd, char *buf, int nbytes)
Read data from a file descriptor (fd).
int close(int fd)
Close the specified file descriptor and free the associated resources.
int writestring(int fd, const char *str)
Write a null terminated ascii string to the stream associated with a file descriptor (fd)....
uint8_t OSTaskCreatewName(void(*task)(void *dptr), void *data, void *pstktop, void *pstkbot, uint8_t prio, const char *name)
Create 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:1732
uint16_t GetSocketRemotePort(int fd)
Returns the port number of the remote host associated with the connection.
int accept(int listening_socket, IPADDR *address, uint16_t *port, uint16_t timeout)
Accept an incoming connection from a listening socket.
IPADDR GetSocketRemoteAddr(int fd)
Returns the IP address of the remote host associated with the specified file descriptor.
Definition tcp.h:638
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:349
void init()
System initialization. Ideally called at the beginning of all applications, since the easiest Recover...
NetBurner System Initialization Header File.
NetBurner I/O System Library API.
#define USER_TASK_STK_SIZE
Definition nbrtos/include/constants.h:131
NetBurner Real-Time Operating System (NBRTOS) 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 <constants.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;
}
}
}
}
}
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...
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...
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)...
void FD_ZERO(fd_set *pfds)
Clear (set to 0) a fd_set (file descriptor set) so no file descriptors (fds) are selected.
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.
NetBurner System Functions.