?? netsocket.c
字號:
/*!
* Example program.
* Copyright (c) 2004 by BREW Development Team, Zhejiang University.
* All Rights Reserved.
*/
/*!-----------------------------------
@file netsocket.c
@author TYB
@brief 程序主文件
-----------------------------------*/
#include "AEEModGen.h"
#include "AEEAppGen.h"
#include "AEEShell.h"
#include "AEEFile.h"
#include "AEENet.h"
#include "netsocket.bid"
#include "AEEStdlib.h"
#include "AEEMenu.h"
typedef struct _CNetSocket {
AEEApplet a;
INetMgr *pINetMgr;
ISocket *pISocket;
IMenuCtl *pIMenuCtl;
AEEDNSResult dnsresult;
AEECallback cbkLookup;
INAddr addrsLookup[8];
uint16 APIFnType;
}CNetSocket;
#define USAGE_BASIC_USAGE 100
#define USAGE_NET_GETHOSTBYNAME 101
#define USAGE_NET_GETLASTERROR 102
#define USAGE_NET_OPENSOCKET 103
#define USAGE_NET_SETLINGER 104
#define USAGE_NET_NETSTATUS 105
#define USAGE_NET_GETMYIPADDRESS 106
#define USAGE_SOCKET_GETPEERNAME 107
#define USAGE_SOCKET_GETLASTERROR 108
#define USAGE_SOCKET_CONNECT 109
#define USAGE_SOCKET_BIND 110
#define USAGE_SOCKET_WRITE 111
#define USAGE_SOCKET_WRITEV 112
#define USAGE_SOCKET_READ 113
#define USAGE_SOCKET_READV 114
#define USAGE_SOCKET_SENDTO 115
#define USAGE_SOCKET_RECVFROM 116
#define USAGE_SOCKET_READBALE 117
#define USAGE_SOCKET_WRITEABLE 118
#define USAGE_SOCKET_CANCEL 119
#define USAGE_SOCKET_SHUTDOWN 120
#define USAGE_ERASE_SCREEN 121
#define TIMESERVER_PORT 23
#define TIMESERVER_HOST "10.214.52.108"
#define USAGE_TEST_HOST "10.214.52.108"
#define USAGE_TEST_PORT 22
#define ISDIGIT(c) ( (unsigned) ((c) - '0') < 10)
#define ISALPHA(c) ( (unsigned) ( ((c)|32) - 'a') < 26 )
#define ISALNUM(c) ( ISDIGIT(c) || ISALPHA(c) )
#define min(a,b) ((a) < (b) ? (a) : (b))
#define ARRAYSIZE(a) (sizeof(a) / sizeof((a)[0]))
/*!
Function Prototypes
*/
static boolean HandleEvent(IApplet * pi,AEEEvent eCode,uint16 wParam,uint32 dwParam);
static boolean InitData(CNetSocket *pme);
static void FreeData(CNetSocket *pme);
static void ConnectCBFun(CNetSocket *pme , int wParam);
void BuildMainMenu(CNetSocket *pMe);
boolean INetSocketUsage (CNetSocket * pme, uint16 wParam);
void DisplayOutput(CNetSocket * pi, int line , char *pszStr);
INAddr ConvertToINAddr(char *psz);
void ConvertToIPAddr(INAddr inaddr, char *psz);
void GetHostByNameCB(void * pUser);
void CommonReadCB(void *pUser);
void CommonWriteCB(void *pUser);
/*!
Function Defintions
*/
//----------------------------------------------------------------------------------
/*!
* @brief: 小程序初始化函數(shù)
* @para: ClsId小程序的ClassID
* @para: pIShell底層傳遞來的指向IShell接口的指針
* @para: po指向IModule接口的指針
* @para: ppObj用于初始化以后返回AEEApplet結(jié)構(gòu)的指針
* @return: AEE_SUCCESS表示成功,EFAILED表示失敗
*/
int AEEClsCreateInstance(AEECLSID ClsId,IShell * pIShell,IModule * po,void ** ppObj)
{
*ppObj = NULL;
if(ClsId != AEECLSID_NETSOCKET)
return (EFAILED);
if(TRUE != AEEApplet_New(sizeof(CNetSocket),
ClsId,
pIShell,
po,
(IApplet**)ppObj,
(AEEHANDLER)HandleEvent,
(PFNFREEAPPDATA)FreeData))
return (EFAILED);
if(!InitData((CNetSocket*)*ppObj))
return (EFAILED);
return AEE_SUCCESS;
}
/*!
* @brief: 消息處理函數(shù)
* @para: pi指向IApplet接口的指針
* @para: eCode消息代碼
* @para: wParam是16位的參數(shù)
* @para: dwParam是32位的參數(shù)
* @return: TRUE表示處理過,F(xiàn)ALSE沒有處理
*/
static boolean HandleEvent(IApplet * pi, AEEEvent eCode, uint16 wParam, uint32 dwParam)
{
CNetSocket *pme = (CNetSocket*)pi;
switch (eCode)
{
case EVT_APP_START:
ISHELL_CreateInstance(pme->a.m_pIShell, AEECLSID_MENUCTL, (void**)&pme->pIMenuCtl);
ISHELL_CreateInstance(pme->a.m_pIShell, AEECLSID_NET, (void **)&pme->pINetMgr);
if(pme->pINetMgr)
//如果這里出現(xiàn)錯誤,又沒有辦法注冊回調(diào)函數(shù),所以錯誤是在ISocket接口中的
//ISOCKET_GetLastError()函數(shù)取得
pme->pISocket = INETMGR_OpenSocket (pme->pINetMgr, AEE_SOCK_STREAM);
if(pme->pIMenuCtl)
BuildMainMenu(pme);
return TRUE;
case EVT_APP_STOP:
return TRUE;
case EVT_KEY:
if(pme->pIMenuCtl != NULL && (IMENUCTL_IsActive(pme->pIMenuCtl) == TRUE))
return IMENUCTL_HandleEvent(pme->pIMenuCtl, EVT_KEY, wParam, 0);
else if(pme->pIMenuCtl != NULL && (IMENUCTL_IsActive(pme->pIMenuCtl) == FALSE)) {
if(wParam == AVK_CLR) {
IMENUCTL_SetActive(pme->pIMenuCtl, TRUE);
return TRUE;
}
}
break;
case EVT_COMMAND:
IDISPLAY_ClearScreen(pme->a.m_pIDisplay);
INetSocketUsage(pme, wParam);
break;
default:
break;
}
return FALSE;
}
/*!
* @brief: 初始化函數(shù)
* @para: pme指向CNetSocket結(jié)構(gòu)的指針
* @return: TRUE表示成功,F(xiàn)ALSE表示失敗
*/
boolean InitData(CNetSocket *pme)
{
pme->pINetMgr = NULL;
pme->pISocket = NULL;
pme->pIMenuCtl= NULL;
return TRUE;
}
/*!
* @brief: 資源釋放函數(shù)
* @para: pme指向CNetSocket結(jié)構(gòu)的指針
*/
static void FreeData(CNetSocket *pme)
{
if(pme->pIMenuCtl) {
IMENUCTL_Release(pme->pIMenuCtl);
pme->pIMenuCtl = NULL;
}
if(pme->pINetMgr) {
INETMGR_Release(pme->pINetMgr);
pme->pINetMgr = NULL;
}
if(pme->pISocket) {
ISOCKET_Release(pme->pISocket);
pme->pISocket = NULL;
}
}
/*!
* @brief: 程序的主要功能模塊
* @para: pme指向CNetSocket結(jié)構(gòu)的指針
* @para: wParam傳遞到該函數(shù)的命令參數(shù)
* @retval: TRUE表示成功,F(xiàn)ALSE表示失敗
*/
boolean INetSocketUsage (CNetSocket * pme, uint16 wParam)
{
INAddr nodeINAddr;
uint16 nPort;
char psz[50] = {0};
const char hostName [] = "www.sina.com";
int invalidSockType = 0xff;
int lastError = 0;
char lTime[100] = {0};
uint16 lingerTime1 = 20;
uint16 prevLingerTime = 0;
NetState netState = NET_INVALID_STATE;
AEENetStats netStats;
int iRetValue = AEE_NET_EBADF;
uint32 readVal;
IMENUCTL_SetActive(pme->pIMenuCtl, FALSE);
IDISPLAY_ClearScreen(pme->a.m_pIDisplay);
if(pme->pINetMgr && pme->pISocket)
{
switch(pme->APIFnType = wParam) {
//基礎(chǔ)用法,先見識一下回調(diào)的工作方式
case USAGE_BASIC_USAGE:
nodeINAddr = ConvertToINAddr(USAGE_TEST_HOST);
nPort = HTONS(USAGE_TEST_PORT);
ISOCKET_Connect(pme->pISocket, nodeINAddr ,nPort, ConnectCBFun ,pme);
DisplayOutput (pme, 1, "Connecting...");
break;
//注意,這里必須注冊回調(diào)函數(shù)來進(jìn)行函數(shù)調(diào)用結(jié)果分析
case USAGE_NET_GETHOSTBYNAME:
CALLBACK_Init(&pme->cbkLookup, GetHostByNameCB, pme);
//注意必須保證在回調(diào)函數(shù)處理完成之前,pme->dnsresult一直存在
//還要注意,在調(diào)用INETMGR_Release()函數(shù)之前保證回調(diào)被清除,防止內(nèi)存錯誤
INETMGR_GetHostByName(pme->pINetMgr,&pme->dnsresult, hostName, &pme->cbkLookup);
break;
//返回錯誤代碼
case USAGE_NET_GETLASTERROR:
{
ISocket *pISocket = NULL;
if(pme->pINetMgr)
//此處用一個非法的socket類型來打開socket連接
pISocket = INETMGR_OpenSocket(pme->pINetMgr, invalidSockType);
if(!pISocket)
lastError = INETMGR_GetLastError(pme->pINetMgr);
if(lastError != AEE_NET_SUCCESS) {
//打印出錯誤號碼
SPRINTF(psz, "Error Id: %u", lastError);
DisplayOutput(pme, 1, psz);
}
else
DisplayOutput (pme, 1, "GetLastError: failed");
if(pISocket)
ISOCKET_Release(pISocket);
}
break;
//設(shè)置網(wǎng)絡(luò)延遲時間,返回值是以前的延遲時間,不能注冊回調(diào)函數(shù)
case USAGE_NET_SETLINGER:
prevLingerTime = INETMGR_SetLinger (pme->pINetMgr, lingerTime1);
SPRINTF (lTime, "Linger Time 1 = %u", prevLingerTime);
DisplayOutput (pme, 1, lTime);
prevLingerTime = INETMGR_SetLinger (pme->pINetMgr, lingerTime1);
SPRINTF (lTime, "Linger Time 2 = %u", prevLingerTime);
DisplayOutput (pme, 2, lTime);
break;
//取得自己的IP地址,返回值是一個IP地址,不能注冊回調(diào)函數(shù)
//由于返回值的IP不是字符串,所以要想顯示先得轉(zhuǎn)換
case USAGE_NET_GETMYIPADDRESS:
nodeINAddr = INETMGR_GetMyIPAddr(pme->pINetMgr);
ConvertToIPAddr(nodeINAddr, psz);
DisplayOutput(pme , 1, psz);
break;
//取得網(wǎng)絡(luò)狀態(tài),網(wǎng)絡(luò)的狀態(tài)通過返回值取得,網(wǎng)絡(luò)參數(shù)通過傳入一個指針參數(shù)來獲取
//這個函數(shù)也是不需要也不能注冊回調(diào)函數(shù)
case USAGE_NET_NETSTATUS:
netState = INETMGR_NetStatus (pme->pINetMgr, &netStats);
switch (netState)
{
case NET_INVALID_STATE:
DisplayOutput (pme, 1, "Status: Invalid");
break;
case NET_PPP_OPENING:
DisplayOutput (pme, 1, "Status: Opening");
break;
case NET_PPP_OPEN:
DisplayOutput (pme, 1, "Status: Open");
break;
case NET_PPP_CLOSING:
DisplayOutput (pme, 1, "Status: Closing");
break;
case NET_PPP_CLOSED:
DisplayOutput (pme, 1, "Status: Closed");
break;
}
break;
//注意,INetMgr接口除了INETMGR_GetHonstByName()函數(shù)以外,還有一個比較特殊的函數(shù)
//這個函數(shù)可以將INetMgr接口產(chǎn)生的所有事件都全部截獲,并在事件發(fā)生時調(diào)用一個
//回調(diào)函數(shù)來進(jìn)行處理
//用于套接字和本地地址和端口相關(guān)聯(lián),只能用于未連接的套接字,通常是用于
//數(shù)據(jù)報(bào)套接字,第二個參數(shù)必須是AEE_INADDR_ANY,原因見API文檔。此函數(shù)
//不能注冊回調(diào),執(zhí)行情況通過返回值取得,如果阻塞,用ISOCKET_Writeable()
//注冊一個回調(diào)函數(shù)等待可以傳輸時進(jìn)行相應(yīng)的處理,在回調(diào)函數(shù)中可以再次調(diào)
//用以取得最終結(jié)果,是成功還是失敗,ISOCKET_Writeable() 可以獲取再次調(diào)
//用Bind() 的時間通知。請注意,和Write()一樣, ISOCKET_Writeable() 回調(diào)
//無法確保完成后續(xù)的Bind() 調(diào)用,因此調(diào)用程序必須準(zhǔn)備再次接收
//AEE_NET_WOULDBLOCK,一旦綁定成功,可以進(jìn)行讀寫操作了
case USAGE_SOCKET_BIND:
if ((iRetValue = ISOCKET_Bind (pme->pISocket, AEE_INADDR_ANY, 1240))
== AEE_NET_WOULDBLOCK)
ISOCKET_Writeable(pme->pISocket, CommonWriteCB, (void *)pme);
else
if (iRetValue != AEE_NET_SUCCESS)
DisplayOutput (pme, 1, "Bind Failed.");
else
DisplayOutput (pme, 1, "Bind Succeeded.");
break;
//ISocket接口中比較簡單的一個函數(shù),不需要注冊回調(diào)函數(shù),直接返回結(jié)果
case USAGE_SOCKET_GETLASTERROR:
//此處還沒有連接,所以調(diào)用Read函數(shù)會出錯
if (AEE_NET_SUCCESS != (iRetValue = ISOCKET_Read(pme->pISocket, (byte*)&readVal, sizeof(uint32))))
if ((lastError = ISOCKET_GetLastError(pme->pISocket))== AEE_NET_ENOTCONN)
DisplayOutput (pme, 1, "Err: Not Connected");
break;
//以下這些功能的調(diào)用都沒有直接在這里進(jìn)行演示,而是都放在
//ConnectCBFun()函數(shù)中進(jìn)行處理,原因很簡單,這些操作都必
//須在網(wǎng)絡(luò)接通的情況下進(jìn)行,而網(wǎng)絡(luò)連接的ISOCKET_Connect()
//函數(shù)是異步執(zhí)行,需要注冊一個回調(diào)函數(shù),不管執(zhí)行是否成功
//即:連接是否成功,都會調(diào)用回調(diào)函數(shù),正確和錯誤的處理都
//必須在回調(diào)函數(shù)中進(jìn)行,所以這些功能都必須在回調(diào)中處理
case USAGE_SOCKET_GETPEERNAME:
case USAGE_SOCKET_WRITE:
case USAGE_SOCKET_WRITEV:
case USAGE_SOCKET_READ:
case USAGE_SOCKET_READV:
case USAGE_SOCKET_READBALE:
case USAGE_SOCKET_WRITEABLE:
nodeINAddr = ConvertToINAddr(USAGE_TEST_HOST);
//此函數(shù)用于將無符號短整型值從主機(jī)轉(zhuǎn)換為網(wǎng)絡(luò)字節(jié)順序。
nPort = HTONS(USAGE_TEST_PORT);
//這里的ISOCKET_Connect()其實(shí)有兩個作用,一個是網(wǎng)絡(luò)連接
//另一個是進(jìn)行回調(diào)的注冊
if ((iRetValue = ISOCKET_Connect (pme->pISocket, nodeINAddr, nPort,
ConnectCBFun, (void *)pme)) != AEE_NET_SUCCESS)
if (iRetValue != AEE_NET_WOULDBLOCK) {
//函數(shù)ISOCKET_GetLastError不能注冊回調(diào),直接返回值
lastError = ISOCKET_GetLastError(pme->pISocket);
SPRINTF(psz, "ERROR Number : %u",lastError);
DisplayOutput(pme, 2, psz);
}
DisplayOutput (pme, 1, "Connecting...");
break;
case USAGE_SOCKET_CANCEL:
if(pme->pISocket) {
ISOCKET_Cancel (pme->pISocket, 0, 0);
DisplayOutput (pme, 1, "Socket Canceled");
}
else
DisplayOutput(pme,1,"The Net Is Not Open!");
break;
case USAGE_SOCKET_SENDTO:
case USAGE_SOCKET_RECVFROM:
{
int32 iRetValue = 0;
INAddr nodeINAddr;
uint16 nPort;
int rv;
char pszSendData[100] = "UDP packet sent to and received from echo-port of remote host...";
char pszRecvData[100] = {0};
if(pme->pISocket)
ISOCKET_Release(pme->pISocket);
pme->pISocket = INETMGR_OpenSocket(pme->pINetMgr,AEE_SOCK_DGRAM);
if(!pme->pISocket) {
DisplayOutput(pme,2,"Socket can't open!");
return TRUE;
}
nodeINAddr = ConvertToINAddr(TIMESERVER_HOST);
nPort = HTONS(TIMESERVER_PORT);
//ISOCKET_Connect(pme->pISocket,nodeINAddr,nPort,ConnectCBFun,pme);
ISOCKET_Writeable(pme->pISocket,CommonWriteCB,pme);
iRetValue = ISOCKET_SendTo(pme->pISocket,(byte*)pszSendData,
(uint16)STRLEN(pszSendData),0,nodeINAddr,nPort);
if(iRetValue == AEE_NET_ERROR){
DisplayOutput(pme,3,"Send Error!");
return FALSE;
}
else if(iRetValue > 0) {
ISOCKET_Readable(pme->pISocket,CommonReadCB,pme);
rv = ISOCKET_RecvFrom(pme->pISocket,(byte*)pszRecvData,sizeof(pszRecvData),
0,&nodeINAddr,&nPort);
if(rv == AEE_NET_WOULDBLOCK)
return TRUE;
else if(rv > 0) {
ISOCKET_Cancel(pme->pISocket,CommonReadCB,pme);
DisplayOutput(pme,3,pszRecvData);
}
}
break;
}
default:
break;
}
return TRUE;
}
return FALSE;
}
/*!
* @brief: 讀回調(diào)函數(shù)
* @para: pUser指向用戶的指針
*/
void CommonReadCB(void *pUser)
{
CNetSocket * pMe = (CNetSocket*)pUser;
ISocket *piSock = pMe->pISocket;
switch (pMe->APIFnType) {
case USAGE_BASIC_USAGE:
{
int32 rv;
char szBuf[100] = {0};
rv = ISOCKET_Read(piSock, (byte *)szBuf, sizeof(szBuf));
//由于ISOCKET_Read函數(shù)是立即返回,所以這里直接可以從其返回值
//rv來判定執(zhí)行狀況,如果是AEE_NET_WOULDBLOCK說明沒有可用數(shù)據(jù)
//但是連接仍然有效,即,仍然處于接受數(shù)據(jù)的有效狀態(tài)
if (rv == AEE_NET_WOULDBLOCK) {
ISOCKET_Readable(piSock, CommonReadCB, (void*)pMe);
return;
}
//如果套接字未處于接收數(shù)據(jù)的有效狀態(tài),則返回AEE_NET_ERROR錯誤
else if (rv == AEE_NET_ERROR)
DisplayOutput (pMe, 1, "Read Error!");
//如果“rv > 0”則表示讀取成功,rv大小表示讀取的字節(jié)數(shù)目
else if (rv > 0)
DisplayOutput (pMe, 4, szBuf);
//如果不再有需要接受的數(shù)據(jù),且對等端已經(jīng)斷開連接,則返回0
else
DisplayOutput (pMe, 1, "No Data!");
}
break;
case USAGE_SOCKET_WRITE:
case USAGE_SOCKET_WRITEABLE:
{
int32 rv;
char szBuf[100] = {0};
rv = ISOCKET_Read(piSock, (byte*)szBuf, sizeof(szBuf));
if (rv == AEE_NET_WOULDBLOCK) {
ISOCKET_Readable(piSock, CommonReadCB, (void*)pMe);
return;
}
else if (rv == AEE_NET_ERROR)
DisplayOutput (pMe, 1, "Read Error!");
else if (rv > 0)
DisplayOutput (pMe, 1, szBuf);
?? 快捷鍵說明
復(fù)制代碼
Ctrl + C
搜索代碼
Ctrl + F
全屏模式
F11
切換主題
Ctrl + Shift + D
顯示快捷鍵
?
增大字號
Ctrl + =
減小字號
Ctrl + -