ノンブロッキングモードを使用する上で注意が必要なのは
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)*/
}