UDP相关知识
1.对于UDP回调函数UDPCallback的UDP_DATAREADY事件,每次datagram达到时,都会产生回调事件("This event is received once per datagram that arrives")
2.无论使用单点发送(unicast)、多点发送(multicast)、广播发送(broadcast),都是使用UDPWrite()函数,只是地址(destinationAddress)不同,unicast为接收机的IP地址,multicast地址范围224.0.0.0~239.255.255.255,broadcast地址:255.255.255.255.("When selecting a multicast address for your application to use, avoid the range 224.0.0.0 to 224.0.0.255; this range is reserved for local network administrative and maintenance purposes.")
3.对于UDPRead函数,"If you pass 0 for inputBuffer or inputBufferSize, the function peeks at the port and returns the size of the first available datagram."
4.RadioGroup控件,记得在“Edit Item(s)”中修改每一项的值。否则默认都为0.
5.Labview软件UDP发送字符串时,没有发送字符串结束标志null,若已CVI相通信,得自己手动加入字符串结束标志位(十六进制显示00)。
UDP程序流程图
//Reader
#include <udpsupp.h>
#include <ansi_c.h>
#include <cvirte.h>
#include <userint.h>
#include "Read.h"
#define LOCAL_PORT 60100 //定义本地UDP端口
#define MULTICAST_ADDRESS "228.0.1.1" //多点传播地址
static int panelHandle;
static unsigned int UDPReadHandle=0; //UDP连接ID
int CVICALLBACK UDPReadCallBack (unsigned channel, int eventType, int errCode, void *callbackData);
int main (int argc, char *argv[])
{
if (InitCVIRTE (0, argv, 0) == 0)
return -1; /* out of memory */
if ((panelHandle = LoadPanel (0, "Read.uir", PANEL)) < 0)
return -1;
DisplayPanel (panelHandle);
SetCtrlVal(panelHandle,PANEL_NUMERIC,LOCAL_PORT); //显示本地UDP端口
SetCtrlVal(panelHandle,PANEL_STRING,MULTICAST_ADDRESS);//显示多点传送地址
CreateUDPChannelConfig (LOCAL_PORT, UDP_ANY_ADDRESS, 1, UDPReadCallBack, 0,& UDPReadHandle); //打开UDP端口
RunUserInterface ();
if(UDPReadHandle)
{
DisposeUDPChannel (UDPReadHandle); //关闭UDP端口
}
DiscardPanel (panelHandle);
return 0;
}
//是否订阅MULTICAST的回调函数
int CVICALLBACK SubscribMulticast (int panel, int control, int event,
void *callbackData, int eventData1, int eventData2)
{ int value;
switch (event)
{
case EVENT_COMMIT:
GetCtrlVal(panelHandle,PANEL_CHECKBOX,& value); //读取是否打钩
if(value) //若打钩,则订阅
{
UDPMulticastSubscribe (UDPReadHandle, MULTICAST_ADDRESS, NULL);
}
else //无打钩,则退订
{
UDPMulticastUnsubscribe (UDPReadHandle, MULTICAST_ADDRESS, NULL);
}
break;
}
return 0;
}
//关闭面板
int CVICALLBACK panelCB (int panel, int event, void *callbackData,
int eventData1, int eventData2)
{
switch (event)
{
case EVENT_CLOSE:
QuitUserInterface(0);
break;
}
return 0;
}
//UDP接收到数据时的回调函数
int CVICALLBACK UDPReadCallBack (unsigned channel, int eventType, int errCode, void *callbackData)
{
int size; //datagram的大小
char * receiveData; //接收到的数据
int sourcePort;
char sourceAddress[16];
char sourceString[16+20];
switch(eventType)
{
case UDP_DATAREADY:
//If you pass 0 for inputBuffer or inputBufferSize,
//the function peeks at the port and returns the size of the first available datagram
size = UDPRead (UDPReadHandle, 0, 0, UDP_DEFAULT_TIMEOUT, 0, 0);
receiveData=(char *)malloc(size*sizeof(char));
size = UDPRead (UDPReadHandle, receiveData, size, UDP_DO_NOT_WAIT, & sourcePort, sourceAddress);
sprintf(sourceString, "[%s:%d]: ", sourceAddress, sourcePort);
SetCtrlVal(panelHandle,PANEL_TEXTBOX,sourceString); //输出发送端的IP和端口号
SetCtrlVal(panelHandle,PANEL_TEXTBOX,receiveData);
SetCtrlVal(panelHandle,PANEL_TEXTBOX,"\n");
free(receiveData);
break;
}
return 0;
}
//Writer
#include <ansi_c.h>
#include <udpsupp.h>
#include "radioGroup.h"
#include <cvirte.h>
#include <userint.h>
#include "Write.h"
#define MULTICAST_ADDRESS "228.0.1.1" //定义多点传播地址
//广播发送地址为常量UDP_LAN_BROADCAST_ADDR
static int panelHandle;
unsigned int UDPWriteHandle=0; //UDP端口连接ID
unsigned int localPort; //UDP端口号
int main (int argc, char *argv[])
{
if (InitCVIRTE (0, argv, 0) == 0)
return -1; /* out of memory */
if ((panelHandle = LoadPanel (0, "Write.uir", PANEL)) < 0)
return -1;
Radio_ConvertFromTree (panelHandle, PANEL_RADIOGROUP);
DisplayPanel (panelHandle);
CreateUDPChannel (UDP_ANY_LOCAL_PORT, & UDPWriteHandle); //打开UDP端口
GetUDPAttribute (UDPWriteHandle, ATTR_UDP_PORT, & localPort);
SetCtrlVal(panelHandle,PANEL_LOCALPORT,localPort);
SetCtrlVal(panelHandle,PANEL_MULTICASTSTRING,MULTICAST_ADDRESS); //显示多点传播地址
SetCtrlVal(panelHandle,PANEL_BROADCASTSTRING,UDP_LAN_BROADCAST_ADDR); //显示广播发送地址
RunUserInterface ();
//释放UDP资源
if(UDPWriteHandle)
{
DisposeUDPChannel (UDPWriteHandle);
}
DiscardPanel (panelHandle);
return 0;
}
int CVICALLBACK SendData (int panel, int control, int event,
void *callbackData, int eventData1, int eventData2)
{
unsigned int stringLen; //待发送字符串长度
char * sendString; //待发送字符串
unsigned int destinationPort; //远程端口
unsigned int radioVal;
char address[16]; //假定输入IP地址无误(可以通过设置属性“最大可输入长度”来保证)。
switch (event)
{
case EVENT_COMMIT:
GetCtrlAttribute (panelHandle, PANEL_TEXTBOX, ATTR_STRING_TEXT_LENGTH, & stringLen);
stringLen++; //长度包括null
sendString=(char *)malloc(stringLen*sizeof(char));
GetCtrlVal(panelHandle,PANEL_TEXTBOX,sendString); //读取待发送的字符串
GetCtrlVal(panelHandle,PANEL_DESTINATIONPORT,& destinationPort); //读取远程端口值
GetCtrlVal(panelHandle,PANEL_RADIOGROUP,&radioVal); //读取发送方式
switch(radioVal)
{
case 0: //unicast
GetCtrlVal(panelHandle,PANEL_UNICASTSTRING,address);
break;
case 1: //multicast
GetCtrlVal(panelHandle,PANEL_MULTICASTSTRING,address);
break;
case 2: //broadcast
strcpy (address, UDP_LAN_BROADCAST_ADDR);
break;
}
UDPWrite (UDPWriteHandle, destinationPort, address, sendString, stringLen); //向远程端口发送数据
free(sendString);
break;
}
return 0;
}
//关闭面板
int CVICALLBACK panelCB (int panel, int event, void *callbackData,
int eventData1, int eventData2)
{
switch (event)
{
case EVENT_CLOSE:
QuitUserInterface(0);
break;
}
return 0;
}