ノンブロッキングモードを使って複数のソケットを1つのタスクで処理したい

弊社TCP/IPプロトコルスタック「μNet3」に関するご質問
返信する
アバター
eForce技術担当
記事: 163
登録日時: 2014年4月24日(木) 14:18

ノンブロッキングモードを使って複数のソケットを1つのタスクで処理したい

投稿記事 by eForce技術担当 » 2016年12月14日(水) 21:42

μNet3のノンブロッキングモードを使用することで、1つのタスクで複数のソケットの送受信が可能になります。

ノンブロッキングモードを使用する上で注意が必要なのは

1.ソケットに対してノンブロッキングモードの設定とコールバック関数の登録を行います。
2.ソケットAPIの戻り値がE_WBLK(ノンブロッキング受付)の時のみコールバックされます。
3.コールバック関数はイベント発生時に呼ばれますが、コールバック関数からソケットAPIを呼ぶことはできません。
4.1度ノンブロッキングを受け付けたソケットに対して、コールバック前に同じソケットAPIを呼ぶとE_QOVRが返却されます。(API実行はキューイングされません)



本トピックにTCPソケット(10000ポート)とUDPソケット(20000ポート)を使って受信したパケットを送信元に返却する(エコーバックサーバ)サンプルを掲載します。
μC3コンパクトを使用する場合はコンフィグレータで次のIDを定義して下さい。

・イベントフラグ(ID_FLG_ECHO) (TA_WMUL)
・TCPソケット(TCP_SOC_ID) (ローカルポート10000)
・UDPソケット(UDP_SOC_ID) (ローカルポート20000)
/***********************************************************************
                Non-blocking echo server program
 ***********************************************************************/

#include "kernel.h"
#include "net_hdr.h"

#define  TCP_CONN_PTN     0x00000001
#define  TCP_RECV_PTN     0x00000002
#define  TCP_CLSE_PTN     0x00000004
#define  UDP_RECV_PTN     0x00000008

#define  ALL_PTN     (TCP_CONN_PTN | TCP_RECV_PTN | TCP_CLSE_PTN | UDP_RECV_PTN)

/*
    Resources 
*/
#ifdef NET_S_OS
    ID  ID_FLG_ECHO  = 0;
    SID TCP_SOC_ID   = 0;
    SID UDP_SOC_ID   = 0;
    UH TCP_SOC_PORT = 10000;
    UH UDP_SOC_PORT = 20000;
#else
    #include "kernel_id.h"
    #include "net_id.h"
#endif

UB TcpEchoBuffer[512];
UB UdpEchoBuffer[512];

/* Callback function */
ER EchoServerCallback(SID SocketId, UH CallbackEvent, ER ReturnValue)
{
    FLGPTN ptn;

    ptn = 0;
    if (ReturnValue >= E_OK) {
        /* TCP Socket */
        if (SocketId == TCP_SOC_ID) {
            /* Passive Open */
            if (CallbackEvent & EV_SOC_CON) {
                ptn |= TCP_CONN_PTN;
            }
            /* Receive Packet */
            if (CallbackEvent & EV_SOC_RCV) {
                ptn |= TCP_RECV_PTN;
            }
            /* Receive FIN */
            if (CallbackEvent & EV_SOC_CLS) {
                ptn |= TCP_CLSE_PTN;
            }
        /* UDP Socket */
        } else if (SocketId == UDP_SOC_ID) {
            /* Receive Packet */
            if (CallbackEvent & EV_SOC_RCV) {
                ptn |= UDP_RECV_PTN;
            }
        }
        set_flg(ID_FLG_ECHO, ptn);
    }
    return E_OK;
}

ER EchoServer(void)
{
    ER      ReturnValue;
    FLGPTN  EventPattern;
    T_NODE  HostEndPoint;

#ifdef NET_S_OS
    T_CFLG  cflg_echo = {TA_TPRI | TA_WMUL, 0};

    ReturnValue = acre_flg(&cflg_echo);
    if (ReturnValue < 0) {
        return ReturnValue;
    }
    ID_FLG_ECHO = ReturnValue;
#endif

    EventPattern = 0;
    net_memset(&HostEndPoint, 0, sizeof(HostEndPoint));

    /*
        TCP echo server
    */

    /* 1. Create TCP Socket */
#ifdef NET_S_OS
    HostEndPoint.port = TCP_SOC_PORT;
    HostEndPoint.num = 1;  /* device number */

    ReturnValue = (ER)cre_soc(IP_PROTO_TCP, &HostEndPoint);
    if (ReturnValue < E_OK) {
        return ReturnValue;
    }
    TCP_SOC_ID = (SID)ReturnValue;
#endif

    /* 2. Register callback function */
    cfg_soc(TCP_SOC_ID, SOC_CBK_HND, (VP)&EchoServerCallback);

    /* 3. Set Socket API blocking mode as Non-Blocking (Connect, Receive, Close)*/
    cfg_soc(TCP_SOC_ID, SOC_CBK_FLG, (VP)(EV_SOC_CON|EV_SOC_RCV|EV_SOC_CLS));


    /*
        UDP echo server
    */
    /* 1. Create UDP Socket */
#ifdef NET_S_OS
    HostEndPoint.port = UDP_SOC_PORT;
    HostEndPoint.num = 1;  /* device number */

    ReturnValue = (ER)cre_soc(IP_PROTO_UDP, &HostEndPoint);
    if (ReturnValue < E_OK) {
        return ReturnValue;
    }
    UDP_SOC_ID = (SID)ReturnValue;
#endif

    /* 2. Register callback function */
    cfg_soc(UDP_SOC_ID, SOC_CBK_HND, (VP)&EchoServerCallback);

    /* 3. Set Socket API blocking mode as Non-Blocking (Receive)*/
    cfg_soc(UDP_SOC_ID, SOC_CBK_FLG, (VP)EV_SOC_RCV);


    /*
        Echoback Process 
    */

    /* give opportunity of first for TCP connect */
    EventPattern |= TCP_CLSE_PTN;

    /* give opportunity of first for UDP receive */
    EventPattern |= UDP_RECV_PTN;

    while (1) {

        /* TCP Passive open */
        if (EventPattern & TCP_CLSE_PTN) {
            ReturnValue = con_soc(TCP_SOC_ID, &HostEndPoint, SOC_SER);
            if (ReturnValue != E_WBLK) {
                return ReturnValue;
            }
        }

        /* packet in socket until empty */
        while (EventPattern & TCP_RECV_PTN) {

            ReturnValue = rcv_soc(TCP_SOC_ID, TcpEchoBuffer, sizeof(TcpEchoBuffer));
            /* Receive data */
            if (ReturnValue > 0) {
                /* Send data to Echo Client */
                snd_soc(TCP_SOC_ID, TcpEchoBuffer, ReturnValue);
            }
            /* Socket has no pakcet */
            else if (ReturnValue == E_WBLK) {
                EventPattern &= ~TCP_RECV_PTN;
            }
            /* Finished TCP session */
            else if (ReturnValue == 0 || ReturnValue == E_CLS) {
                ReturnValue = cls_soc(TCP_SOC_ID, SOC_TCP_CLS);
                if (ReturnValue != E_WBLK) {
                    return ReturnValue;
                }
                EventPattern &= ~TCP_RECV_PTN;
            }
            /* rcv_soc() error */
            else {
                return EventPattern;
            }
        }


        /* UDP */
        /* packet in socket until empty */
        while (EventPattern & UDP_RECV_PTN) {

            ReturnValue = rcv_soc(UDP_SOC_ID, UdpEchoBuffer, sizeof(UdpEchoBuffer));
            /* Receive data */
            if (ReturnValue > 0) {

                /* Get the IP Address and Port number information of Echo Clien */
                ref_soc(UDP_SOC_ID, SOC_IP_REMOTE, (VP)&HostEndPoint);

                /* Set the IP Address and Port number for data Transmission */
                con_soc(UDP_SOC_ID, (VP)&HostEndPoint, 0);

                /* Send data to Echo Client */
                snd_soc(UDP_SOC_ID, UdpEchoBuffer, ReturnValue);
            }
            /* Socket has no pakcet */
            else if (ReturnValue == E_WBLK) {
                EventPattern &= ~UDP_RECV_PTN;
            }
            /* rcv_soc() error */
            else {
                return EventPattern;
            }
        }

        EventPattern = 0;

        /* Wait callback event */
        ReturnValue = wai_flg(ID_FLG_ECHO, ALL_PTN, TWF_ORW, &EventPattern);
        clr_flg(ID_FLG_ECHO, ~EventPattern);

        if (ReturnValue != E_OK) {
            return ReturnValue;
        }

        if (EventPattern & TCP_CONN_PTN) {
            /* give opportunity of first for TCP receive */
            EventPattern |= TCP_RECV_PTN;
        }

    } /* while (1)*/
}

返信する