fnSendBufTCP()

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:


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.