【发布时间】:2021-07-06 13:58:59
【问题描述】:
我正在尝试实现一个客户端服务器架构,其中客户端一次发送一个文件 1 行,服务器接收并确认它。它是使用 stop-n-wait 协议实现的。问题是客户端只能发送字符串,但不能发送整个结构数据包。我知道这一点是因为我确定了数据包的整数值并且它们出错了,而字符串部分在服务器端是正确的。
服务器端代码 data.seq_no 和 data.size 都是垃圾值。这就是问题
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <arpa/inet.h>
#include <sys/socket.h>
#include <unistd.h>
#include <signal.h>
#include <stdbool.h>
#define PORT 4444
#define MAX_PACKET_SIZE 200
#define MAXPENDING 5
typedef struct packet{
char data[MAX_PACKET_SIZE];
int size;
int seq_no;
bool last_pkt;
bool type;
}PKT;
char db[2000];
void die(char *s){
printf("%s\n", s);
exit(0);
}
int main(){
int s;
struct sockaddr_in servr, cli;
int slen=sizeof(servr);
if((s=socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP))==-1)
die("creating");
printf("socket created successfully\n");
memset(&servr, 0, sizeof(servr));
servr.sin_family = AF_INET;
servr.sin_addr.s_addr = htonl(INADDR_ANY);
servr.sin_port = htons(PORT);
if(bind(s, (struct sockaddr*)&servr, sizeof(servr))==-1)
die("connection failed");
printf("connected to the server\n");
int curr = 0;
PKT data;
while(1){
if(recvfrom(s, &data, sizeof(data), 0, (struct sockaddr*)&cli, &slen)==-1)
die("recvfrom()");
printf("RECV PKT: seq no. = %d, size = %d\n", data.seq_no, data.size);
printf("%d\n", data.size);
for(int i = 0; i<data.size; ++i)
db[curr+i]==data.data[i];
curr+=data.size;
int flag = rand()%10;
if(flag!=0){
data.size = 0;
data.type = 0;
if(sendto(s, &data, sizeof(data), 0, (struct sockaddr*)&cli, slen)==-1)
die("sendto()");
printf("SENT ACK: seq no = %d\n", data.seq_no);
}
else{
printf("DROP DATA: seq no = %d, size = %d\n", data.seq_no, data.size);
}
}
close(s);
}
客户端代码 generate_packet 生成正确的数据包。它生成包含 1 行文本的数据包,直到 '\n'。它还包含 char 数组和其他整数/布尔值的大小
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <arpa/inet.h>
#include <sys/socket.h>
#include <unistd.h>
#include <signal.h>
#include <stdbool.h>
#define PORT 4444
#define MAX_PACKET_SIZE 100
typedef struct packet{
int size;
int seq_no;
bool last_pkt;
bool type; //true is data and false is ack
char data[MAX_PACKET_SIZE];
}PKT;
void die(char *s){
printf("%s\n", s);
exit(1);
}
PKT generate_packet(int start){
FILE *fp;
fp = fopen("input.txt", "r");
fseek(fp, start, SEEK_SET);
PKT packet;
int count = 0;
char ch;
while((ch = fgetc(fp))!=EOF && ch!='\n')
packet.data[count++] = ch;
packet.data[count++] = '\0';
packet.size = count;
if(ch==EOF)
packet.last_pkt=true;
else
packet.last_pkt=false;
packet.type=true;
packet.seq_no = start;
fclose(fp);
return packet;
}
int main(){
int s;
struct sockaddr_in servr, cli;
int slen=sizeof(servr),retval;
struct timeval tv;
fd_set set;
if((s=socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP))==-1)
die("creating");
printf("socket created successfully\n");
memset(&servr, 0, sizeof(servr));
servr.sin_family = AF_INET;
servr.sin_addr.s_addr = inet_addr("127.0.0.1");
servr.sin_port = htons(PORT);
struct packet* data_pkt = malloc(sizeof(struct packet));
data_pkt->last_pkt=false;
int start = 0;
while(data_pkt->last_pkt!=true){
(*data_pkt) = generate_packet(start); //get the packet here
printf("packet generated, %d, %d, %d\n", data_pkt->seq_no, data_pkt->last_pkt, data_pkt->size);
start+=data_pkt->size;
if(sendto(s, data_pkt, sizeof(*data_pkt), 0, (struct sockaddr*)&servr, slen)==-1)
die("sendto()");
printf("SENT DATA, seq_no = %d, size = %d\n", data_pkt->seq_no, data_pkt->size);
while(1){
tv.tv_sec = 2;
tv.tv_usec = 0;
FD_ZERO(&set);
FD_SET(s, &set);
retval = select(s+1, &set, NULL, NULL, &tv);
if (retval == -1)
die("error");
else if (retval == 0){
if(sendto(s, data_pkt, sizeof(*data_pkt), 0, (struct sockaddr*)&servr, slen)==-1)
die("sendto()");
printf("RESENT DATA, seq_no = %d, size = %d\n", data_pkt->seq_no, data_pkt->size);
}
else{
if(recvfrom(s, data_pkt, sizeof(*data_pkt), 0, (struct sockaddr*)&servr, &slen)==-1)
die("receiving error");
printf("RECEIVED ACK: seq no = %d\n", data_pkt->seq_no);
break;
}
}
}
close(s);
}
【问题讨论】:
-
服务器和客户端两个结构
packet是否相等?对于需要在程序之间共享的东西,把它放在两个程序都包含的头文件中。 -
谢谢!抱歉这么愚蠢的怀疑。这就是问题
-
OT: about:
void die(char *s){ printf("%s\n", s); exit(0);发生错误时调用此函数。通常,返回值 0 表示成功。建议使用:void die(char *s){ printf("%s\n", s); exit( EXIT_FAILURE );其中EXIT_FAILURE定义在stdlib.h
标签: c sockets network-programming udp