QUEUE_TRANSFER fnSendBufTCP(
USOCKET TCP_socket,
unsigned char *ptrBuf,
unsigned short usDataLen,
unsigned char ucCommand);
TCP_socket is the number of the TCP socket over which connection the data should be sent
ptrBuf is a pointer to a buffer containing the data to be sent. Unlike the simple TCP transmission using
fnSendTCP();
, where the data is situated after space reserved for a TCP header, this buffer contains only the data to be sent
usDataLen is the length of the TCP payload (the user data)
ucCommand contains user specified flags to control the buffer operation as follows:
- TCP_BUF_SEND - send the largest buffer content possible
- TCP_BUF_NEXT - delete the old data since it has been acked
- TCP_BUF_REP - repeat lost data - this repeats lost buffer plus any extra data that may have become available in the meantime
- TCP_BUF_CHECK - the caller doesn't want to send the data yet but wishes to check that there is enough space for it (requires WAKE_BLOCKED_TCP_BUF)
- TCP_BUF_SEND_REPORT_COPY - returns the amount of byte that were queued
- TCP_BUF_KICK_NEXT - used together with TCP_BUF_NEXT to send following waiting data
The routine returns the number of bytes that were transmitted if a frame was generated. Since buffered operation can cause multiple
frames to be transmitted, this value corresponds to the final transmitted frame, which will be a value of > 0 as long as something was sent.
If the user sets the flag
TCP_BUF_CHECK the return value informs of the amount of space in the output TCP buffer once the defined
number of bytes were added to it. Furthermore, if there is not enough space to add this amount of data the pointer
ptrBuf can be set to the
address of a variable of type
UTASK_TASK with the task to be informed by the event
TX_FREE when the space becomes available
(otherwise use
ptrBuf of value 0).
Due to the nature of the output buffer operation, transmission is not always started immediately and so a return value of 0 doesn't
necessarily indicate an error but instead that no transmission was started. It is however up to the user to ensure that data of lengths longer than
the available space in the output buffer are not attempted since the data length is cut to match and the remaining content discarded.
This function is called when the user has prepared a buffer of data to be transmitted over the TCP connection. The user's buffer is copied to
an output buffer of size
TCP_BUFFER. This buffer is created on HEAP the first time that it is required. From this buffer the function
sends as much content as possible depending on the amount of data presently waiting as well as the amount of data that the remote TCP
partner can accept, respecting the TCP congestion window. When buffered TCP operation is used it is recommended to activate
SUPPORT_PEER_WINDOW
to ensure optimum and correct operation.
The use of the TCP output buffer and TCP windowing allows buffered TCP connections to transmit at higher bulk-data rates than with simple TCP
socket use, which needs to first receive an acknowledge to outstanding data before further data can be sent. Its use is however slightly more complicated
due to the fact that the listener function must do more work to control this operation. Note that the use of a "TELNET-like" socket
is a further possibility of using a buffered TCP socket, by which this additional overhead is controlled by TELNET itself - see
the
TELNET user's guide and
TCP usage thread.
Example
This example shows a simple TCP server sending data when a connection is made to it. It waits until all data has been acked and then immediately closes the connection.
Note that it sends the message using multiple calls to
fnSendBufTCP() to illustrate the output buffer use.
Further note that the application doesn't need to keep a copy of transmitted data in case of regenerations since the TCP output buffer ensures that
all data can be repeated when required.
static const CHAR cFixedMessage1[] = "Hello";
static const CHAR cFixedMessage2[] = ", World!";
static const CHAR cFixedMessage3[] = "!";
static int fnListener(USOCKET Socket, unsigned char ucEvent, unsigned char *ucIp_Data, unsigned short usPortLen)
{
switch (ucEvent) {
case TCP_EVENT_CONNECTED:
{
QUEUE_TRANSFER sent = fnSendBufTCP(Socket, (unsigned char *)cFixedMessage1, (sizeof(cFixedMessage1) - 1), TCP_BUF_NEXT);
sent |= fnSendBufTCP(Socket, (unsigned char *)cFixedMessage2, (sizeof(cFixedMessage2) - 1), TCP_BUF_NEXT);
sent |= fnSendBufTCP(Socket, (unsigned char *)cFixedMessage3, (sizeof(cFixedMessage3) - 1), TCP_BUF_NEXT);
if (sent > 0) {
return APP_SENT_DATA;
}
}
break;
#ifdef SUPPORT_PEER_WINDOW
case TCP_EVENT_PARTIAL_ACK: // possible ack to a part of a transmission received
if (fnSendBufTCP(Socket, 0, usPortLen, TCP_BUF_NEXT)) { // send next buffered (if waiting)
return APP_SENT_DATA;
}
break;
#endif
case TCP_EVENT_REGENERATE:
if (fnSendBufTCP(Socket, 0, 0, TCP_BUF_REP) != 0) { // repeat send buffered
#ifdef SUPPORT_PEER_WINDOW
fnSendBufTCP(Socket, 0, 0, (TCP_BUF_NEXT | TCP_BUF_KICK_NEXT)); // kick off any following data as long as windowing allows it
#endif
return APP_SENT_DATA;
}
break;
case TCP_EVENT_ACK:
if (fnSendBufTCP(Socket, 0, 0, TCP_BUF_NEXT)) { // send next buffered (if waiting)
return APP_SENT_DATA; // mark that data has been transmitted
}
#ifdef WAKE_BLOCKED_TCP_BUF
else {
if (fnSendBufTCP(Socket, 0, 0, TCP_BUF_CHECK) == TCP_BUFFER) { // all buffer content has been sent
fnTCP_close(Socket); // terminate the connection
return APP_REQUEST_CLOSE;
}
}
#endif
default:
break;
}
return APP_ACCEPT;
}
See the following forum thread for additional details about working with TCP sockets:
µTasker forum TCP discussion.
Related functions
fnSendTCP();
fnReleaseTCP_Socket();
fnTCP_Listen();
fnGetTCP_state();
fnReportWindow();
fnTCP_Activity();
fnTCP_close();
Please use the
µTasker forum to ask specific questions.