Глобальный массив теряет свое значение - PullRequest
0 голосов
/ 18 марта 2019

Я работаю над базовым кодом, который добавляет уровень надежности по протоколу UDP, добавляя идентификатор сообщения к каждому сообщению и ожидая подтверждения для этого сообщения. Я использовал следующие глобальные буферы:

struct message {
    char *msg;
    struct sockaddr_in *srce_addr;
} *receive;    //store received messages
int rec_i = 0;

struct messageNtime {
    int id;
    char *msg;
    time_t tm;
    struct sockaddr_in *des_addr;
} *unacknowledged_message;   //store unacknowledged messages
int unack_i = 0;

int *received_message_id;   //store message ids
int msg_i = 0;

Все буферы были динамически распределены во время вызова socket ():

receive = (struct message *) calloc(100, sizeof(struct message));
for (i = 0; i < 100; i++) receive[i].msg = (char *) calloc(100, sizeof(char));
unacknowledged_message = (struct messageNtime *) calloc(100, sizeof(struct messageNtime));
received_message_id = (int *) calloc(100, sizeof(int));

Основная проблема связана с буфером приема [] (пока). Есть функция 'HandleReceive', которая выглядит так:

void HandleReceive(int sockfd){
    char buf[100];
    struct sockaddr_in src_addr;
    socklen_t len=sizeof(src_addr);
    int n=recvfrom(sockfd, (char *)buf, 100, 0,(struct sockaddr *)&src_addr, &len);
    if(n==4) HandleACKMsgRecv(buf);
    else HandleAppMsgRecv(sockfd,buf,n,&src_addr);
    for(int a=0; a < rec_i; a++) printf("HanReceive[%d]: %s\n",a,receive[a].msg);  //garbage
}

Вызывает функцию 'HandleAppMsgRecv', которая вставляет полученное сообщение в буфер приема:

void HandleAppMsgRecv(int sockfd, char *buf, int n, struct sockaddr_in *src_addr){
char app_msg[n-3],app_id[4];  //buf contains a id component and a message component.
for ( i = 0; i < 4; i++) app_id[i]=buf[i];
for (i=0;i<n-4;i++) app_msg[i]=buf[i+4];
......
receive[rec_i].msg=app_msg;
receive[rec_i].srce_addr=src_addr;
rec_i++;
......
for(int a=0; a < rec_i; a++) printf("AppReceive[%d]: %s\n",a,receive[a].msg);  //Correct value
}

Когда я печатаю массив получения в конце (но внутри) HandleAppMsgRecv, я получаю ожидаемый вывод (буфер содержит полученное сообщение). Однако, когда я печатаю тот же массив после вызова HandleAppMsgRecv () в функции HandleReceive, я получаю некоторое значение мусора в индексе 1 st и нулевые значения в остальных индексах. Я вставляю значения по одному в буфер, и эта проблема возникает при каждой вставке.

Есть что-то, чего мне здесь не хватает? Кто-нибудь сталкивался с такой ситуацией раньше и может пролить свет? Я работаю над Ubuntu 16.04.

Я также прилагаю полный код на случай, если вы захотите запустить / проверить его.

#include <stdio.h>
#include <stdlib.h>
#include <pthread.h>
#include <string.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <sys/select.h>
#include <fcntl.h>
#include <arpa/inet.h>
#include <unistd.h>
#include "rsocket.h"

//rsocket.c
struct message{
  char *msg;
  struct sockaddr_in *srce_addr;
 }*receive;
int rec_i=0;

struct messageNtime{
  int id;
  char *msg;
  time_t tm;
  struct sockaddr_in *des_addr;
}*unacknowledged_message;
int unack_i=0;

int *received_message_id;
int msg_i=0;

unsigned int message_id=1;

pthread_t tid;
pthread_mutex_t lock_rec=PTHREAD_MUTEX_INITIALIZER,lock_unack=PTHREAD_MUTEX_INITIALIZER,lock_id=PTHREAD_MUTEX_INITIALIZER;

int search(int id){
  int i;
  for(i=0;i<msg_i;i++) if(received_message_id[i]==id) return 1;
  return 0;
}

void searchNdelete(int m_id){
  int i,j;
  for(i=0;i<unack_i;i++)
    if(unacknowledged_message[i].id==m_id){
        for(j=i;j<unack_i-1;j++) unacknowledged_message[j]=unacknowledged_message[j+1];
        unack_i--;
        break;
    }
}

void HandleAppMsgRecv(int sockfd, char *buf, int n, struct sockaddr_in *src_addr){
  printf("In HandleAppMsgRecv\n");
  printf("n=%d\n", n);
  char app_msg[n-3],app_id[4];
  int i,ap_id;
  printf("a\n");
  for ( i = 0; i < 4; i++) app_id[i]=buf[i];
  for (i=0;i<n-4;i++) app_msg[i]=buf[i+4];
  printf("b\n");
  app_msg[n-4]='\0';
  printf("c\n");
  ap_id=ntohl(*(int *)app_id);
  printf("Received MSG %d\n",ap_id );
  if(search(ap_id)==0){
    pthread_mutex_lock(&lock_rec);
    received_message_id[msg_i]=ap_id;
    msg_i++;
    receive[rec_i].msg=app_msg;
    receive[rec_i].srce_addr=src_addr;
    rec_i++;
    pthread_mutex_unlock(&lock_rec);
    for(i=0;i<rec_i;i++) printf("1.%s,%d ", receive[i].msg,strlen(receive[i].msg));
    printf("\n+++++++++++++++++++\n");
  }
  sendto(sockfd,app_id,4,0,(struct sockaddr *)src_addr, sizeof(*src_addr));
}

void HandleACKMsgRecv(char* buf){
  printf("In HandleACKMsgRecv\n");
  int ack_id=ntohl(*(int *)buf);
  printf("Received ACK %d\n",ack_id );
  searchNdelete(ack_id);
}

void HandleReceive(int sockfd){
  int n;
  char buf[100];
  struct sockaddr_in src_addr;
  socklen_t len;
  len=sizeof(src_addr);
  n=recvfrom(sockfd, (char *)buf, 100, 0,(struct sockaddr *)&src_addr, &len);
  if(n==4) HandleACKMsgRecv(buf);
  else HandleAppMsgRecv(sockfd,buf,n,&src_addr);
  for(int i=0;i<rec_i;i++) printf("2.%s,%d ", receive[i].msg,strlen(receive[i].msg));
}

void HandleRetransmit(int sockfd){
  // printf("In HandleRetransmit\n");
  int i;
  time_t now;
  time(&now);
  for (i = 0; i < unack_i; i++){
    if(difftime(now,unacknowledged_message[i].tm)>=T){
        unacknowledged_message[i].tm=now;
        sendto(sockfd, unacknowledged_message[i].msg, strlen(unacknowledged_message[i].msg), 0, (const struct sockaddr *)unacknowledged_message[i].des_addr, sizeof(*unacknowledged_message[i].des_addr));
    }
    }
}

void *threadX(void *args){
  int *socket=(int *)args;
  int sockfd,r;
  sockfd=*socket;
  struct timeval *t;
  t=(struct timeval *)calloc(1,sizeof(struct timeval));
  t->tv_sec=T;
  t->tv_usec=0;
  fd_set readfs;
  while(1){
    FD_ZERO(&readfs);
    FD_SET(sockfd,&readfs);
    r=select(sockfd+1, &readfs, 0,0,t);
    if(r==0){
        t->tv_sec=T;
        t->tv_usec=0;
        HandleRetransmit(sockfd);   
    }
    else if(FD_ISSET(sockfd,&readfs))
        HandleReceive(sockfd);
  }
}


int r_socket(int domain, int type, int protocol){
  int sockfd,i;
  if(type!=SOCK_MRP) return -1;
  //Initializing tables
  receive=(struct message *)calloc(100,sizeof(struct message));
  for(i=0;i<100;i++) receive[i].msg=(char *)calloc(100,sizeof(char));
  unacknowledged_message=(struct messageNtime *)calloc(100,sizeof(struct messageNtime));
  received_message_id=(int *)calloc(100,sizeof(int));

  sockfd=socket(domain,SOCK_DGRAM,protocol);
  //create thread
  pthread_create(&tid,0,threadX,&sockfd);
  sleep(1);
  return sockfd;
}

int r_bind(int sockfd, const struct sockaddr *addr, socklen_t addrlen){
  if(bind(sockfd,addr,addrlen)<0) return -1;
  else return 0;
}

int r_sendto(int sockfd, const void *buf, size_t len, int flags, const struct sockaddr *dest_addr, socklen_t addrlen){
  printf("In send\n");
  char msg[len+4];
  time_t curr_time;
  time(&curr_time);
  unsigned int id;
  int out;

  unacknowledged_message[unack_i].tm=curr_time;
  unacknowledged_message[unack_i].id=message_id;
  unacknowledged_message[unack_i].msg=(char *)buf;
  unacknowledged_message[unack_i].des_addr=(struct sockaddr_in *)dest_addr;
  unack_i++;

  id=htonl(message_id);
  memcpy(msg,&id,4);
  memcpy(&msg[4],buf,len);
  message_id++;

  out=sendto(sockfd, msg, len+4, flags, dest_addr, addrlen);
  printf("Out: %d\n", out);
  if(out>=0) return 0;
  return -1;
}

int r_recvfrom(int sockfd, void *buf, size_t len, int flags, struct sockaddr *src_addr, socklen_t *addrlen){
  printf("In recv\n");
   int i;
  // printf("rec_i: %d\n", rec_i);
  while(rec_i==0) sleep(0.1);
  pthread_mutex_lock(&lock_rec);
  memcpy(buf,receive[0].msg,strlen(receive[0].msg));
  rec_i--;
  printf("---------------\n");
  for(i=0;i<rec_i;i++) receive[i]=receive[i+1];
  bzero(receive[rec_i].msg,100);
  pthread_mutex_unlock(&lock_rec);
  return strlen(buf);
}

int r_close(int sockfd){
  while(unack_i>0);
  pthread_cancel(tid);
  free(receive);
  free(received_message_id);
  free(unacknowledged_message);
  pthread_mutex_destroy(&lock_id); 
  pthread_mutex_destroy(&lock_rec); 
  pthread_mutex_destroy(&lock_unack); 
  return close(sockfd);
}

С помощью заголовочного файла rsocket.h создайте библиотеку (ar -rcs librsocket.a rsocket.o), затем вы можете использовать функции r_socket, r_bind, r_recvfrom, r_sendto, r_close в базовой программе-клиенте сервера udp для тест.

#include <sys/socket.h>

#ifndef rsocket   //rsocket.h
#define rsocket

#define SOCK_MRP 1
#define T 2 //Timeout
#define p 2 //Timeout

int r_socket(int domain, int type, int protocol);
int r_bind(int sockfd, const struct sockaddr *addr, socklen_t addrlen);
int r_sendto(int sockfd, const void *buf, size_t len, int flags, const struct sockaddr *dest_addr, socklen_t addrlen);
int r_recvfrom(int sockfd, void *buf, size_t len, int flags, struct sockaddr *src_addr, socklen_t *addrlen);
int r_close(int sockfd);

#endif

1 Ответ

0 голосов
/ 20 марта 2019

Основная ошибка в HandleAppMsgRecv():

    receive[rec_i].msg=app_msg;

Хотя вы установили receive[].msg для указания на выделенную область памяти, вы перезаписываете указатель здесь адресом локального массива app_msg, время жизни которого заканчивается при выходе из функции.Конечно, правильно, например:

    memcpy(receive[rec_i].msg, app_msg, sizeof app_msg);

Незначительная ошибка в r_recvfrom():

  memcpy(buf,receive[0].msg,strlen(receive[0].msg));
  …
  return strlen(buf);

Для правильного использования strlen(buf), buf должен иметь завершающий нольсимвол в конце строки, который не скопирован указанным выше memcpy.Правильно, например:

  memcpy(buf, receive[0].msg, strlen(receive[0].msg)+1);    // plus the '\0'!
  …
...