Stream Socket (TCP)

The figure below uses the Micrium proprietary socket API function calls. A similar example could be written using the BSD socket API.

Typically, after a TCP server starts, TCP clients can connect and send requests to the server. A TCP server waits until client connections arrive and then creates a dedicated TCP socket connection to process the client’s requests and reply back to the client (if necessary). This continues until either the client or the server closes the dedicated client-server connection. Also while handling multiple, simultaneous client-server connections, the TCP server can wait for new client-server connections

Figure - µC/TCP-IP Socket calls used in a typical TCP client-server application


Stream Server (TCP Server)

This example presents a very basic client-server application over a TCP connection. The server presented is simply waits for a connection and send the string ‘Hello World!’. See TCPIP API Reference Core for a list of all µC/TCP-IP socket API functions.


Listing - Stream Server
#define  TCP_SERVER_PORT                   10000
#define  TCP_SERVER_CONN_Q_SIZE                1
#define  TCP_SERVER_TX_STR         "Hello World!"
 
CPU_BOOLEAN  TestTCPServer (void)
{
    NET_SOCK_ID         sock_listen;
    NET_SOCK_ID         sock_req;
    NET_SOCK_ADDR_IP    server_sock_addr_ip;
    NET_SOCK_ADDR_LEN   server_sock_addr_ip_size; 
    NET_SOCK_ADDR_IP    client_sock_addr_ip;
    NET_SOCK_ADDR_LEN   client_sock_addr_ip_size; 
    CPU_BOOLEAN         attempt_conn;
    CPU_CHAR           *pbuf;
    CPU_INT16S          buf_len;
    NET_SOCK_RTN_CODE   tx_size;
    NET_ERR             err;
    pbuf    = TCP_SERVER_TX_STR;
    buf_len = Str_Len(TCP_SERVER_TX_STR);
    
    
    sock_listen = NetSock_Open( NET_SOCK_ADDR_FAMILY_IP_V4,                                (1)
                                NET_SOCK_TYPE_STREAM,
                                NET_SOCK_PROTOCOL_TCP,
                               &err);
    if (err != NET_SOCK_ERR_NONE) {
        return (DEF_FALSE);
    }
 
 
    server_sock_addr_ip_size = sizeof(server_sock_addr_ip);                                (2)
    Mem_Clr((void     *)&server_sock_addr_ip,
            (CPU_SIZE_T) server_sock_addr_ip_size);
    server_sock_addr_ip.AddrFamily = NET_SOCK_ADDR_FAMILY_IP_V4;
    server_sock_addr_ip.Addr       = NET_UTIL_HOST_TO_NET_32(NET_SOCK_ADDR_IP_WILD_CARD); 
    server_sock_addr_ip.Port       = NET_UTIL_HOST_TO_NET_16(TCP_SERVER_PORT);
    NetSock_Bind((NET_SOCK_ID ) sock_listen,                                               (3)
                 (NET_SOCK_ADDR *)&server_sock_addr_ip,
                 (NET_SOCK_ADDR_LEN) NET_SOCK_ADDR_SIZE,
                 (NET_ERR *)&err);
    if (err != NET_SOCK_ERR_NONE) {
        NetSock_Close(sock_listen, &err);
        return (DEF_FALSE);
}
 
    NetSock_Listen( sock_listen,                                                           (4)
                    TCP_SERVER_CONN_Q_SIZE,
                   &err);
    if (err != NET_SOCK_ERR_NONE) {
        NetSock_Close(sock_listen, &err);
        return (DEF_FALSE);
    }
 
    do {
        client_sock_addr_ip_size = sizeof(client_sock_addr_ip);
 
         sock_req = NetSock_Accept((NET_SOCK_ID ) sock_listen,                             (5)
                                  (NET_SOCK_ADDR *)&client_sock_addr_ip,
                                  (NET_SOCK_ADDR_LEN *)&client_sock_addr_ip_size,
                                  (NET_ERR *)&err);
        switch (err) {
            case NET_SOCK_ERR_NONE:
                attempt_conn = DEF_NO;
                break;
            case NET_ERR_INIT_INCOMPLETE:
            case NET_SOCK_ERR_NULL_PTR:
            case NET_SOCK_ERR_NONE_AVAIL:
            case NET_SOCK_ERR_CONN_ACCEPT_Q_NONE_AVAIL:
            case NET_SOCK_ERR_CONN_SIGNAL_TIMEOUT:
            case NET_OS_ERR_LOCK:
                attempt_conn = DEF_YES;
                break;
 
            default:
                attempt_conn = DEF_NO;
                break;
        }
    } while (attempt_conn == DEF_YES);
 
    if (err != NET_SOCK_ERR_NONE) {
        NetSock_Close(sock_req, &err);
        return (DEF_FALSE);
    }
    tx_size = NetSock_TxData( sock_req,                                                     (6)
                              pbuf,
                              buf_len,
                              NET_SOCK_FLAG_NONE,
                             &err);
 
    NetSock_Close(sock_req, &err);                                                          (7)
    NetSock_Close(sock_listen, &err);
 
    return (DEF_TRUE);
}
  1. Open a stream socket (TCP protocol).
  2. Populate the NET_SOCK_ADDR_IP structure for the server address and port, and convert it to network order.
  3. Bind the newly created socket to the address and port specified by server_sock_addr_ip.
  4. Set the socket to listen for a connection request coming on the specified port.
  5. Accept the incoming connection request, and return a new socket for this particular connection. Note that this function call is being called from inside a loop because it might timeout (no client attempts to connect to the server).
  6. One the connection has been established between the server and a client, transmit the message. Note that the return value of this function is not used here, but a real application should make sure all the message has been sent by comparing that value with the length of the message.
  7. Close both listen and request sockets. When the server need to stay active, the listen socket stays open so that I can accept additional connection requests. Usually, the server will wait for a connection, accept() it, and OSTaskCreate() a task to handle it.


Stream Client (TCP Client)

The client of the listing below connects to the specified server and receives the string the server sends.

Listing - Stream Client
#define  TCP_SERVER_IP_ADDR  "192.168.1.101"
#define  TCP_SERVER_PORT              10000
#define  RX_BUF_SIZE                     15
 
CPU_BOOLEAN  TestTCPClient (void)
{
    NET_SOCK_ID        sock;
    NET_IP_ADDR        server_ip_addr;
    NET_SOCK_ADDR_IP   server_sock_addr_ip;
    NET_SOCK_ADDR_LEN  server_sock_addr_ip_size;
    NET_SOCK_RTN_CODE  conn_rtn_code;
    NET_SOCK_RTN_CODE  rx_size;
    CPU_CHAR           rx_buf[RX_BUF_SIZE];
    NET_ERR            err;
    
    
    sock = NetSock_Open( NET_SOCK_ADDR_FAMILY_IP_V4,                                     (1)
                         NET_SOCK_TYPE_STREAM,
                         NET_SOCK_PROTOCOL_TCP,
                        &err);
    if (err != NET_SOCK_ERR_NONE) {
        return (DEF_FALSE);
    }
    
    server_ip_addr = NetASCII_Str_to_IP(TCP_SERVER_IP_ADDR, &err);                       (2)
    if (err != NET_ASCII_ERR_NONE) {
        NetSock_Close(sock, &err);
        return (DEF_FALSE);
    }
    
    server_sock_addr_ip_size = sizeof(server_sock_addr_ip);                              (3)
    Mem_Clr((void     *)&server_sock_addr_ip,
            (CPU_SIZE_T) server_sock_addr_ip_size);
    server_sock_addr_ip.AddrFamily = NET_SOCK_ADDR_FAMILY_IP_V4;
    server_sock_addr_ip.Addr       = NET_UTIL_HOST_TO_NET_32(server_ip_addr); 
    server_sock_addr_ip.Port       = NET_UTIL_HOST_TO_NET_16(TCP_SERVER_PORT);
    conn_rtn_code = NetSock_Conn((NET_SOCK_ID ) sock,                                    (4)
                                 (NET_SOCK_ADDR *)&server_sock_addr_ip,
                                 (NET_SOCK_ADDR_LEN) sizeof(server_sock_addr_ip),
                                 (NET_ERR *)&err);
    if (err != NET_SOCK_ERR_NONE) {
        NetSock_Close(sock, &err);
        return (DEF_FALSE);
    }
 
    rx_size = NetSock_RxData( sock,                                                      (5)
                              rx_buf,
                              RX_BUF_SIZE,
                              NET_SOCK_FLAG_NONE,
                             &err);
    if (err != NET_SOCK_ERR_NONE) {
        NetSock_Close(sock, &err);
        return (DEF_FALSE);
    }
 
    NetSock_Close(sock, &err);                                                           (6)
    return (DEF_TRUE);
}
  1. Open a stream socket (TCP protocol).
  2. Convert an IPv4 address from ASCII dotted-decimal notation to a network protocol IPv4 address in host-order.
  3. Populate the NET_SOCK_ADDR_IP structure for the server address and port, and convert it to network order.
  4. Connect the socket to a remote host.
  5. Receive data from the connected socket. Note that the return value for this function is not used here.However, a real application should make sure everything has been received.
  6. Close the socket.


TCP Connection Configuration

µC/TCP-IP provides a set of APIs to configure TCP connections on an individual basis. These APIs are listed below and detailed in TCP Functions: