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 . 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 // Telent port number
#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);
iprintf("Connected to: %I\r\n", GetSocketRemoteAddr(fdAccept));
writestring(fdAccept,
"Welcome to the NetBurner TCP Server\r\n");
fdprintf(fdAccept,
"You are connected to IP Address %I:%d\r\n", GetSocketRemoteAddr(fdAccept),
GetSocketRemotePort(fdAccept) );
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 );
iprintf("Closing client connection: %I\r\n", GetSocketRemoteAddr(fdAccept) );
fdAccept = 0;
}
}
}
}
void UserMain(void * pd)
{
(void *)TCP_LISTEN_PORT,
&TcpServerTaskStack[USER_TASK_STK_SIZE] ,
TcpServerTaskStack,
MAIN_PRIO - 1,
"TCP Server" );
while (1)
{
}
}
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 #defines 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) // TCP port number to listen on
#define maxConnections (10) // Max number of file descriptors/connections
#define readBufferSize (1024) // Connection read buffer size
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;
}
}
}
}
}