我正在研究一个基本代码,该代码通过向每个消息添加消息ID并等待对该消息的确认来增加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));
主要问题是使用了receive []缓冲区(到目前为止)。 有一个函数“ 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()调用之后打印相同的数组时,我在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),然后可以在基本的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
答案 0 :(得分:0)
主要错误在于HandleAppMsgRecv()
:
receive[rec_i].msg=app_msg;
尽管您已经设置receive[].msg
指向已分配的内存区域,但是您在此处用本地数组app_msg
的地址覆盖了指针,该数组的生存期在函数退出时结束。正确的当然是e。 g。:
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。 g。:
memcpy(buf, receive[0].msg, strlen(receive[0].msg)+1); // plus the '\0'!
…