业务场景是主控机A和数据卡B通过UDP通信。由于软件测试,迫于环境需要本地进程间通信。直接将原先跑在两台设备的软件跑在同一台机器,置双方IP都为127.0.0.1。原先主控机和数据卡的接收端口都为6002,现同一台设备运行,两个进程端口不可以相同。将主控机的接收端口改为6003,即可正常通信。代码如下
UDP初始化库
/*-----------------------------------------------------------
**
** 文件名: UDP_Driver.c
**
** 描述: 定义了通过UDP进行通信所需的所有函数和变量
**
** 定义的函数:
** UDP_Init()
** UDP_Send()
** UDP_Recv()
**
** 设计注记:
**
**
**
**-----------------------------------------------------------
*/
/*UDP运行环境*/
#ifdef _WIN32
#define UDP_UNDER_VXWORKS 0
#else
#define UDP_UNDER_VXWORKS 2 /*Windows C++运行环境下定义为0, vxWorks5.x环境下定义为1, vxWorks6.x环境下定义为2*/
#endif
#if UDP_UNDER_VXWORKS > 0
//#include <sysIO.h>
#include <netinet/in.h>
#include <sockLib.h>
#include <string.h>
#include <stdio.h>
#include <fcntl.h>
#include "errnoLib.h"
#include "UDP_Driver.h"
#if UDP_UNDER_VXWORKS == 2
#ifndef SOCKADDR
//typedef struct sockaddr SOCKADD
#endif
#endif
typedef unsigned int SOCKET;
#else
#include <WinSock2.h>
#include <stdio.h>
#pragma comment(lib, "WS2_32.lib")
#include "UDP_Driver.h"
typedef char* caddr_t;
static WSADATA wsaData;
#endif
typedef struct sockaddr_in SockAddr_TYPE;
typedef struct
{
int (*Send)(void * const Handler, void * const Payload, int const LenBytes);
int (*Recv)(void * const Handler, void * const Buffer, int const MaxBytes);
SOCKET Recv_Socket;/*接收和发送的socket*/
SockAddr_TYPE Self_Recv_Address;/*配置接收IP与端口号,用于创建Recv_Socket*/
SockAddr_TYPE Peer_Send_Address;/*配置源端IP与端口号,用于判定接收数据来源*/
SockAddr_TYPE Peer_Recv_Address;/*配置目的IP与端口号,用于指定发送地址*/
} UDP_INNER_TYPE;
/*.BH-------------------------------------------------------------
**
** 函数名: UDP_Send
**
** 描述: UDP发送函数
**
** 输入参数:
** Handler : void * const, UDP句柄
** Payload : void * const, 发送数据指针
** LenBytes: int const, 发送数据长度
**
** 输出参数:
** 返回值: int, > 0, 发送成功(返回发送数据长度, 单位:BYTE)
** -1, 句柄无效
** -2, Payload为空或LenBytes小于1
** -3, Socket故障
**
** 设计注记:
**
**.EH-------------------------------------------------------------
*/
int UDP_Send(void * const Handler, void * const Payload, int const LenBytes)
{
UDP_INNER_TYPE * pUDP = (UDP_INNER_TYPE*)Handler;
int ret_val = 0;
if (pUDP == NULL)
ret_val = -1;
else if ((Payload == NULL) || (LenBytes < 1))
ret_val = -2;
else
{
ret_val = sendto(pUDP->Recv_Socket/*pUDP->Send_Socket*/, (caddr_t)Payload, LenBytes, 0, (SOCKADDR*)&pUDP->Peer_Recv_Address, sizeof(SockAddr_TYPE));
#if UDP_UNDER_VXWORKS > 0
if (ret_val == ERROR)
#else
if (ret_val == SOCKET_ERROR)
#endif
{
//printf(" UDP_Send Error %s\n", strerror(errno));
//printf("UDP_Send errno = %d\n", WSAGetLastError());
ret_val = -3;
}
}
return ret_val;
}
/* END of UDP_Send */
/*.BH-------------------------------------------------------------
**
** 函数名: UDP_Recv
**
** 描述: UDP接收函数
**
** 输入参数:
** Handler : void * const, UDP句柄
** Buffer : void * const, 存放接收数据的缓存指针
** MaxBytes: int const, Buffer的最大容量
**
** 输出参数:
** 返回值: int, >= 1, 实际获取到的数据长度(单位:BYTE)
** 0, 无数据可接收
** -1, 句柄无效
** -2, Buffer为空或MaxBytes长度不足
** -3, Socket故障
**
** 设计注记:
**
**.EH-------------------------------------------------------------
*/
int UDP_Recv(void * const Handler, void * const Buffer, int const MaxBytes)
{
UDP_INNER_TYPE * pUDP = (UDP_INNER_TYPE*)Handler;
SockAddr_TYPE Source_Address;
int Source_AddrSize = sizeof(SockAddr_TYPE);
int ret_val = 0;
if (pUDP == NULL)
ret_val = -1;
else if ((Buffer == NULL) || (MaxBytes < 1))
ret_val = -2;
else
{
while ((ret_val = recvfrom(pUDP->Recv_Socket, (char*)Buffer, MaxBytes, 0, (SOCKADDR*)&Source_Address, &Source_AddrSize)) > 0)
{
if ((0xC00A0050 == pUDP->Peer_Send_Address.sin_addr.s_addr) /*&& (Source_Address.sin_port == pUDP->Peer_Send_Address.sin_port)*/)
{
// just for test()MMP Send Data, data monitor in wireshark, but IDMP have no data recived!
}
/*对端往用XXXX发数据,本端就往对端的这个端口XXXX发数据(默认认为对端收发接口一致)*/
if ((Source_Address.sin_addr.s_addr == pUDP->Peer_Send_Address.sin_addr.s_addr) /*&& (Source_Address.sin_port == pUDP->Peer_Send_Address.sin_port)*/)
{
//printf("[UDP_Recv] recv port %d, %d\n", htons(Source_Address.sin_port), htons(pUDP->Self_Recv_Address.sin_port));
pUDP->Peer_Recv_Address.sin_port = Source_Address.sin_port;
break;
}
}
#if 0
ret_val = recvfrom(pUDP->Recv_Socket, (char*)Buffer, MaxBytes, 0, (SOCKADDR*)&Source_Address, &Source_AddrSize);
if(ret_val > 0){
if ((Source_Address.sin_addr.s_addr == pUDP->Peer_Send_Address.sin_addr.s_addr) /*&& (Source_Address.sin_port == pUDP->Peer_Send_Address.sin_port)*/)
{
pUDP->Peer_Recv_Address.sin_port = Source_Address.sin_port;
}
}
#endif
if (ret_val < 0){
ret_val = -3;
}
}
return ret_val;
}
/* END of UDP_Recv */
/*.BH-------------------------------------------------------------
**
** 函数名: UDP_Init
**
** 描述: UDP初始化接口函数
**
** 输入参数:
** Handler : UDP_STRUCT_TYPE * const, 需初始化的UDP句柄
** Peer_IP : unsigned int const, 对方设备IP地址
** Peer_Send_Port : unsigned short const, 对方设备发送UDP端口号
** Peer_Recv_Port : unsigned short const, 对方设备接收UDP端口号
** Self_IP : unsigned int const, 本方设备IP地址(单网卡环境可置零,多网卡环境必须指定通信网卡地址)
** Self_Send_Port : unsigned short const, 本方设备发送UDP端口号
** Self_Recv_Port : unsigned short const, 本方设备接收UDP端口号
** Recv_Cache : int const, 接收缓存大小(系统默认为8192, 大数据量时可增加)
** Recv_Block_Mode: int const, 接收模式: 0-阻塞, 1-非阻塞
**
** 输出参数:
** 返回值: int, >= 0, 初始化成功
** -1, 初始化失败(句柄无效)
**
** 设计注记:
**
**.EH-------------------------------------------------------------
*/
int UDP_Init(UDP_STRUCT_TYPE * const Handler, unsigned int const Peer_IP, unsigned short const Peer_Send_Port, unsigned short const Peer_Recv_Port,
unsigned int const Self_IP, unsigned short const Self_Send_Port, unsigned short const Self_Recv_Port, int const Recv_Cache, int const Recv_Block_Mode)
{
UDP_INNER_TYPE *pUDP = (UDP_INNER_TYPE*)Handler;
unsigned int Recv_Mode;
int Ret;
#if UDP_UNDER_VXWORKS == 0
static int First_Init = 1;
if (First_Init)
WSAStartup(MAKEWORD(2, 2), &wsaData);
First_Init = 0;
#endif
if (pUDP == NULL)
return -1;
/*send buffer默认100000*/
// if(0 == getsockopt(pUDP->Send_Socket, SOL_SOCKET, SO_SNDBUF, buffer, &Send_Cache))
// printf("udp send buff size %d\n", *(int*)buffer);
pUDP->Self_Recv_Address.sin_family = AF_INET;
pUDP->Self_Recv_Address.sin_addr.s_addr = htonl(Self_IP);
pUDP->Self_Recv_Address.sin_port = htons(Self_Recv_Port);
pUDP->Recv_Socket = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP);
Ret = bind(pUDP->Recv_Socket, (SOCKADDR*)&(pUDP->Self_Recv_Address), sizeof(SockAddr_TYPE));
if (Ret < 0)
{
printf("Bind Failed, Ret-%d, sock-%d\n", Ret, pUDP->Recv_Socket);
return -2;
}
if (Recv_Cache > 8192){
setsockopt(pUDP->Recv_Socket, SOL_SOCKET, SO_RCVBUF, (char*)&Recv_Cache, sizeof(int));
setsockopt(pUDP->Recv_Socket, SOL_SOCKET, SO_SNDBUF, (char*)&Recv_Cache, sizeof(int));
}
Recv_Mode = (Recv_Block_Mode > 0);
#if UDP_UNDER_VXWORKS > 0
ioctl(pUDP->Recv_Socket, FIONBIO, &Recv_Mode);
#else
ioctlsocket(pUDP->Recv_Socket, FIONBIO, (u_long*)&Recv_Mode);
#endif
pUDP->Peer_Send_Address.sin_family = AF_INET;
pUDP->Peer_Send_Address.sin_addr.s_addr = htonl(Peer_IP);
pUDP->Peer_Send_Address.sin_port = htons(Peer_Send_Port);
pUDP->Peer_Recv_Address.sin_family = AF_INET;
pUDP->Peer_Recv_Address.sin_addr.s_addr = htonl(Peer_IP);
pUDP->Peer_Recv_Address.sin_port = htons(Peer_Recv_Port);
pUDP->Send = UDP_Send;
pUDP->Recv = UDP_Recv;
return 0;
}
/* END of UDP_Init */
#undef SockAddr_TYPE
#if UDP_UNDER_VXWORKS > 0
#undef SOCKADDR
#undef SOCKET
#else
#undef caddr_t
#endif
#undef UDP_UNDER_VXWORKS
主控机初始化(A):
#define DLR_CARD_IP 0x7F000001/*0xAC100A0F*/
#define DLR_RECV_IDMP_PORT 6002
#define IDMP_RECV_DLR_PORT 6003/*6002*/
/*BASEIO_UDP0_CHANNEL_DLR:服务器端(DLR)IP地址:172.16.10.15*/
Ret = UDP_Init(&UDP_Handler[0], DLR_CARD_IP, DLR_RECV_IDMP_PORT, DLR_RECV_IDMP_PORT, IDMP_SIM_IP1, 0, IDMP_RECV_DLR_PORT, 64 * 1024, UDP_RECV_NONBLK);
if (Ret != 0) {
IOM_Report_Fault(Chn++, CDMP_FAIL);
USR_LOG(LOGER_IOSS, LOG4C_PRIORITY_ERROR, "%s, %d UDP_Init Error %d\n", "DLR", 0, Ret);
}
else {
IOM_Report_Fault(Chn++, CDMP_PASS);
}
数据卡端初始化(B):
#define UdpLocalIP 0x7F000001
#define DLR_RECV_IDMP_PORT 6002
#define IDMP_RECV_DLR_PORT 6003/*6002*/
Ret = UDP_Init(&UDP_Handler[BASEIO_UDP0_CHANNEL_DLR], UdpLocalIP/*0xAC100A10*/, IDMP_RECV_DLR_PORT, IDMP_RECV_DLR_PORT, UdpLocalIP, DLR_RECV_IDMP_PORT, DLR_RECV_IDMP_PORT, 64 * 1024, UDP_RECV_NONBLK);
if (Ret != 0) {
//IOM_Report_Fault(Chn++, CDMP_FAIL);
USR_LOG(LOGER_IOSS, LOG4C_PRIORITY_ERROR, "MCU UDP_Init Error %d\n", Ret);
}
这样,一个点对点的本地进程间UDP通信模型就建立完成了。
不论是A发B还是B发A,都可以正常通信。如果追求效率可以将SOCKET绑定为AF_UNIX,通过文件进行进程间数据收发。
**粗体** _斜体_ [链接](http://example.com) `代码` - 列表 > 引用
。你还可以使用@
来通知其他用户。