⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 netsocket.c

📁 netsocket——深入研究BREW手机游戏开发Chapter10
💻 C
📖 第 1 页 / 共 2 页
字号:
/*!
 *	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 + -