关于socket:windows本地SOCKET通信

52次阅读

共计 7443 个字符,预计需要花费 19 分钟才能阅读完成。

业务场景是主控机 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,通过文件进行过程间数据收发。

正文完
 0