📄 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: 小程序初始化函数
* @para: ClsId小程序的ClassID
* @para: pIShell底层传递来的指向IShell接口的指针
* @para: po指向IModule接口的指针
* @para: ppObj用于初始化以后返回AEEApplet结构的指针
* @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: 消息处理函数
* @para: pi指向IApplet接口的指针
* @para: eCode消息代码
* @para: wParam是16位的参数
* @para: dwParam是32位的参数
* @return: TRUE表示处理过,FALSE没有处理
*/
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)
//如果这里出现错误,又没有办法注册回调函数,所以错误是在ISocket接口中的
//ISOCKET_GetLastError()函数取得
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: 初始化函数
* @para: pme指向CNetSocket结构的指针
* @return: TRUE表示成功,FALSE表示失败
*/
boolean InitData(CNetSocket *pme)
{
pme->pINetMgr = NULL;
pme->pISocket = NULL;
pme->pIMenuCtl= NULL;
return TRUE;
}
/*!
* @brief: 资源释放函数
* @para: pme指向CNetSocket结构的指针
*/
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结构的指针
* @para: wParam传递到该函数的命令参数
* @retval: TRUE表示成功,FALSE表示失败
*/
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) {
//基础用法,先见识一下回调的工作方式
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;
//注意,这里必须注册回调函数来进行函数调用结果分析
case USAGE_NET_GETHOSTBYNAME:
CALLBACK_Init(&pme->cbkLookup, GetHostByNameCB, pme);
//注意必须保证在回调函数处理完成之前,pme->dnsresult一直存在
//还要注意,在调用INETMGR_Release()函数之前保证回调被清除,防止内存错误
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;
//设置网络延迟时间,返回值是以前的延迟时间,不能注册回调函数
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地址,不能注册回调函数
//由于返回值的IP不是字符串,所以要想显示先得转换
case USAGE_NET_GETMYIPADDRESS:
nodeINAddr = INETMGR_GetMyIPAddr(pme->pINetMgr);
ConvertToIPAddr(nodeINAddr, psz);
DisplayOutput(pme , 1, psz);
break;
//取得网络状态,网络的状态通过返回值取得,网络参数通过传入一个指针参数来获取
//这个函数也是不需要也不能注册回调函数
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()函数以外,还有一个比较特殊的函数
//这个函数可以将INetMgr接口产生的所有事件都全部截获,并在事件发生时调用一个
//回调函数来进行处理
//用于套接字和本地地址和端口相关联,只能用于未连接的套接字,通常是用于
//数据报套接字,第二个参数必须是AEE_INADDR_ANY,原因见API文档。此函数
//不能注册回调,执行情况通过返回值取得,如果阻塞,用ISOCKET_Writeable()
//注册一个回调函数等待可以传输时进行相应的处理,在回调函数中可以再次调
//用以取得最终结果,是成功还是失败,ISOCKET_Writeable() 可以获取再次调
//用Bind() 的时间通知。请注意,和Write()一样, ISOCKET_Writeable() 回调
//无法确保完成后续的Bind() 调用,因此调用程序必须准备再次接收
//AEE_NET_WOULDBLOCK,一旦绑定成功,可以进行读写操作了
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接口中比较简单的一个函数,不需要注册回调函数,直接返回结果
case USAGE_SOCKET_GETLASTERROR:
//此处还没有连接,所以调用Read函数会出错
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;
//以下这些功能的调用都没有直接在这里进行演示,而是都放在
//ConnectCBFun()函数中进行处理,原因很简单,这些操作都必
//须在网络接通的情况下进行,而网络连接的ISOCKET_Connect()
//函数是异步执行,需要注册一个回调函数,不管执行是否成功
//即:连接是否成功,都会调用回调函数,正确和错误的处理都
//必须在回调函数中进行,所以这些功能都必须在回调中处理
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);
//此函数用于将无符号短整型值从主机转换为网络字节顺序。
nPort = HTONS(USAGE_TEST_PORT);
//这里的ISOCKET_Connect()其实有两个作用,一个是网络连接
//另一个是进行回调的注册
if ((iRetValue = ISOCKET_Connect (pme->pISocket, nodeINAddr, nPort,
ConnectCBFun, (void *)pme)) != AEE_NET_SUCCESS)
if (iRetValue != AEE_NET_WOULDBLOCK) {
//函数ISOCKET_GetLastError不能注册回调,直接返回值
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: 读回调函数
* @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函数是立即返回,所以这里直接可以从其返回值
//rv来判定执行状况,如果是AEE_NET_WOULDBLOCK说明没有可用数据
//但是连接仍然有效,即,仍然处于接受数据的有效状态
if (rv == AEE_NET_WOULDBLOCK) {
ISOCKET_Readable(piSock, CommonReadCB, (void*)pMe);
return;
}
//如果套接字未处于接收数据的有效状态,则返回AEE_NET_ERROR错误
else if (rv == AEE_NET_ERROR)
DisplayOutput (pMe, 1, "Read Error!");
//如果“rv > 0”则表示读取成功,rv大小表示读取的字节数目
else if (rv > 0)
DisplayOutput (pMe, 4, szBuf);
//如果不再有需要接受的数据,且对等端已经断开连接,则返回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);
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -