发送 struct UDP socket 两次而不是一次

Sending struct UDP socket twice instead of one

我是 c++ 新手,需要帮助。 我使用 UDP 服务器接收结构,但是我无法读取它,客户端发送一个我调用的结构:ChannAccessReq 所以结构被发送,服务器用 RECVFROM 接收它,我使用通过仅读取结构的 header (H1) 来获得一般结构,然后当条件满足时,我会使用更精确的缓冲区结构 (temp2) 进行读取。 但是客户端需要发送消息两次,第一次发送到 recvfrom,第二次发送到 read()(我认为)我试了一整天,想知道它的大小是否合适缓冲区的 ?

我认为最敏感的部分是在带有 recvfrom() 的服务器中,它的结构与紧随其后的 read() 不同。

希望清楚!

这是服务器:

#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <string.h>
#include <strings.h>
#include <arpa/inet.h>
#include <netinet/in.h>
#include <sys/types.h>
#include <sys/socket.h>
#include "struct.h"
#include <iostream>
void DieWithError(char *err) {
   perror(err);
   exit(1);
}

typedef struct IntMsgHeaderType {
  uint8_t code ;      // Code message7
  uint8_t bourrage ;  // Octet de bourrage
  uint16_t ParamLength; // Longueur eventuel données complémentaires

} HeaderInt;

typedef struct TextMessage //TESTTESTTEST
{
     HeaderInt H;      // Code message7


};

int main(int argc, char *argv[])
{
     int sock;                        /* Socket */
     struct sockaddr_in echoServAddr; /* Local address */
     struct sockaddr_in echoClntAddr; /* Client address */
     unsigned int cliAddrLen;         /* Length of incoming message */
     unsigned short echoServPort;     /* Server port */
     int recvMsgSize;                 /* Size of received message */

   struct TextMessage * temp = (TextMessage *)malloc(sizeof(struct TextMessage));
   HeaderInt *H1 =(HeaderInt *)malloc(104+sizeof(HeaderInt));
    ChanAccesReq *temp2=(ChanAccesReq *)malloc(sizeof(ChanAccesReq));
  if (!argv[1]) {
      fprintf(stderr,"no port number provided");
     exit(1);
  }

      echoServPort = atoi(argv[1]);  /* First arg:  local port */

    /* Create socket for sending/receiving datagrams */
  if ((sock = socket(PF_INET, SOCK_DGRAM, IPPROTO_UDP)) < 0)
    DieWithError("socket() failed");

  /* Construct local address structure */
  memset(&echoServAddr, 0, sizeof(echoServAddr));   /* Zero out structure */
  echoServAddr.sin_family = AF_INET;                /* Internet address family */
  echoServAddr.sin_addr.s_addr = htonl(INADDR_ANY); /* Any incoming interface */
  echoServAddr.sin_port = htons(echoServPort);      /* Local port */

  /* Bind to the local address */
  if (bind(sock, (struct sockaddr *) &echoServAddr, sizeof(echoServAddr)) < 0)
     DieWithError("bind() failed");

  for (;;) /* Run forever */
  {

         cliAddrLen = sizeof(echoClntAddr);
         int nbrOctet;

         if (recvfrom(sock, H1, sizeof(*H1), 0,(struct sockaddr *) &echoClntAddr, &cliAddrLen)>0 && H1->code==1){


         //read(sock,H1,sizeof(*H1));
         std::cout<<"taille nbrOctet : "<<nbrOctet<<'\n';
         memset(&echoServAddr, 0, sizeof(echoServAddr));   /* Zero out structure */

         read(sock, temp2, sizeof(*temp2));
                //read(sock,temp2,sizeof(*temp2))>0;
                    std::cout<<unsigned(temp2->P.linkAddr)<<'\n';

        };

   }

        close(sock);
        return 0;
  }

这里是客户

#include <stdio.h>
  #include <stdlib.h>
  #include <unistd.h>
  #include <string.h>
  #include <strings.h>
  #include <arpa/inet.h>
  #include <netinet/in.h>
  #include <sys/types.h>
  #include <sys/socket.h>
  #include "struct.h"

  void DieWithError(char *err) {
       perror(err);
       exit(1);
  }

typedef struct {

  char transMode ;
  uint8_t linkAddr;

} ChanAccessReqParam;


typedef struct {
HeaderInt H;
ChanAccessReqParam P;

} ChanAccesReq ;
  int main(int argc, char *argv[])
  {
       int sock;                        /* Socket descriptor */
       struct sockaddr_in echoServAddr; /* Echo server address */
       struct sockaddr_in fromAddr;     /* Source address of echo */
       unsigned short echoServPort;     /* Echo server port */
       unsigned int fromSize;           /* In-out of address size for recvfrom() */
       char *servIP;                    /* IP address of server */
       int structLen;                   /* Length of string to echo */
       int respStringLen;               /* Length of received response */


       if (!argv[1]) {
              fprintf(stderr,"No server IP sepcified at arg 1\n");
              exit(1);
       }

       else if (!argv[2]) {
              fprintf(stderr,"No port Number Sepcified at arg 2\n");
              exit(2);
       }




        ChanAccesReq test { 1 ,1,0,'c',15};
        

        servIP = argv[1];           /* First arg: server IP address (dotted quad) */
        echoServPort = atoi(argv[2]);  /* Use given port, if any */

        /* Create a datagram/UDP socket */
        if ((sock = socket(PF_INET, SOCK_DGRAM, IPPROTO_UDP)) < 0)
               DieWithError("socket() failed");

        /* Construct the server address structure */
        memset(&echoServAddr, 0, sizeof(echoServAddr));    /* Zero out structure */
        echoServAddr.sin_family = AF_INET;                 /* Internet addr family */
        echoServAddr.sin_addr.s_addr = inet_addr(servIP);  /* Server IP address */
        echoServAddr.sin_port   = htons(echoServPort);     /* Server port */

        int tempint = 0;


        tempint = sendto(sock, (ChanAccesInd*)&test, 10+(sizeof(test)), 0, (struct sockaddr *)
         &echoServAddr, sizeof(echoServAddr));

        if (tempint == -1 ) {

               printf("Sent struct size: %d\n", tempint);
               DieWithError("sendto() sent a different number of bytes than expected\n");
        }

        close(sock);
        exit(0);
}

感谢您的帮助

在 C++ 中,您必须定义参数的类型。 正如我从调用位置推断的那样,它应该是 int 和 bool。

int GesCanSlotSendTimeInd( int subscIPAddr , bool TransModeFlash){
    return 0;
}

也可以使用 const 限定符,但您还需要类型。

int GesCanSlotSendTimeInd( const int& subscIPAddr , const bool& TransModeFlash){
    return 0;
}

更多信息请查看cpp reference

您需要使用非阻塞模式同时轮询recvfrom和sendto。有关详细信息,请参阅 here

int main(int argc, const char** argv) {
  setvbuf(stdout, NULL, _IONBF, 0);

  int portnum = 9988;
  if (argc >= 2) {
    portnum = atoi(argv[1]);
  }
  printf("Listening on port %d\n", portnum);

  int sockfd = listen_inet_socket(portnum);
  struct sockaddr_in peer_addr;
  socklen_t peer_addr_len = sizeof(peer_addr);

  int newsockfd = accept(sockfd, (struct sockaddr*)&peer_addr, &peer_addr_len);
  if (newsockfd < 0) {
    perror_die("ERROR on accept");
  }
  report_peer_connected(&peer_addr, peer_addr_len);

  // Set nonblocking mode on the socket.
  int flags = fcntl(newsockfd, F_GETFL, 0);
  if (flags == -1) {
    perror_die("fcntl F_GETFL");
  }

  if (fcntl(newsockfd, F_SETFL, flags | O_NONBLOCK) == -1) {
    perror_die("fcntl F_SETFL O_NONBLOCK");
  }

  while (1) {
    uint8_t buf[1024];
    printf("Calling recv...\n");
    int len = recv(newsockfd, buf, sizeof buf, 0);
    if (len < 0) {
      if (errno == EAGAIN || errno == EWOULDBLOCK) {
        usleep(200 * 1000);
        continue;
      }
      perror_die("recv");
    } else if (len == 0) {
      printf("Peer disconnected; I'm done.\n");
      break;
    }
    printf("recv returned %d bytes\n", len);
  }

  close(newsockfd);
  close(sockfd);

  return 0;
}

“与阻塞版本的几个显着差异:

accept 编辑的newsockfd 套接字return 通过调用fcntl 设置为非阻塞模式。 在检查 recv 的 return 状态时,我们检查 errno 是否设置为表示没有数据可用于接收的值。在这种情况下,我们只休眠 200 毫秒,然后继续循环的下一次迭代。"

您仍然可以在同一个套接字上使用 send() 和 recvfrom(),因为如果您需要的话,您实际上并不需要 2 个不同的进程