Example1: tcpecho_client

Description

This example implements a simple TCP echo client.  It connects to a 
TCP echo server, periodically sends echo requests and then validates 
that the data in the received response exactly matches the data sent. 
If it is linked into the DEBUG version of embTCP and is run on a 
system with a console, it will print status messages.  Otherwise, you 
will only be able to see what there are doing by looking at a 
WireShark trace.

The initialization routine for all of the embTCP example programs is 
called example_init. For this reason, you can only link with one 
example at a time on an embTCP system.  When example_init is called, 
it will create and initialize a task and begin running.

Example 1 was intended as a simple example of a TCP client program.  
It is not a robust TCP echo client. It starts immediately once it 
has been initialized, sends 10 echo requests of 255 bytes each at a 
fixed rate, listens for responses and then exits by deleting its task.  

Note:  The target TCP echo server needs to be running when 
tcpecho_client is initialized. Once initialized, the tcpecho_client  
immediately attempts to connect.  If the server is not running, the 
connection request will timeout and the task will return to its task 
loop where it will be deleted.  

Configuration Parameters

You must change the 'svraddrstr' parameter to be the IP address of a 
TCP echo server. The other parameters should not be changed for the 
initial tests.

Most Windows and Linux systems have a running TCP echo server that 
will respond to echo requests. You could also send the requests to 
another system running embTCP with example 2, a TCP echo server. 

Code Walkthrough

The TCPCLIENT structure holds the input and output buffers and the 
variables that are maintained across all of the echo requests.  

The next section defines the TCP task info structure and calls 
TK_CREATE to create the TCP echo client task.

The function example_init() creates the tcp echo client task.
Task body tk_tc_echo waits until the network is ready 
and then calls tec_init.  Tec_init() calls the main loop of the echo 
client. Most tasks run for the life of the system.  However, the TCP 
echo task runs only long enough to send the configured number of echo 
requests.  When it returns to the task loop, the task is deleted.      

The tec_init() routine does the following:
* Converts the IP address string to a binary number
* Allocates a TCPCLIENT structure.
* Sets the tec->nextsend to the current time so that an echo request 
  will be sent as soon as we are ready.
* Fills out the address structure for the remote server.
* Opens a socket and calls t_connect().  The connect routine blocks 
  and will not return until either the connection has been made or it 
  times out. Note:  If the server is not running, when the t_connect() 
  times out it will print a connection error message and return to the 
  task loop where the task will be deleted.
* Calls  t_setsockopt() to put the socket in non-blocking mode.
* Calls tcp_send_an_echo to send the first echo request.  
* If there is no error, it calls tcecho_loop() to send the rest of the 
  requests.

The tcp_send_an_echo() routine does the following:
* Fills each byte of the outgoing buffer with values incrementing from 0 
  to ECHODFTLEN - 1.  
* The tcp_send_an_echo routine will loop until all bytes in the request 
  are sent. If the system is congested, then t_send may return EWOULDBLOCK 
  or a t_send it may send only part of the data. 
* If the t_send call blocks, we call taskYIELD() to let other tasks run. 
  On return we continue in the send loop.  
* If t_send return a positive value, then we add that value to the number 
  of bytes sent.  If only part of the data was sent, we advance the buffer 
  pointer and reduce bytestosend by the number of bytes sent.
* Once the full echo request has been sent, we increment the statistics 
  variables and set the timer for when the next request should be sent.

The tcecho_loop does the following:
* Goes into a loop.  The "for(;;)" expression means it will only exit 
  when "return" is called.  
* Calls t_select() to see if there are any responses ready to be read.  
  It sets the timeout value for t_select to 200 ms.  This allows it to 
  test to see if it is time to send another echo request.
* Calls t_recv() to read any available echo response.  
* If the return from t_recv ('len') is < 0 it calls t_errno to determine 
  the error number. If the return is anything other the EWOULDBLOCK, it 
  will print an error message and call tcp_client_close.
* If 'len' is greater than 0, then we read an echo response.  Note if the 
  system were congested, the full response may not be read in a single 
  t_recv() call.  
* Loops to validate each byte of the received data.  The variable 
  'tec->nextrcvbyte' hold the value of the next expected byte.  When 
  tec->nextrcvbyte increments to ECHODFTLEN, it is reset to 0.  If we find 
  an unexpected character, we print and error message and close the 
  connection.
* After a successful read,  the number of replies is incremented and 'len' 
  is added to the cumulative total number of bytes read.
* When the number of requests sent equals the configured number of requests 
  to send, tcp echo has completed.  It calls tcp_client_close() to clean up 
  and returns.
* Otherwise, if it is time to send another request, it calls tcp_send_an_echo.

When the TCP echo client is ready to close for any reason, it calls 
tcp_client_close() to clean up the connection.  The tcp_client_close() 
routine does the following:
* If there is a valid socket, it closes it.
* If there is an allocated TCPCLIENT structure, it frees it.


