windows本地SOCKET通信

业务场景是主控机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_VXWORKS0 #else #define UDP_UNDER_VXWORKS2 /*Windows C++运行环境下定义为0, vxWorks5.x环境下定义为1, vxWorks6.x环境下定义为2*/ #endif#if UDP_UNDER_VXWORKS > 0 //#include #include #include #include #include #include #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 #include #pragma comment(lib, "WS2_32.lib")#include "UDP_Driver.h" typedef char* caddr_t; static WSADATA wsaData; #endiftypedef 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); SOCKETRecv_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; #endifif (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); #endifpUDP->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_IP0x7F000001/*0xAC100A0F*/ #define DLR_RECV_IDMP_PORT6002 #define IDMP_RECV_DLR_PORT6003/*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 UdpLocalIP0x7F000001 #define DLR_RECV_IDMP_PORT6002 #define IDMP_RECV_DLR_PORT6003/*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); }

【windows本地SOCKET通信】这样,一个点对点的本地进程间UDP通信模型就建立完成了。
不论是A发B还是B发A,都可以正常通信。如果追求效率可以将SOCKET绑定为AF_UNIX,通过文件进行进程间数据收发。

    推荐阅读