【问题标题】:UDP socket - C programming Bind and broadcastUDP套接字-C编程绑定和广播
【发布时间】:2019-08-06 22:52:12
【问题描述】:

所以,下面是我从公司继承的代码(由我不知道是谁编写的),该代码目前适用于我的特定场景: 设备(信号发生器)向我发送 UDP 数据,我需要接收、分析它们,有时还需要向设备发送命令(基于分析)。这是它的样子:

/*********************************************
        **  Communication Struct.
    **********************************************/

typedef struct CtxCom
{
  int                   socket_client;     //socket
  char*                 cmd;               //command
  char*                 recepbuff;         //recepbuff

  struct sockaddr_in    addr_client;       //contains IP and PORT

}CtxCom;


extern struct CtxCom init_Ctx_com ( char* IP_client, const int PORT_client, struct timeval timeout )
{

    CtxCom ClientCom; //define struct
    ClientCom.socket_client = socket(AF_INET, SOCK_DGRAM, 0); //Create the socket

    if(ClientCom.socket_client < 0) //Check the creation of the socket
    {
      perror("[Init_Com] socket()");
      exit(errno);
    }

    struct sockaddr_in addr_me = { 0 }; //create the server struct

    addr_me.sin_addr.s_addr = htonl(INADDR_ANY); //any incoming IP 
    addr_me.sin_port = htons(PORT_client);
    addr_me.sin_family = AF_INET; //address family

    if(bind(ClientCom.socket_client,(struct sockaddr *) &addr_me, sizeof(addr_me)) < 0) //bind the socket
    {
      perror("[Init_Com] bind()");
      exit(errno);
    }

    //conf equipment side
    ClientCom.addr_client.sin_addr.s_addr = inet_addr(IP_client);
    ClientCom.addr_client.sin_port = htons(PORT_client);
    ClientCom.addr_client.sin_family = AF_INET;

    //timeout
    //setsockopt(ClientCom.socket_client , SOL_SOCKET, SO_RCVTIMEO, (const char *)&timeout , sizeof (struct timeval));
    //fcntl(ClientCom.socket_client, F_SETFL, O_NONBLOCK); //set socket to non block

    //Printf info
    printf("[Init CtxCom]");
    printf(" Socket connected and Client[%s:%d] configured *************** \n",
            inet_ntoa(ClientCom.addr_client.sin_addr),
            ntohs(ClientCom.addr_client.sin_port) );

  return ClientCom;

}


/*Write char* cmd of size cmdSize in the socket specified*/
extern void write_client(struct CtxCom CtxCom, char* cmd, int cmdSize)
{
    //adding 0x0a 0x0d to the end of a CMD
    cmdSize+=2;
    cmd[cmdSize-2]='\r';
    cmd[cmdSize-1]='\n';

    //send CMD
    if(sendto(CtxCom.socket_client, cmd, cmdSize, 0, (struct sockaddr *)&(CtxCom.addr_client), sizeof(CtxCom.addr_client)) < 0)
    {
      perror("[Write_client] send()");
      exit(errno);
    }
    else
    {
      //printf( "\n***************SEND OK [%s:%d]******************\n"
        //    ,inet_ntoa(CtxCom.addr_client.sin_addr), ntohs(CtxCom.addr_client.sin_port) );
    }
}




* Give in output the char* strings outStringLLRX with a size of sizeOutStringLLRX*/
extern void read_client(
    /*input*/  struct CtxCom CtxCom, struct timeval timeout,
    /*output*/ char** outStringLLRX, int* sizeOutStringLLRX)
{
    //timeout forced
    //timeout.tv_usec=TIMEOUT_LISTEN_GIII;

    //Define variables
    fd_set      readfs;
    int         loop=1;
    int         i=0, k=0, z=0, z_prev=0;
    int         res;
    char        buf[25500];
    int         sizeBuf;

    //Init variables
    memset(buf, '\0' ,sizeof(buf));
    for(i=0;i<NB_CHANNELS_LLRX;i++)
    {
        sizeOutStringLLRX[i]=0;
        outStringLLRX[i][0]='\0';
    }

    //Make sure buffer is empty
    memset(buf, '\0' ,sizeof(buf));         //empty recep buffer
    FD_ZERO(&readfs);                       //zero testing
    FD_SET(CtxCom.socket_client, &readfs);  // set testing

    //block until input becomes available
    res=select(CtxCom.socket_client+1, &readfs, NULL, NULL, &timeout);

    switch (res)
    {
        case 0: //timeout
            printf("TIMEOUT error [Read Client] - No data received \n");
            break;

        case -1: //error
            printf("Error [Read Client] \n");
            break;

        default : //streams event
            if( FD_ISSET(CtxCom.socket_client, &readfs) )
            {
                sizeBuf=recvfrom (CtxCom.socket_client, buf , 25500, 0, NULL, NULL); //already now wich IP, no need to update
                if ( sizeBuf<0 )  //if <0 => no data => error
                {
                    printf("[Read_Client] Read failed : SizeBuf<0 \n");
                }
                else
                {
                    printf("[Read_Client] Got a buffer of size %d (round %d) \n", sizeBuf, k);
                    (sizeOutStringLLRX[0])+=sizeBuf;
                    for( z=0; z<sizeBuf; z++) {outStringLLRX[0][z_prev]=buf[z]; z_prev++;}
                }
            }
            break;

    }//switch


  //printf("[Read_Client] final size =%d\n", z_prev);
  /*printf("***************RECV OK [%s:%d]******************\n",
          inet_ntoa(CtxCom.addr_client.sin_addr),ntohs(CtxCom.addr_client.sin_port) );*/
}

我已经阅读了 socket 课程和 bind() man,但我仍然想知道:如果我有另一个设备在同一子网上发送数据,但在广播中(在 x.255 上)。这会污染插座吗?有时当我从我的设备接收数据时在同一个套接字上我收到了广播而不是(或另外)? 就我而言,bind 实际上只是为了给套接字“命名”,而不是像评论中写的那样接受任何传入的 IP 地址?

(顺便说一句,如果这里写的东西真的很糟糕,请告诉我,我很乐意让这段代码变得更好)

【问题讨论】:

    标签: c sockets bind


    【解决方案1】:

    您不必担心在套接字上接收广播数据包。假设是 Linux,man 7 ip 告诉我们“只有在设置 SO_BROADCAST 套接字标志时才能发送或接收广播地址的数据报”(该标志可以使用 setsockopt 设置,并记录在 man 7 socket 中)。

    bind()用来选择监听的端口,也包括哪个网络接口。该接口由其本地地址指定,INADDR_ANY 在这种情况下表示侦听所有网络接口(请参阅man 7 ip)。套接字将从所选接口上的任何(有效)IP 地址接收数据。

    【讨论】:

    • 好吧,如果没有这个广播标志,就不可能看到套接字上的广播流量? Bind 正在创建一种端点,但在本地机器上?并且使用 INADDR_ANY 它会自动选择本地机器上可用的本地 IP 吗?我的理解正确吗?谢谢
    猜你喜欢
    • 2010-10-22
    • 2013-06-03
    • 1970-01-01
    • 2023-03-23
    • 1970-01-01
    • 2014-10-20
    • 1970-01-01
    • 2012-05-28
    • 1970-01-01
    相关资源
    最近更新 更多