Nano Hash - криптовалюты, майнинг, программирование

проблемы с отправкой структуры UDP Socket

Я новичок в С++ и мне нужна помощь. Я использую сервер UDP для получения структуры, однако у меня проблемы с ее чтением, клиент отправляет структуру, которую я вызываю: ChannAccessReq, поэтому структура отправляется, а сервер получает ее с помощью RECVFROM, и я использую общую структуру читая только заголовок (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);
}

спасибо за помощь

08.04.2021

  • Не связанное примечание: это не код C++. Это код C со случайным потоком ввода-вывода. 08.04.2021
  • согласен хд я обновляю 08.04.2021
  • Рекомендация: обратите немного больше внимания на значения, возвращаемые recvfrom и read. Да, отрицательное число — это явный сбой, но ноль и положительные числа содержат важную информацию, например, количество байтов, прочитанных из сокета. UDP более снисходителен, чем TCP, вы получаете одно и только одно полное сообщение, но это сообщение все равно может быть не совсем тем, что вы ожидали. 08.04.2021
  • @ user4581301 спасибо за вашу помощь, я изменю это, у вас есть идеи, как мне помочь? Я знаю его два разных типа, но я уверен, что есть способ, которым мне не нужно дважды отправлять сообщение, поскольку вся информация одинакова каждый раз, когда я отправляю 08.04.2021
  • При быстром чтении у меня ничего не выскочило, и я сейчас качаю коробку с Windows, поэтому не могу скомпилировать и промыть программу через отладчик. Говоря об отладчиках, вы должны иметь возможность использовать любой отладчик, поставляемый с вашими инструментами, чтобы прогуляться по серверу и точно увидеть, что он делает. В лучшем случае вы осознаете проблему и исправите ее. В худшем случае у вас есть больше информации, чтобы добавить к вопросу. 08.04.2021
  • Имейте в виду, мне было интересно, почему 104 в malloc(104 + sizeof(HeaderInt))? Если вы собираетесь читать sizeof(*H1), вы никогда не будете его использовать. И если я подумаю об этом немного дольше, это может быть вашей проблемой. 08.04.2021
  • На мгновение я подумал, что было бы полезно, если бы у меня был больший размер для моего буфера, я пытался многое добавить и пытался удалить, это ничего не меняет, не уверен, что проблема в этом, кстати, большое спасибо 08.04.2021

Ответы:


1

вы можете использовать флаг recvfrom, например PEEK, см. измененный код здесь:

 recvfrom(sock, HeaderStruct, sizeof(*HeaderStruct), MSG_PEEK,(struct sockaddr *) &echoClntAddr, &cliAddrLen);

и полный код здесь

#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 GesCanSrvRecvMsg(){

     int sock;                        // Socket
     struct sockaddr_in echoServAddr; // Adresse local
     struct sockaddr_in echoClntAddr; // Adresse Client
     unsigned int cliAddrLen;         // Longeur des messages entrant
     unsigned short echoServPort;     // Port Serveur
     unsigned recvMsgSize;                 // Taille message reçu

    //Creation allocation memoire necessaire pour recevoir les structures
   HeaderInt *HeaderStruct=(HeaderInt *)malloc(sizeof(HeaderInt));
   ChanAccesReq *ChanReqStruct=(ChanAccesReq *)malloc(sizeof(ChanReqStruct));
   TransTimeReq *TransTReqStruct=(TransTimeReq *)malloc(sizeof(TransTReqStruct));
   TransCancelReq *TransCReqStruct=(TransCancelReq *)malloc(sizeof(TransCReqStruct));
    //Port definie a 13000

   echoServPort = atoi("13000");  //Premier argument port local
  //Creation socket
  if ((sock = socket(PF_INET, SOCK_DGRAM, IPPROTO_UDP)) < 0)
    Error("socket() failed");

  //Construct local address structure
  memset(&echoServAddr, 0, sizeof(echoServAddr));
  echoServAddr.sin_family = AF_INET;
  echoServAddr.sin_addr.s_addr = htonl(INADDR_ANY);
  echoServAddr.sin_port = htons(echoServPort);

  //Bind a ladresse
  if (bind(sock, (struct sockaddr *) &echoServAddr, sizeof(echoServAddr)) < 0)
     Error("bind() failed");

  while(1) //Boucle infinie
  {

         cliAddrLen = sizeof(echoClntAddr);
         HeaderStruct->code=0;

         /*Attente des messages en ne regarde que l'entete Header
         Flag -> MSG_PEEK pour eviter un double envoie du client*/
         recvfrom(sock, HeaderStruct, sizeof(*HeaderStruct), MSG_PEEK,(struct sockaddr *) &echoClntAddr, &cliAddrLen);
         std::cout<<"coucou"<<'\n';
         char* subscIPAddr=inet_ntoa(echoClntAddr.sin_addr); // adresse iP Client



         if (unsigned(HeaderStruct->code)==ChanAccessReqc){ //Si code == ChanAccessReqC (1)
            recv(sock,ChanReqStruct,sizeof(*ChanReqStruct),0);
            CSMAChnAccessLstReq.push_back(*ChanReqStruct); //Placement dans liste partagée avec GesCanSlot


        }

        else if (unsigned(HeaderStruct->code==TransTimeReqc)){ //Si code == TransTimeReqc (3)
            recv(sock,TransTReqStruct,sizeof(*TransTReqStruct),0);
            CSMATimeTransmLstReq.push_back(*TransTReqStruct);

        }
        else if (unsigned(HeaderStruct->code==TransCancelReqc)){ //Si code == TransCancelReqc (3)
            recv(sock,TransCReqStruct,sizeof(*TransCReqStruct),0);
            TransacCancelLst.push_back(*TransCReqStruct);
        }

        else {
            Error("Error");
        }
   }
   close(sock);
};

int main(int argc, char *argv[])
{


        GesCanSrvRecvMsg();


        return 0;
  }

12.04.2021
  • Просто имейте в виду, что следующий read или recv может прочитать другую дейтаграмму. Дейтаграммы UDP всегда отбрасываются, и реализация может отбросить их в любое время, когда посчитает нужным, поэтому сообщение, которое вы просмотрели, может быть отброшено до того, как вы получите возможность read или recv его. Затем вы можете read или recv следующую дейтаграмму. 12.04.2021
  • Спасибо @DavidSchwartz за подробности, но, поскольку это тот же сокет, и мы просто делаем второе чтение того же сообщения, у нас не должно быть никаких проблем? Он просто использует другую структуру (как я понимаю) для анализа своего буфера? 12.04.2021
  • Почему вы думаете, что у него не будет проблем? Это потому, что вы не можете придумать, как это могло бы произойти? Вы не можете создать гарантию из своей неспособности думать о том, как что-то может пойти не так. Либо есть гарантия, либо нет. И нет никакой гарантии, что дейтаграмма UDP не будет отброшена. Я могу думать о том, как это может произойти, и видел, как это происходит, но это потому, что я программировал десятилетиями. Способ избежать необходимости в глубоких знаниях и опыте состоит в том, чтобы полагаться только на те гарантии, которые у вас действительно есть, и понимать, что когда говорят, что дейтаграммы можно отбросить, это факт. 12.04.2021
  • Новые материалы

    Кластеризация: более глубокий взгляд
    Кластеризация — это метод обучения без учителя, в котором мы пытаемся найти группы в наборе данных на основе некоторых известных или неизвестных свойств, которые могут существовать. Независимо от..

    Как написать эффективное резюме
    Предложения по дизайну и макету, чтобы представить себя профессионально Вам не позвонили на собеседование после того, как вы несколько раз подали заявку на работу своей мечты? У вас может..

    Частный метод Python: улучшение инкапсуляции и безопасности
    Введение Python — универсальный и мощный язык программирования, известный своей простотой и удобством использования. Одной из ключевых особенностей, отличающих Python от других языков, является..

    Как я автоматизирую тестирование с помощью Jest
    Шутка для победы, когда дело касается автоматизации тестирования Одной очень важной частью разработки программного обеспечения является автоматизация тестирования, поскольку она создает..

    Работа с векторными символическими архитектурами, часть 4 (искусственный интеллект)
    Hyperseed: неконтролируемое обучение с векторными символическими архитектурами (arXiv) Автор: Евгений Осипов , Сачин Кахавала , Диланта Хапутантри , Тимал Кемпития , Дасвин Де Сильва ,..

    Понимание расстояния Вассерштейна: мощная метрика в машинном обучении
    В обширной области машинного обучения часто возникает необходимость сравнивать и измерять различия между распределениями вероятностей. Традиционные метрики расстояния, такие как евклидово..

    Обеспечение масштабируемости LLM: облачный анализ с помощью AWS Fargate и Copilot
    В динамичной области искусственного интеллекта все большее распространение получают модели больших языков (LLM). Они жизненно важны для различных приложений, таких как интеллектуальные..