我正在使用 c 和 udp 套接字编程实现停止和等待。为了模拟这个协议,我写了两个代码。
这是我的server.c
文件:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <time.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <sys/socket.h>
#include <unistd.h>
#include <arpa/inet.h>
typedef struct packet{
char data[1024];
}Packet;
typedef struct frame{
int frame_kind; //ACK:0, SEQ:1 FIN:2
int sq_no;
int ack;
Packet packet;
}Frame;
int main(int argc, char** argv)
{
int sockfd;
int clilen;
int state;
int n;
int sum;
int recv_result;
int frame_id = 0;
Packet packet;
Frame frame;
Frame recv_frame;
char buffer[1024] = "";
struct timeval tv;
struct sockaddr_in serveraddr, clientaddr;
FILE* infile = fopen(argv[2], "r");
if(argc != 3)
{
perror("error! usage: $./server <PORT> filename\n");
exit(1);
}
if(infile == NULL)
{
printf("error! failed to open the file.\n");
exit(0);
}
clilen = sizeof(clientaddr);
sockfd = socket(AF_INET, SOCK_DGRAM, 0); //using diagram instead of stream-- UDP
if(sockfd < 0)
{
perror("socket error: ");
exit(0);
}
bzero(&serveraddr, sizeof(serveraddr));
serveraddr.sin_family = AF_INET;
serveraddr.sin_addr.s_addr = htonl(INADDR_ANY);
serveraddr.sin_port = htons(atoi(argv[1])); //set port number 9999
//set socket option -- timeout is 100000 microseconds
tv.tv_sec = 1;
tv.tv_usec = 0;
setsockopt(sockfd, SOL_SOCKET, SO_RCVTIMEO, (char*)&tv, sizeof(struct timeval));
state = bind(sockfd, (struct sockaddr*)&serveraddr, sizeof(serveraddr));
if(state == -1)
{
perror("bind error: ");
exit(0);
}
do{
n = fscanf(infile, "%s", buffer);
strcpy(packet.data, buffer);
memcpy(&(frame.packet), &packet, sizeof(Packet));
frame.frame_kind = 1; //SEQ
frame.sq_no = frame_id;
frame.ack = 0;
printf("flag2");
while(1)
{
sendto(sockfd, &frame, sizeof(frame), 0, (struct sockaddr*)&clientaddr, (socklen_t)clilen);
printf("Frame %d sent\n", frame_id);
recv_result = recvfrom(sockfd, &recv_frame, sizeof(recv_frame), 0,(struct sockaddr*)&clientaddr, &clilen );
if(recv_result > 0 && recv_frame.sq_no == 0 && recv_frame.ack == frame_id){
printf("Ack %d received\n", recv_frame.sq_no);
break;
}else{
printf("Frame %d time expired\n", frame_id);
}
}
frame_id++;
}while(n > 0);
printf("finished\n");
return 0;
}
这是我的client.c
文件:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <arpa/inet.h>
#include <sys/socket.h>
typedef struct packet{
char data[1024];
}Packet;
typedef struct frame{
int frame_kind; //ACK:0, SEQ:1 FIN:2
int sq_no;
int ack;
Packet packet;
}Frame;
int main(int argc, char *argv[])
{
int sock;
int str_len;
socklen_t adr_sz;
FILE* outfile = fopen("output.txt", "w");
struct sockaddr_in serv_adr, from_adr;
Frame ackframe, recv_frame;
int frame_id;
int recv_result;
struct timeval tv;
if(argc!=3){
printf("Usage : %s <IP> <port>\n", argv[0]);
exit(1);
}
sock=socket(PF_INET, SOCK_DGRAM, 0);
if(sock==-1)
{
printf("error! failed to open the socket\n");
exit(1);
}
memset(&serv_adr, 0, sizeof(serv_adr));
adr_sz = sizeof(serv_adr);
serv_adr.sin_family=AF_INET;
serv_adr.sin_addr.s_addr=inet_addr(argv[1]);
serv_adr.sin_port=htons(atoi(argv[2]));
tv.tv_sec = 1;
tv.tv_usec = 0;
setsockopt(sock, SOL_SOCKET, SO_RCVTIMEO, (char*)&tv, sizeof(struct timeval));
frame_id = 0;
while(1)
{
recv_result = recvfrom(sock, &recv_frame, sizeof(recv_frame), 0,(struct sockaddr*)&serv_adr, &adr_sz);
perror("error: ");
printf("data %s\n", recv_frame.packet.data);
printf("recv result %d\n", recv_result);
printf("recv frame=%d, frame_kind = %d\n", recv_frame.sq_no, recv_frame.frame_kind);
if(recv_result > 0 && recv_frame.frame_kind == 1 && recv_frame.sq_no==frame_id){
printf("Frame %d received\n", recv_frame.sq_no);
fprintf(outfile, "%s", recv_frame.packet.data);
ackframe.frame_kind = 0;
ackframe.ack = recv_frame.sq_no + 1;
printf("Ack %d sent\n", ackframe.ack);
sendto(sock, &recv_frame, sizeof(recv_frame), 0,(struct sockaddr*)&serv_adr, adr_sz);
break;
}else{
printf("Frame %d time expired\n", frame_id);
}
}
close(sock);
fclose(outfile);
return 0;
}
服务器需要 3 个参数:./server <port> <test.txt>
客户端还需要 3 个参数:./client <ip> <port>
它被执行,但recvfrom
客户端总是返回-1
。
我阅读了一些相同主题的问题,但无法从我的代码中找出错误。有没有办法用recvfrom
&修复我的代码sendto
?还是我需要使用select
功能?(我只会与一台服务器和一台客户端通信。)