• 物联网工程师开发服务平台

MiCO Socket APIs

MiCO 提供 socket 相关 API 包括 3 种,分别是:TCP/UDP, TCP TLS/SLL,和 TCPIP 通信。 更详细的 API 参数及返回值说明,可参考: doxygen 文档,更多示例代码查看可至 MiCO Demos

TCP/UDP通信

  • socket : 创建一个通信终端
  • setsockopt: 设置 socket 选项
  • getsockopt: 获取 socket 选项
  • bind: 为socket绑定一个名字
  • connect: 初始化一个socket连接
  • listen: 监听一个socket连接
  • accept:接受一个socket连接
  • select: 监视多个文件描述符
  • send: 在socket套接字上发送消息
  • write: 在socket套接字上,发送消息
  • sendto: 从socket套接字发送一条信息到目标地址
  • recv: 从socket套接字接收一条信息
  • read: 从socket套接字读取一条信息
  • recvfrom: 从一个sokcet套接字接收一条信息,并获取源地址
  • close: 关闭一个文件描述符
  • inet_addr: 将网络主机地址,从 IPv4数和点符号,转换为网络字节序的二进制数据
  • inet_ntoa: 将网络主机地址,按照网络字节顺序,转换为一个IPv4点分十进制的字符串

TCP TLS/SSL通信

TCPIP通信

示例

tcp_client.c

本例实现:创建一个 TCP Client 客户端,配网成功后,主动连接指定的TCP Server服务器,当 Server 发来字符串数据时,client 将回传数据给 TCP Server。

#include "mico.h"
#include "SocketUtils.h"

#define tcp_client_log(M, ...) custom_log("TCP", M, ##__VA_ARGS__)

static char tcp_remote_ip[16] = "192.168.3.53"; /*remote ip address*/
static int tcp_remote_port = 6000; /*remote port*/
static mico_semaphore_t wait_sem = NULL;

static void micoNotify_WifiStatusHandler( WiFiEvent status, void* const inContext )
{
    switch ( status )
    {
        case NOTIFY_STATION_UP:
            mico_rtos_set_semaphore( &wait_sem );
            break;
        case NOTIFY_STATION_DOWN:
        case NOTIFY_AP_UP:
        case NOTIFY_AP_DOWN:
            break;
    }
}

/*when client connected wlan success,create socket*/
void tcp_client_thread( mico_thread_arg_t arg )
{
    UNUSED_PARAMETER( arg );

    OSStatus err;
    struct sockaddr_in addr;
    struct timeval t;
    fd_set readfds;
    int tcp_fd = -1, len;
    char *buf = NULL;

    buf = (char*) malloc( 1024 );
    require_action( buf, exit, err = kNoMemoryErr );

    tcp_fd = socket( AF_INET, SOCK_STREAM, IPPROTO_TCP );
    require_action( IsValidSocket( tcp_fd ), exit, err = kNoResourcesErr );

    addr.sin_family = AF_INET;
    addr.sin_addr.s_addr = inet_addr( tcp_remote_ip );
    addr.sin_port = htons(tcp_remote_port);

    tcp_client_log( "Connecting to server: ip=%s  port=%d!", tcp_remote_ip,tcp_remote_port );
    err = connect( tcp_fd, (struct sockaddr *)&addr, sizeof(addr) );
    require_noerr( err, exit );
    tcp_client_log( "Connect success!" );

    t.tv_sec = 2;
    t.tv_usec = 0;

    while ( 1 )
    {
        FD_ZERO( &readfds );
        FD_SET( tcp_fd, &readfds );

        require_action( select( tcp_fd + 1, &readfds, NULL, NULL, &t) >= 0, exit,
                        err = kConnectionErr );

        /* recv wlan data, and send back */
        if ( FD_ISSET( tcp_fd, &readfds ) )
        {
            len = recv( tcp_fd, buf, 1024, 0 );
            require_action( len >= 0, exit, err = kConnectionErr );

            if ( len == 0 )
            {
                tcp_client_log( "TCP Client is disconnected, fd: %d", tcp_fd );
                goto exit;
            }

            tcp_client_log("Client fd: %d, recv data %d", tcp_fd, len);
            len = send( tcp_fd, buf, len, 0 );
            tcp_client_log("Client fd: %d, send data %d", tcp_fd, len);
        }
    }

    exit:
    if ( err != kNoErr ) tcp_client_log( "TCP client thread exit with err: %d", err );
    if ( buf != NULL ) free( buf );
    SocketClose( &tcp_fd );
    mico_rtos_delete_thread( NULL );
}

int application_start( void )
{
    OSStatus err = kNoErr;

    mico_rtos_init_semaphore( &wait_sem, 1 );

    /*Register user function for MiCO nitification: WiFi status changed */
    err = mico_system_notify_register( mico_notify_WIFI_STATUS_CHANGED,
                                       (void *) micoNotify_WifiStatusHandler, NULL );
    require_noerr( err, exit );

    /* Start MiCO system functions according to mico_config.h */
    err = mico_system_init( mico_system_context_init( 0 ) );
    require_noerr( err, exit );

    /* Wait for wlan connection*/
    mico_rtos_get_semaphore( &wait_sem, MICO_WAIT_FOREVER );
    tcp_client_log( "wifi connected successful" );

    /* Start TCP client thread */
    err = mico_rtos_create_thread( NULL, MICO_APPLICATION_PRIORITY, "TCP_client", tcp_client_thread, 0x800, 0 );
    require_noerr_string( err, exit, "ERROR: Unable to start the tcp client thread." );

    exit:
    if ( wait_sem != NULL )
        mico_rtos_deinit_semaphore( &wait_sem );
    mico_rtos_delete_thread( NULL );
    return err;
}

tcp_server.c

本例实现:创建一个 TCP server,等待TCP client的连接,当 client 向该 server 发送字符时,TCP server将接收到的字符回传给TCP client。

#include "mico.h"
#include "SocketUtils.h"

#define tcp_server_log(M, ...) custom_log("TCP", M, ##__VA_ARGS__)

#define SERVER_PORT 20000 /*set up a tcp server,port at 20000*/

void micoNotify_WifiStatusHandler( WiFiEvent event, void* const inContext )
{
    IPStatusTypedef para;
    switch ( event )
    {
        case NOTIFY_STATION_UP:
            micoWlanGetIPStatus( &para, Station );
            tcp_server_log("Server established at ip: %s port: %d",para.ip, SERVER_PORT);
            break;
        case NOTIFY_STATION_DOWN:
            case NOTIFY_AP_UP:
            case NOTIFY_AP_DOWN:
            break;
    }
}

void tcp_client_thread( mico_thread_arg_t arg )
{
    OSStatus err = kNoErr;
    int fd = (int) arg;
    int len = 0;
    fd_set readfds;
    char *buf = NULL;
    struct timeval t;

    buf = (char*) malloc( 1024 );
    require_action( buf, exit, err = kNoMemoryErr );

    t.tv_sec = 5;
    t.tv_usec = 0;

    while ( 1 )
    {
        FD_ZERO( &readfds );
        FD_SET( fd, &readfds );

        require_action( select( fd+1, &readfds, NULL, NULL, &t) >= 0, exit, err = kConnectionErr );

        if ( FD_ISSET( fd, &readfds ) ) /*one client has data*/
        {
            len = recv( fd, buf, 1024, 0 );
            require_action( len >= 0, exit, err = kConnectionErr );

            if ( len == 0 )
            {
                tcp_server_log( "TCP Client is disconnected, fd: %d", fd );
                goto exit;
            }

            tcp_server_log("fd: %d, recv data %d from client", fd, len);
            len = send( fd, buf, len, 0 );
            tcp_server_log("fd: %d, send data %d to client", fd, len);
        }
    }
    exit:
    if ( err != kNoErr ) tcp_server_log( "TCP client thread exit with err: %d", err );
    if ( buf != NULL ) free( buf );
    SocketClose( &fd );
    mico_rtos_delete_thread( NULL );
}

/* TCP server listener thread */
void tcp_server_thread( mico_thread_arg_t arg )
{
    UNUSED_PARAMETER( arg );
    OSStatus err = kNoErr;
    struct sockaddr_in server_addr, client_addr;
    socklen_t sockaddr_t_size = sizeof(client_addr);
    char client_ip_str[16];
    int tcp_listen_fd = -1, client_fd = -1;
    fd_set readfds;

    tcp_listen_fd = socket( AF_INET, SOCK_STREAM, IPPROTO_TCP );
    require_action( IsValidSocket( tcp_listen_fd ), exit, err = kNoResourcesErr );

    server_addr.sin_family = AF_INET;
    server_addr.sin_addr.s_addr = INADDR_ANY;/* Accept conenction request on all network interface */
    server_addr.sin_port = htons( SERVER_PORT );/* Server listen on port: 20000 */

    err = bind( tcp_listen_fd, (struct sockaddr *) &server_addr, sizeof(server_addr) );
    require_noerr( err, exit );

    err = listen( tcp_listen_fd, 0 );
    require_noerr( err, exit );

    while ( 1 )
    {
        FD_ZERO( &readfds );
        FD_SET( tcp_listen_fd, &readfds );

        require( select( tcp_listen_fd + 1, &readfds, NULL, NULL, NULL) >= 0, exit );

        if ( FD_ISSET( tcp_listen_fd, &readfds ) )
        {
            client_fd = accept( tcp_listen_fd, (struct sockaddr *) &client_addr, &sockaddr_t_size );
            if ( IsValidSocket( client_fd ) )
            {
//                inet_ntoa( client_ip_str, client_addr.s_ip );
                strcpy( client_ip_str, inet_ntoa( client_addr.sin_addr ) );
                tcp_server_log( "TCP Client %s:%d connected, fd: %d", client_ip_str, client_addr.sin_port, client_fd );
                if ( kNoErr
                     != mico_rtos_create_thread( NULL, MICO_APPLICATION_PRIORITY, "TCP Clients",
                                                 tcp_client_thread,
                                                 0x800, client_fd ) )
                    SocketClose( &client_fd );
            }
        }
    }
    exit:
    if ( err != kNoErr ) tcp_server_log( "Server listerner thread exit with err: %d", err );
    SocketClose( &tcp_listen_fd );
    mico_rtos_delete_thread( NULL );
}

int application_start( void )
{
    OSStatus err = kNoErr;

    /*Register user function for MiCO nitification: WiFi status changed */
    err = mico_system_notify_register( mico_notify_WIFI_STATUS_CHANGED,
                                       (void *) micoNotify_WifiStatusHandler,
                                       NULL );
    require_noerr( err, exit );

    /* Start MiCO system functions according to mico_config.h */
    err = mico_system_init( mico_system_context_init( 0 ) );
    require_noerr( err, exit );

    /* Start TCP server listener thread*/
    err = mico_rtos_create_thread( NULL, MICO_APPLICATION_PRIORITY, "TCP_server", tcp_server_thread,
                                   0x800,
                                   0 );
    require_noerr_string( err, exit, "ERROR: Unable to start the tcp server thread." );

    exit:
    mico_rtos_delete_thread( NULL );
    return err;
}

udp_broadcast.c

本例实现:启动 UDP 广播服务,与同一网关下的不同 IP 地址的主机的同一端口号进行通讯。

#include "mico.h"

#define udp_broadcast_log(M, ...) custom_log("UDP", M, ##__VA_ARGS__)

#define LOCAL_UDP_PORT 20000
#define REMOTE_UDP_PORT 20001

char* data = "UDP broadcast data";

/*create udp socket*/
void udp_broadcast_thread( mico_thread_arg_t arg )
{
    UNUSED_PARAMETER( arg );

    OSStatus err;
    struct sockaddr_in addr;
    int udp_fd = -1;

    /*Establish a UDP port to receive any data sent to this port*/
    udp_fd = socket( AF_INET, SOCK_DGRAM, IPPROTO_UDP );
    require_action( IsValidSocket( udp_fd ), exit, err = kNoResourcesErr );

    addr.sin_family = AF_INET;
    addr.sin_addr.s_addr = INADDR_ANY;
    addr.sin_port = htons( LOCAL_UDP_PORT );

    err = bind( udp_fd, (struct sockaddr *) &addr, sizeof(addr) );
    require_noerr( err, exit );

    udp_broadcast_log("Start UDP broadcast mode, local port: %d, remote port: %d", LOCAL_UDP_PORT, REMOTE_UDP_PORT);

    while ( 1 )
    {
        udp_broadcast_log( "broadcast now!" );

        addr.sin_family = AF_INET;
        addr.sin_addr.s_addr = INADDR_BROADCAST;
        addr.sin_port = htons( REMOTE_UDP_PORT );
        /*the receiver should bind at port=20000*/
        sendto( udp_fd, data, strlen( data ), 0, (struct sockaddr *) &addr, sizeof(addr) );

        mico_thread_sleep( 2 );
    }

    exit:
    if ( err != kNoErr )
        udp_broadcast_log("UDP thread exit with err: %d", err);
    mico_rtos_delete_thread( NULL );
}

int application_start( void )
{
    OSStatus err = kNoErr;

    /* Start MiCO system functions according to mico_config.h */
    err = mico_system_init( mico_system_context_init( 0 ) );
    require_noerr( err, exit );

    err = mico_rtos_create_thread( NULL, MICO_APPLICATION_PRIORITY, "udp_broadcast", udp_broadcast_thread, 0x800, 0 );
    require_noerr_string( err, exit, "ERROR: Unable to start the UDP thread." );

    exit:
    if ( err != kNoErr )
        udp_broadcast_log("Thread exit with err: %d", err);
    mico_rtos_delete_thread( NULL );
    return err;
}

udp_unicast.c

本示例实现:启动 udp 单播服务,与指定 IP 地址 的主机端口号进行数据通信。

#include "mico.h"

#define udp_unicast_log(M, ...) custom_log("UDP", M, ##__VA_ARGS__)

#define LOCAL_UDP_PORT 20000

void micoNotify_WifiStatusHandler( WiFiEvent event, void* const inContext )
{
    IPStatusTypedef para;
    switch ( event )
    {
        case NOTIFY_STATION_UP:
            micoWlanGetIPStatus( &para, Station );
            udp_unicast_log( "Wlan connected, Local ip address: %s", para.ip );
            break;
        case NOTIFY_STATION_DOWN:
        case NOTIFY_AP_UP:
        case NOTIFY_AP_DOWN:
            break;
    }
}

/*create udp socket*/
void udp_unicast_thread( void *arg )
{
    UNUSED_PARAMETER( arg );

    OSStatus err;
    struct sockaddr_in addr;
    fd_set readfds;
    socklen_t addrLen = sizeof(addr);
    int udp_fd = -1, len;
    char ip_address[16];
    uint8_t *buf = NULL;

    buf = malloc( 1024 );
    require_action( buf, exit, err = kNoMemoryErr );

    /*Establish a UDP port to receive any data sent to this port*/
    udp_fd = socket( AF_INET, SOCK_DGRAM, IPPROTO_UDP );
    require_action( IsValidSocket( udp_fd ), exit, err = kNoResourcesErr );

    addr.sin_family = AF_INET;
    addr.sin_addr.s_addr = INADDR_ANY;
    addr.sin_port = htons(LOCAL_UDP_PORT);
    err = bind( udp_fd, (struct sockaddr *)&addr, sizeof(addr) );
    require_noerr( err, exit );

    udp_unicast_log("Open local UDP port %d", LOCAL_UDP_PORT);

    while ( 1 )
    {
        FD_ZERO( &readfds );
        FD_SET( udp_fd, &readfds );

        require_action( select(udp_fd + 1, &readfds, NULL, NULL, NULL) >= 0, exit,
                        err = kConnectionErr );

        /*Read data from udp and send data back */
        if ( FD_ISSET( udp_fd, &readfds ) )
        {
            len = recvfrom( udp_fd, buf, 1024, 0, (struct sockaddr *)&addr, &addrLen );
            require_action( len >= 0, exit, err = kConnectionErr );

            strcpy(ip_address, inet_ntoa(addr.sin_addr));
            udp_unicast_log( "udp recv from %s:%d, len:%d", ip_address,addr.sin_port, len );
            sendto( udp_fd, buf, len, 0, (struct sockaddr *)&addr, sizeof(struct sockaddr_in) );
        }
    }

    exit:
    if ( err != kNoErr )
        udp_unicast_log("UDP thread exit with err: %d", err);
    if ( buf != NULL ) free( buf );
    mico_rtos_delete_thread( NULL );
}

int application_start( void )
{
    OSStatus err = kNoErr;

    /*Register user function for MiCO nitification: WiFi status changed */
    err = mico_system_notify_register( mico_notify_WIFI_STATUS_CHANGED,
                                       (void *) micoNotify_WifiStatusHandler, NULL );
    require_noerr( err, exit );

    /* Start MiCO system functions according to mico_config.h */
    err = mico_system_init( mico_system_context_init( 0 ) );
    require_noerr( err, exit );

    err = mico_rtos_create_thread( NULL, MICO_APPLICATION_PRIORITY, "udp_unicast",
                                   (mico_thread_function_t)udp_unicast_thread, 0x800, 0 );
    require_noerr_string( err, exit, "ERROR: Unable to start the UDP thread." );

    exit:
    if ( err != kNoErr )
        udp_unicast_log("Thread exit with err: %d", err);
    mico_rtos_delete_thread( NULL );
    return err;
}
文本导读目录