UDP文件传输程序在C中,而循环不会做任何事情

UDP文件传输程序在C中,而循环不会做任何事情,c,loops,sockets,udp,file-transfer,C,Loops,Sockets,Udp,File Transfer,我正在尝试用UDP制作一个文件传输程序,使用停止等待协议。客户端提示用户输入要传输的文本文件,如果存在,服务器将找到该文件,并以每次80个字符的数据包形式将其发送回。客户端发送文件名,服务器接收文件名的部分工作正常,但一旦我进入while1循环进行文件传输,就什么也没有发生。不知道为什么会这样,任何帮助都会很好!谢谢 客户c `#include <stdio.h> #include <stdlib.h> #include <string.h> #include

我正在尝试用UDP制作一个文件传输程序,使用停止等待协议。客户端提示用户输入要传输的文本文件,如果存在,服务器将找到该文件,并以每次80个字符的数据包形式将其发送回。客户端发送文件名,服务器接收文件名的部分工作正常,但一旦我进入while1循环进行文件传输,就什么也没有发生。不知道为什么会这样,任何帮助都会很好!谢谢

客户c

`#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <libgen.h>
#include <unistd.h>
#include <arpa/inet.h>
#include <netinet/in.h>
#include <sys/socket.h>
#include <sys/types.h>
#include <netdb.h>
#include <errno.h>

/*This source file lies the client side of the file transfer. Its job is to open a
socket and ask to connect with server
It should then ask user for input of the text file they wish to transfer.
Once server sends out the file in packets, the client will then place this data in an
output.txt file, viewable for the user*/

typedef struct packet{
    char pktData[80]; //data in each packet
}Packet;

typedef struct frame{
    int frame_kind; //ACK:0, SEQ:1 FIN:2
    int countOfChar; //count of characters in a packet
    int sq_no;
    int ack;
    Packet packet;
}Frame;

int offset = 4;

int main(){
    int sockfd = 0; //socket descriptor
    int countOfChar = 0; //count of characters in a packet
    char buffer[80]; //data in each packet
    char fileName[20];
    char pktData[80];

    //socklen_t addr_size;

    int frame_id = 0;
    int frame_id2 = 0;
    Frame frame_send; //frame being sent to server (for the filename)
    Frame frame_recv; //frame being received from the server (for the data)
    Frame name_send; 
    Frame name_recv;
    int ack_recv = 1;
    
    struct sockaddr_in serv_addr;
    struct sockaddr_in new_addr;
    memset(&serv_addr, '0', sizeof(serv_addr));
    
    
    // Open a socket
    if((sockfd = socket(AF_INET, SOCK_DGRAM, 0)) < 0){
        printf("Error creating socket");
        return 1;
    }
    // Server address structure
    serv_addr.sin_family = AF_INET;
    serv_addr.sin_port = htons(20000);
    serv_addr.sin_addr.s_addr = inet_addr("127.0.0.1");

    socklen_t addr_size = sizeof(serv_addr);

    //Sending File name
    printf("\nConnected to server successfully!\nEnter the file name: ");
    scanf("%[^\n]%*c",fileName);
    printf("\n");
    char buff[20];
    strcpy(buff, fileName);

    sendto(sockfd, &buff, sizeof(buff), 0, (struct sockaddr*)&serv_addr, sizeof(serv_addr));

 
        int new_addr_size = sizeof(new_addr);
        //int addr_size = sizeof(serv_addr);
        //writing file into output.txt
        FILE *fp = fopen("output.txt", "ab");

        //loop until theres no more to read
        while(1){
        int f_recv_size = recvfrom(sockfd, &frame_recv, sizeof(Frame), 0, (struct sockaddr*)&serv_addr, &addr_size);
        if (f_recv_size > 0 && frame_recv.frame_kind == 1 && frame_recv.sq_no == frame_id){
            fwrite(frame_recv.packet.pktData, 1, sizeof(frame_recv.packet.pktData), fp);
            //printf("[+]Frame %d received with %lu data bytes\n",frame_recv.sq_no, sizeof(frame_recv.packet.pktData));
            printf("Frame Received");
            
            frame_send.sq_no = 0;
            frame_send.frame_kind = 0;
            frame_send.ack = frame_recv.sq_no + 1;
            sendto(sockfd, &frame_send, sizeof(frame_send), 0, (struct sockaddr*)&serv_addr, addr_size);
            printf("[+]Ack Sent\n");
        }else{
            printf("[+]Frame Not Received\n");
        }
        frame_id++; 
        }
close(sockfd);
    return 0;

}
服务器.c

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <errno.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>

/*This source file lies the server side of the file transfer. Its job is to listen
for a connection and connect with client when prompted.
It should then read the file with the txt file name and start sending out packets of 
80 bytes each with the data of the given file name.*/

typedef struct packet{
    char pktData[80]; //data in each packet
}Packet;

typedef struct frame{
    int frame_kind; //ACK:0, SEQ:1 FIN:2
    int countOfChar; //count of characters in a packet
    int sq_no;
    int ack;
    Packet packet;
}Frame;

int main(){

    unsigned int size = 0;
    int listenfd = 0;
    int connfd = 0;
    char file_buff[20];
    char buffer[80];
    char FLAG[] = "NF"; //No file flag

    int frame_id = 0;
    int frame_id2 = 0;
    Frame name_recv;
    Frame name_send;
    Frame frame_recv;
    Frame frame_send;
    int ack_recv;

    struct sockaddr_in server_addr, client_addr;
    char sendBuff[1025];
    size = sizeof(client_addr);

    listenfd = socket(AF_INET, SOCK_DGRAM, 0);  //listening descriptor 
    printf("Server initiated...\n");

    memset(&server_addr, '0', sizeof(server_addr));
    memset(sendBuff, '0', sizeof(sendBuff));

    //Local address structure
    server_addr.sin_family = AF_INET;
    server_addr.sin_addr.s_addr = htonl(INADDR_ANY);
    server_addr.sin_port = htons(20000);

    //bind to local address
    bind(listenfd, (struct sockaddr*)&server_addr, sizeof(server_addr));
    
     // Receiving File Name
    recvfrom(listenfd, &file_buff, sizeof(file_buff), 0, (struct sockaddr*)&client_addr, &size);
    printf("Filename requested by client = %s\n",file_buff);

        if (access(file_buff, F_OK) != -1 ) { 
            printf("File exist!\n");
            FILE *fp = fopen(file_buff,"rb"); 
            while(1){
        
                if(ack_recv == 1){
                frame_send.sq_no = frame_id;
                frame_send.frame_kind = 1;
                frame_send.ack = 0;     
    
                fscanf(fp, "%s ", buffer);
                strcpy(frame_send.packet.pktData, buffer);
                sendto(listenfd, &frame_send, sizeof(Frame), 0, (struct sockaddr*)&client_addr, sizeof(client_addr));
                //printf("[+]Frame %d Sent with %lu data bytes\n",frame_send.sq_no, strlen(frame_send.packet.pktData));
                printf("Frame Sent");
                }
            int addr_size = sizeof(server_addr);
            int f_recv_size = recvfrom(listenfd, &frame_recv, sizeof(frame_recv), 0 ,(struct sockaddr*)&client_addr, &size);
        
            if( f_recv_size > 0 && frame_recv.sq_no == 0 && frame_recv.ack == frame_id+1){
                printf("[+]Ack Received\n");
                ack_recv = 1;
                }   
            else{
                printf("[-]Ack Not Received\n");
                ack_recv = 0;
                }   
            
            frame_id++;     
            }
        }
        else {
            printf("File doesn't exist\n");
            write(listenfd, FLAG, sizeof(FLAG));
            close(listenfd);
            return 0;
        }
 close(listenfd);
    return 0;

}
很抱歉advanced中的所有混乱和不必要的变量,我已经尝试了这么多选项,但都不起作用


第一个问题是,在尝试读取服务器程序之前,从未在服务器程序中初始化ack_recv。读取一个未初始化的变量,而该变量的地址尚未被占用

至少,读取了除1之外的值,因此服务器正在等待来自客户端的读取,而由于客户端正在服务器上等待,该读取从未出现。您需要将ack_recv初始化为1,以便服务器发送文件的第一部分

然而,代码中存在的问题比这更多

主要问题是它假设没有数据包丢失。UDP不保证交付。所以,如果一个包真的丢失了,一方将永远被卡住,等待一个没有到达的包。读取时,每侧应使用select以允许在等待时超时。如果超时触发,则应假定最后发送的数据包丢失并重新发送

对于客户端,这也意味着如果ACK丢失,它可以从服务器获取给定序列号的多个副本。因此,在收到该序列号之前,它不应该增加帧id

两边还有一个无限循环,因为里面有一个while1循环,没有中断、返回或退出。服务器需要知道何时停止发送,并且需要某种方式让客户端知道何时停止发送


此外,作为一般规则,在调试网络程序时,应使用tcpdump或wireshark跟踪双向传输的数据包。

循环中没有退出条件。while1循环结束,除非您有一个break语句退出循环。请更准确地描述问题,而不是什么都没有发生。输出到底是什么?程序在做什么?您可以通过在调试器中运行程序找到答案。现在的输出是打印文件名所需的所有语句。因此,一旦客户机提示文件名并将其发送,该名称就会按原样打印到服务器。然而,发生这种情况后,终端只是缓冲,它不会打印任何其他内容,也不会像超时一样提示新的终端行。我在帖子中添加了终端的图片!你是一个享受生活的人!我需要添加一个超时,但这是一个了不起的开始,非常感谢@CarolineSync,很高兴我能提供帮助。如果你觉得它有用的话,请随意使用。