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

📄 netsvr.c

📁 采集板软件和人机界面软件之间的通信协议实现。包含目标板(vxworks)和pc端(vc 6.0)两个代码
💻 C
字号:
/**********************************************************************
 chengjy@felab, copyright 2002-2004
 netSvr.c
 vxWorks作为server,双缓冲网络通讯,带网络监控,同时支持通讯协议
 函数:
		void netInit(int mode);
		void netCMDRecv();
		void netCMDExplain();
		void netCMDSend();
		void netCloseAll(int mode);
		void netCheckLink();
		char netCMDAdd(unsigned char *pBuff, int buffLen, int cmdNum, unsigned char priority);
		char netRecvSize(unsigned char *pBuff, int len);
 调用:
 		netTask.c
			extern char t0x0200(unsigned char *pBuff);
			extern char t0x0400(unsigned char *pBuff);
			extern char t0x1600(unsigned char*pBuff);
		netQueue.c
			extern void queueInit();
			extern char queueAdd(int index, unsigned char* pBuff, int pri);
			extern char queueDelHead(int index);
			extern char queueDelAll();
 被调用:
 		用户程序初始化部分
 		netTask.c
 **********************************************************************/
 
#include "vxWorks.h"
#include "taskLib.h"
#include "sockLib.h"
#include "ioLib.h"
#include "inetLib.h"
#include "logLib.h"
#include "string.h"
#include "fioLib.h"
#include "stdio.h"
#include "memLib.h"
#include "stdLib.h"
#include "semLib.h"
#include "netinet\\tcp.h"

#include "board.h"

/*通讯协议支持的命令*/
extern char t0x0200(unsigned char *pBuff);	/*参数配置*/
extern char t0x0400(unsigned char *pBuff);	/*reset*/  
extern char t0x1600(unsigned char*pBuff);	/*flash程序下载*/

/*缓冲队列操作*/
extern void queueInit();
extern char queueAdd(int index, unsigned char* pBuff, int pri);
extern char queueDelHead(int index);
extern char queueDelAll();
extern struct cmdSingle *queueHead[QUEUE_NUM];

int flagNetInit = NET_INIT_NULL;	/*服务器初始化标志,程序中省略了对应的判断和操作*/
int listenSkt;			/*命令通道侦听socket*/
int commuSkt;			/*命令通道通讯socket*/
SEM_ID semQueueRecv;	/*网络接收缓冲队列信号灯*/
SEM_ID semQueueSend;	/*网络发送缓冲队列信号灯*/
SEM_ID semCmdLink;		/*网络连接出错信号灯*/

void netInit(int mode);
void netCMDRecv();
void netCMDExplain();
void netCMDSend();
void netCloseAll(int mode);

void netCheckLink();

char netCMDAdd(unsigned char *pBuff, int buffLen, int cmdNum, unsigned char priority);
char netRecvSize(unsigned char *pBuff, int len);

/**********************************************************************
 void netInit(int mode)
 函数说明:	网络初始化程序
 参数:		mode,	分为MODE_NET_DEFAULT 和MODE_NET_REINIT	两种,
 					分别对应初始化侦听+通讯套接字和只
 					初始化通讯套接字两种。
 返回:		无
 调用:			
			void netCMDRecv();
			void netCMDExplain();
			void netCMDSend();
			void netCheckLink();
 		netQueue.c:
			extern void 	queueInit();
 被调用:	用户程序初始化模块
			void netCloseAll(int mode);
 **********************************************************************/
void netInit(int mode)
{
	struct	sockaddr_in  serverAddr;
	struct	sockaddr_in  clientAddr;
	int		sockAddrSize;
	int		i;
	char 	optval = 1;
	
	/*建立本地的侦听用套接字listenSkt 并bind和listen*/
	if(flagNetInit==NET_INIT_COMMUSKT)
		return;
	if((mode == MODE_NET_DEFAULT) && (flagNetInit == NET_INIT_NULL))
	{
		if((listenSkt = socket (AF_INET, SOCK_STREAM, 0)) == ERROR)
		{
			logMsg("netInit: can not open listen socket\n",0,0,0,0,0,0);
			return;
		}
		sockAddrSize = sizeof (struct sockaddr_in);
		bzero ((char *) &serverAddr, sockAddrSize);
		serverAddr.sin_family = AF_INET;
		serverAddr.sin_len = (u_char) sockAddrSize;
		serverAddr.sin_port = htons (LOCAL_SERVER_PORT);
		serverAddr.sin_addr.s_addr = htonl (INADDR_ANY);
		if (bind (listenSkt, (struct sockaddr *) &serverAddr, sockAddrSize) == ERROR)
		{
		    logMsg("netInit:unable to bind to port %d\n",LOCAL_SERVER_PORT,0,0,0,0,0);
		    close(listenSkt);
		    return;
		}
		logMsg("netInit: successfully bind to port\n",LOCAL_SERVER_PORT,0,0,0,0,0);
		if (listen (listenSkt, 1) == ERROR)
		{
			logMsg("netInit: can not listen to listen socket\n",0,0,0,0,0,0);
			close (listenSkt);        
			return;
		}
		flagNetInit=NET_INIT_LISTENSKT;	
	}

	/*接收外部联接,建立通讯套接字commuSkt*/
	if(flagNetInit==NET_INIT_LISTENSKT)
	{
		sockAddrSize = sizeof (struct sockaddr_in);
		commuSkt = accept(listenSkt, (struct sockaddr*)(&clientAddr), &sockAddrSize);
		if(commuSkt==ERROR)
		{
			logMsg("netInit: can not accept command socket\n",0,0,0,0,0,0);
			close (listenSkt);
			return;
		}
		setsockopt (commuSkt, IPPROTO_TCP, TCP_NODELAY, &optval, sizeof (optval));
		/*初始化网络通讯的缓冲对列*/
		queueInit();  
		/*初始化缓冲队列的计数型信号灯*/
		semQueueSend = semCCreate(SEM_Q_FIFO,0);
		semQueueRecv = semCCreate(SEM_Q_FIFO,0);
		if((semQueueSend==NULL) ||(semQueueRecv==NULL))
		{
			semDelete(semQueueSend);
			semDelete(semQueueRecv);
		}
		/*发起网络命令循环接收任务、命令解释任务、命令发送任务和网络监控任务*/
		taskSpawn(TNAME_NETCHECKLINK,TPRI_NETCHECKLINK,0,USER_STACK_SIZE,
					(FUNCPTR)netCheckLink,0,0,0,0,0,0,0,0,0,0);	
		taskSpawn(TNAME_NETRECV,TPRI_NETRECV,0,USER_STACK_SIZE,
					(FUNCPTR)netCMDRecv,0,0,0,0,0,0,0,0,0,0);
		taskSpawn(TNAME_NETEXPLAIN,TPRI_NETEXPLAIN,0,USER_STACK_SIZE,
					(FUNCPTR)netCMDExplain,0,0,0,0,0,0,0,0,0,0);
		taskSpawn(TNAME_NETSEND,TPRI_NETSEND,0,USER_STACK_SIZE,
					(FUNCPTR)netCMDSend,0,0,0,0,0,0,0,0,0,0);
		flagNetInit = NET_INIT_COMMUSKT;
		logMsg("netInit: netInit finished\n",0,0,0,0,0,0);
	}
}


/**********************************************************************
 void netCMDRecv()
 函数说明:	信息接收任务。循环从网络获得信息,打包后
 				添加到缓冲队列,等待信息解释任务处理。
 参数:		无
 返回:		无
 调用:
			char netRecvSize(unsigned char *pBuff, int len)
 		netQueue.c
			char queueAdd(int index, unsigned char* pBuff, int pri);
 被调用:	
 			void netInit()
 **********************************************************************/
void netCMDRecv()
{
	unsigned char buff[8];
	unsigned char *pBuff;
	int lenAll;
	char pri;
	char state=STATUS_NORMAL;
	int i;
		
	/* 循环接收*/
	while(1)
	{
		if(netRecvSize(buff,8)!=STATUS_NORMAL)
		{
			logMsg("netCMDRecv: error in head Recv netRecvSize(buff,8)\n",0,0,0,0,0,0);
			break;
		}
		else		
		{

#ifdef LOG_NETMSG_HEAD	
			printf("netCMDRecv: print out head 8 bytes\n");
			for(i=0;i<8;i++)
				printf("0x%02x ",buff[i]);
			printf("\n");
#endif
			/*计算需要缓冲的总长度*/
			lenAll = ((buff[2]*0x1000000)&0xFF000000)+((buff[3]*0x10000)&0xFF0000)
						+((buff[4]*0x100)&0xFF00)+buff[5]; 				/*单条命令的总长度*/	
			pBuff = malloc(lenAll*sizeof(char));
			if(pBuff!=NULL)
			{
				memcpy(pBuff,buff,8*sizeof(char));
				if(lenAll>8)
				{
					state = netRecvSize(pBuff+8,lenAll-8);
					if(state!=STATUS_NORMAL)
					{
						logMsg("netCMDRecv: error in rear part recv netRecvSize(pBuff,%d)\n",lenAll-8,0,0,0,0,0);
						break;
					}
				}
				/*正确接收了所有数据,添加到接收缓冲队列中*/
				if(state== STATUS_NORMAL)
				{
					queueAdd(QUEUE_INDEX_RECV, pBuff, buff[6]);
					semGive(semQueueRecv);
				}
			}
		}
	}
	logMsg("netCMDRecv: something wrong, now exit\n",0,0,0,0,0,0);
}

/**********************************************************************
 void netCMDExplain()
 函数说明:	主循环消息处理和状态发送任务。循环获取信号灯
				获取成功后, 根据命令号执行相应任务。
 参数:		无
 返回:		无
 调用:
 		netQueue.c
 			char queueDelHead();
 		netTask:
 			STATUS t0xXXXX(char *pBuff);
 被调用:	
 			void netInit()
 **********************************************************************/
void netCMDExplain()
{
	unsigned char *pBegin;
	int 	CMDNum;
	char 	state;
	while(semTake(semQueueRecv,WAIT_FOREVER)== OK)
	{
		/*从队头取出信息*/
		pBegin = queueHead[QUEUE_INDEX_RECV]->pBuff;
		CMDNum = pBegin[0]*0x100+pBegin[1];
		/*这里只是示意性地作了几个命令的解释,用户应该根据
		自己的通讯协议再添加内容*/
		switch(CMDNum)
		{
			case 0x0200:
				state = t0x0200(pBegin);
				break;
			case 0x0400:
				state = t0x0400(pBegin);
				break;
			case 0x1600:
				state = t0x1600(pBegin);
				break;
			default:
				logMsg("netCMDExplain: command 0x%04x is not supported\n",CMDNum,0,0,0,0,0);
				break;
		}
		if(state == STATUS_NORMAL)
			logMsg("netCMDExplain: result of command 0x%04x is *OK*\n",CMDNum,0,0,0,0,0);
		else
			logMsg("netCMDExplain: result of command 0x%04x is *ERROR*\n",CMDNum,0,0,0,0,0);

		free(pBegin);
	
		queueDelHead(QUEUE_INDEX_RECV);
		
	}
	
	logMsg("netCMDExplain: error in taking semQueue\n",0,0,0,0,0,0);
}


/**********************************************************************
 void netCMDSend()
 函数说明:	循环从网络发送缓冲队列中取出数据并发送
 参数:		无
 返回:		无
 调用:		
  		netQueue.c
			char queueDelHead(int index);
 被调用:
		netTask.c
			char t0xXXXX(char *pBuff);
 **********************************************************************/
void netCMDSend()
{
	unsigned char *pBegin;
	int lenAll,remainLen,realLen;
	while(semTake(semQueueSend,WAIT_FOREVER)!=ERROR)
	{
		/*从队头取出信息*/
		pBegin = queueHead[QUEUE_INDEX_SEND]->pBuff;
		lenAll = ((pBegin[2]*0x1000000)&0xFF000000)+((pBegin[3]*0x10000)&0xFF0000)
					+((pBegin[4]*0x100)&0xFF00)+pBegin[5]; 				/*单条命令的总长度*/

		/*循环发送,直到发送完毕或者出错为止*/
		remainLen = lenAll;
		while(remainLen>0)
		{
			if(remainLen>NET_MSG_MAX_SIZE)
			{
				realLen =  send(commuSkt,pBegin+lenAll-remainLen,NET_MSG_MAX_SIZE,0);
			}
			else
			{
				realLen =  send(commuSkt,pBegin+lenAll-remainLen,remainLen,0);
			}
			if(realLen== ERROR)
			{
				logMsg("netCMDSend: unable to send command\n",0,0,0,0,0,0);
				semGive(semCmdLink);
				break;
			}
			remainLen = remainLen-realLen;
		}

		/*结束发送,释放空间*/
		free(pBegin);
		queueDelHead(QUEUE_INDEX_SEND);
		
		if(remainLen!=0)		/*发送出错,中途跳出的情况*/
			break;
	}
	logMsg("netCMDSend: something wrong, now exit\n",0,0,0,0,0,0);
}
	
/**********************************************************************
 void netCloseAll(int mode)
 函数说明:   	函数说明:  关闭侦听socket ,并删除命令缓冲
 				队列以及与socket相关的任务,并根据模式的
 				不同选择是直接关闭侦听套接字 (MODE_NET_DEFAULT) 
 				还是重新初始化网络(MODE_NET_REINIT)
 参数:		mode,	选择关闭方式
 返回:		无
 调用:		
 			void netInit(int mode);
 		netQueue.c
 			char queuDelAll();
 被调用: 	
 			void netCheckLink();
 			用户在shell下调用
 **********************************************************************/
void netCloseAll(int mode)
{
	int taskId;

	/*删除网络相关任务*/
	taskId = taskNameToId(TNAME_NETRECV);
	if(taskId!=taskIdSelf() && taskId!=ERROR)
	{
		taskDelete(taskId);
	}
	taskId = taskNameToId(TNAME_NETSEND);
	if(taskId!=taskIdSelf() && taskId!=ERROR)
	{
		taskDelete(taskId);
	}
	taskId = taskNameToId(TNAME_NETEXPLAIN);
	if(taskId!=taskIdSelf() && taskId!=ERROR)
	{
		taskDelete(taskId);
	}
	taskId = taskNameToId(TNAME_NETCHECKLINK);
	if(taskId!=taskIdSelf() && taskId!=ERROR)
	{
		taskDelete(taskId);
	}

	/*删除缓冲队列*/
	queueDelAll();
	/*删除缓冲队列的信号灯*/
	semDelete(semQueueRecv);
	semDelete(semQueueSend);

	/*删除网络通断检测用信号灯*/
	semDelete(semCmdLink);
	
	/*根据网络初始化的不同状态作相应的退出工作*/
	if(mode==MODE_NET_DEFAULT)
	{
		close(commuSkt);
		close(listenSkt);
		flagNetInit = NET_INIT_NULL;
	}
	else if(mode==MODE_NET_REINIT)
	{
		close(commuSkt);
		flagNetInit = NET_INIT_LISTENSKT;
		/*重新初始化网络*/
		logMsg("netCloseAll: reInitialize net server\n",0,0,0,0,0,0);
		taskDelete(taskNameToId(TNAME_NETINIT));
		taskSpawn(TNAME_NETINIT,TPRI_NETINIT,0,USER_STACK_SIZE,
					(FUNCPTR)netInit,mode,0,0,0,0,0,0,0,0,0);	
	}
}


/**********************************************************************
 void netCheckLink()
 函数说明:	监测网络状态,出错即关闭网络并重新初始化
 参数:		无
 返回:		无
 调用:
 			void netCloseAll(int mode)
 被调用:
 			void netInit();
 **********************************************************************/
void netCheckLink()
{
	/*由于优先极高,因此先创建信号灯才会进行网络的接收和发送*/
	semCmdLink = semBCreate(SEM_Q_FIFO,SEM_EMPTY);

	/*等待send()和recv()出错释放信号灯*/
	semTake(semCmdLink,WAIT_FOREVER);

	/*获得信号灯,表示网络连接断开*/
	semDelete(semCmdLink);
	taskSpawn(TNAME_NETCLOSEALL,TPRI_NETCLOSEALL,0,USER_STACK_SIZE,(FUNCPTR)netCloseAll,
				MODE_NET_REINIT,0,0,0,0,0,0,0,0,0);
}
			
/**********************************************************************
 char netRecvSize(unsigned char *pBuff, int len)
 函数说明:	底层函数,从网络接收数据
 参数:		pBuff,	接收数据存储的地方
 			len,		需要接受的总长度
 返回:		正确执行返回STATUS_NORMAL,否则返回错误
 调用:		无	
 被调用:	void netCMDRecv();
 **********************************************************************/
char netRecvSize(unsigned char *pBuff, int len)
{
	int recvLen,remainLen;
	if((len<=0) || (flagNetInit!=NET_INIT_COMMUSKT))
		return(STATUS_INVALID);
	else
		remainLen = len;
	while(remainLen>0)
	{
		recvLen = recv(commuSkt,pBuff+len-remainLen, remainLen,0);
		if( (recvLen==ERROR) || (recvLen ==0) )
		{
			semGive(semCmdLink);
			return(STATUS_ERROR);
		}
		remainLen = remainLen-recvLen;
	}
	return(STATUS_NORMAL);
}			

/**********************************************************************
 char netCMDAdd(unsigned char *pBuff, int buffLen, int cmdNum, unsigned char priority)
 函数说明:	添加内容到发送缓冲队列
 参数:		pBuff,	需要经过修改后添加的数组首地址
 			buffLen,	数组长度,单位为byte
 			cmdNum,命令号
 			priority,	优先级
 返回:		添加成功返回STATUS_NORMAL,否则返回错误
 调用:		
 		netQueue.c
			char queueAdd(int index, unsigned char* pBuff, int pri)
 被调用:
		netTask.c
			char t0xXXXX(char *pBuff);
 **********************************************************************/
char netCMDAdd(unsigned char *pBuff, int buffLen, int cmdNum, unsigned char priority)
{
	pBuff[0] = (cmdNum&0xFF00)>>8;
	pBuff[1] = cmdNum&0x00FF;
	pBuff[2] = ((buffLen>>24)&0xFF);
	pBuff[3] = ((buffLen>>16)&0xFF);
	pBuff[4] = ((buffLen>>8)&0xFF);
	pBuff[5] = (buffLen&0xFF);
	pBuff[6] = priority;
	pBuff[7] = 0;

	queueAdd(QUEUE_INDEX_SEND, pBuff, priority);
	semGive(semQueueSend);
	return(STATUS_NORMAL);
}


⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -