c - 全局数组失去值(value)

标签 c pointers udp ubuntu-16.04

我正在开发一个基本代码,通过向每条消息添加消息 ID 并等待该消息的确认,在 UDP 协议(protocol)上添加一层可靠性。我使用了以下全局缓冲区:

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 末尾(但在内部)打印接收数组时,我得到了预期的输出(缓冲区包含接收到的消息)。但是,当我在 HandleReceive 函数中调用 HandleAppMsgRecv() 后打印相同的数组时,我在第一个索引中得到一些垃圾值,在其余索引中得到空值。我将值一一插入缓冲区中,每次插入时都会出现此问题。

我在这里缺少什么吗?以前有人遇到过这种情况吗?可以透露一些信息吗?我正在 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),然后就可以在基本的udp服务器-客户端程序中使用r_socket、r_bind、r_recvfrom、r_sendto、r_close函数来测试。

#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

最佳答案

主要错误在 HandleAppMsgRecv() :

    receive[rec_i].msg=app_msg;

尽管您已设置 receive[].msg要指向已分配的内存区域,请使用本地数组的地址 app_msg 覆盖此处的指针其生命周期在函数退出时结束。正确的当然是e。例如:

    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 不会复制该字符。正确的是 e。例如:

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

关于c - 全局数组失去值(value),我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/55228085/

相关文章:

c - 指针算法在链表指针中不起作用?

C++ std::vector 问题

c - 硬件平方根 gcc

c - 在C中使用malloc实现aligned_malloc

c - 尝试在 ubuntu 上使用 c 学习漏洞利用

c++ - 带指针的模板类的析构函数

sockets - sendto() + recvfrom() 缓冲区混淆数据报

c - UDP:每 x 秒从客户端读取一个新帧

c - 多线程程序中不接收UDP并输出数据

关闭 SSH 连接,同时更改 IP 地址