vxWorks下的UDP通信程序--广播方式

来源:互联网 发布:酷家乐橱柜云设计软件 编辑:程序博客网 时间:2024/06/03 02:26

http://hi.baidu.com/tianhaixin8315/blog/item/1815e0cfec87ba5f0eb34569.html


最近需要编写一个vxWorks下的UDP通信程序,要求Server端广播发送,几个Client端接收数据,同时进行拆包处理。
在网上找了不少UDP广播发送的程序,不是讲的不太清楚,就是功能实现上有问题,最后参考VC下的UDP broadcast 例程实现了功能。
在这里和大家分享一下。

/*   udpServer.c   -   UDP   server   example   */    
     
/*    
DESCRIPTION    
This   file   contains   the   server-side   of   the   VxWorks   UDP   example   code.    
The   example   code   demonstrates   the   useage   of   several   BSD   4.4-style    
socket   routine   calls.    
*/    
     
/*   includes   */    
#include   "vxWorks.h"    
#include   "sockLib.h"    
#include   "inetLib.h"    
#include   "stdioLib.h"    
#include   "strLib.h"    
#include   "ioLib.h"    
#include   "fioLib.h"    
#include   "Define.h"    
#include   "taskLib.h"
#include   "string.h "
#include   "vxudpServer.h"
#include   "fsfb_main.h"
#include   "logLib.h"
/*********************************************************************    
*    
*   udpServer   -   read   from   UDP   socket   and   display   client's   message   if   requested      
*    
*   Example   of   VxWorks   UDP   server:    
*               ->   sp   udpServer    
*               task   spawned:   id   =   0x3a1f6c,   name   =   t2    
*               value   =   3809132   =   0x3a1f6c    
*               ->   MESSAGE   FROM   CLIENT   (Internet   Address   150.12.0.11,   port   1028):    
*               Greetings   from   UDP   client    
*    
*   RETURNS:   Never,   or   ERROR   if   a   resources   could   not   be   allocated.    
***********************************************************************/     
int udpInitialize(void);
int StartUdpRecv(void);
void OnReceiveThread(void);
int udpSendData(FSFB_MSG *fsfb_msg_send, int MSG_LEN,char * chNetAddr,int nPort);

struct   sockaddr_in     serverAddr;         /*   server's   socket   address   */    
struct   sockaddr_in     clientAddr;         /*   client's   socket   address   */     
int      sockAddrSize;     /*   size   of   socket   address   structure   */    
int      sFd;                       /*   socket   file   descriptor   */    
char     inetAddr[INET_ADDR_LEN];   /*   buffer   for   client's   inet   addr   */
BYTE nDataAddress = 0;
BYTE nDataType = 0;
int      nSendDataLen = 0;
BYTE     bQueInRslt   = 0;


char pBuf[1024]; //Recv data use
char strSendData[4096]; //send data use

int udpInitialize(void)    
{    
     
          /*   set   up   the   local   address   */    
     
          sockAddrSize   =   sizeof   (struct   sockaddr_in);    
          bzero   ((char   *)   &serverAddr,   sockAddrSize);    
          serverAddr.sin_len   =   (u_char)   sockAddrSize;    
          serverAddr.sin_family   =   AF_INET;    
          serverAddr.sin_port   =   htons   (SERVER_PORT_NUM);    
          serverAddr.sin_addr.s_addr   =   htonl   (INADDR_ANY);    //INADDR_BROADCAST,INADDR_ANY
     
          /*   create   a   UDP-based   socket   */    
     
          if   ((sFd   =   socket   (AF_INET,   SOCK_DGRAM,   0))   ==   ERROR)    
          {    
                  perror   ("socket");    
                  return   (ERROR);    
          }    
   //设置允许地址复用
   int flag = 1,ret;
   ret = setsockopt(sFd,SOL_SOCKET,SO_BROADCAST,(char *)&flag,sizeof(flag));
   if(ret!=0)
   {
   logMsg("setsockopt failed\n",0,0,0,0,0,0);
   close(sFd);
   return FALSE;
   }   
          /*   bind   socket   to   local   address   */    
     
          if   (bind   (sFd,   (struct   sockaddr   *)   &serverAddr,   sockAddrSize)   ==   ERROR)    
          {    
                  perror   ("bind");    
                  close   (sFd);    
                  return   (ERROR);    
          }  
   return TRUE;
}

int StartUdpRecv(void)
{
int udpNet=taskSpawn("udpNet",JUDGECOMPRIO,VX_NO_STACK_FILL,0x1000,(FUNCPTR)OnReceiveThread,0,0,0,0,0,0,0,0,0,0);
if (udpNet==ERROR)
{
   if (taskIdVerify(udpNet) == TRUE)
   {
    taskDelete(udpNet);
   }
   return FALSE;
}
}


   
          /*   read   data   from   a   socket   and   satisfy   requests   */    
void OnReceiveThread(void)
{     
memset(pBuf,0,sizeof pBuf);

FOREVER    
          {    
   if   (recvfrom   (sFd,   pBuf,   sizeof   pBuf,   0,    
                          (struct   sockaddr   *)   &clientAddr,   &sockAddrSize)   ==   ERROR)    
                {    
                          perror   ("recvfrom");    
                          close   (sFd);    
                          return;    
                }    
     
                  /*   if   client   requested   that   message   be   displayed,   print   it   */      
                {    
                          /*   convert   inet   address   to   dot   notation   */    
     
       inet_ntoa_b   (clientAddr.sin_addr,   inetAddr);    

       nDataAddress = pBuf[2];
      
       nDataType    = (BYTE)pBuf[1];
       logMsg("nDataType = 0x%x\n",nDataType,0,0,0,0,0);
       logMsg("nDataAddress = 0x%x\n",nDataAddress,0,0,0,0,0);
       if (nDataAddress == 0x10)
       {
        continue;
       }
      

       switch(nDataAddress)      //判断数据来源:由IP地址判断改成数据源地址判断
       {
        case CTCMSGAddress:
        logMsg("CTC que come in\n",0,0,0,0,0,0);
        if (nDataType == FSFB_MSG_ID_SSE)
        {
         bQueInRslt = InsertData(&(ctc_cbi_2_tcc_sse.SSEINQUE),(BYTE *)pBuf);
         logMsg("CTC sse come in : %d\n",bQueInRslt,0,0,0,0,0);
        }
        else if (nDataType == FSFB_MSG_ID_SSR)
        {
         bQueInRslt = InsertData(&(ctc_cbi_2_tcc_ssr.SSRINQUE),(BYTE *)pBuf);
         logMsg("CTC ssr come in : %d\n",bQueInRslt,0,0,0,0,0);
        }
        else if (nDataType == FSFB_MSG_ID_DATA)
        {
         bQueInRslt = InsertData(&(ctc_2_tcc_data.CTCINQUE),(BYTE *)pBuf);
         logMsg("CTC data come in : %d\n",bQueInRslt,0,0,0,0,0);
        }
          break;
        case CBIMSGAddress:
        if (nDataType == FSFB_MSG_ID_SSE)
        {
         bQueInRslt = InsertData(&(ctc_cbi_2_tcc_sse.SSEINQUE),(BYTE *)pBuf);
         logMsg("CBI sse come in : %d\n",bQueInRslt,0,0,0,0,0);
        }
        else if (nDataType == FSFB_MSG_ID_SSR)
        {
         bQueInRslt = InsertData(&(ctc_cbi_2_tcc_ssr.SSRINQUE),(BYTE *)pBuf);
         logMsg("CBI ssr come in : %d\n",bQueInRslt,0,0,0,0,0);
        }
        else if (nDataType == FSFB_MSG_ID_DATA)
        {
         bQueInRslt = InsertData(&(cbi_2_tcc_data.CBIINQUE),(BYTE *)pBuf);
         logMsg("CBI data come in : %d\n",bQueInRslt,0,0,0,0,0);
        }
        break;
        default:
        break;
       }

   
                  }
          }    
}  

int udpSendData(FSFB_MSG *fsfb_msg_send, int MSG_LEN,char * chNetAddr,int nPort)
{

    memset(strSendData,0,sizeof strSendData);
    memcpy(strSendData,fsfb_msg_send,MSG_LEN+2);

    serverAddr.sin_addr.s_addr = inet_addr(chNetAddr);
    if   ((nSendDataLen = sendto   (sFd,   strSendData,   MSG_LEN+2,   0,    
                  (struct   sockaddr   *)   &serverAddr,   sockAddrSize))   ==   ERROR)    
    {    
   perror   ("sendto");         
        return   (FALSE);    
    }
   
    if(nSendDataLen != MSG_LEN+2)
return -1;
    return   (TRUE);


}

广播发送的关键是设置socket的选项,允许地址复用,即给多个ip地址发送数据,而发送端只需发送一包数据。
   int flag = 1,ret;
   ret = setsockopt(sFd,SOL_SOCKET,SO_BROADCAST,(char *)&flag,sizeof(flag));
   if(ret!=0)
   {
         logMsg("setsockopt failed\n",0,0,0,0,0,0);
         close(sFd);
         return FALSE;
   }   

在发送数据时,将chNetAddr填写为 x.x.x.255,则x.x.x.*网段中的所有地址(1~254)都将接收到广播数据。