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)。
程序流程圖
//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;
}