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

弊社TCP/IPプロトコルスタック「μNet3」に関するご質問

ノンブロッキングモードを使って複数のソケットを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)*/
}
アバター
eForce技術担当
 
記事: 163
登録日時: 2014年4月24日(木) 14:18

Return to μNet3

オンラインデータ

このフォーラムを閲覧中のユーザー: なし & ゲスト[0人]