首页 > 解决方案 > C 套接字编程 - UDP 序列中的文件传输

问题描述

我正在尝试通过套接字按顺序发送一个 mp3 文件。我发送 8194 字节的 txt 文件没有问题,但是任何其他文件类型似乎都不起作用。我一次发送一个数据包,然后接收该数据包的 ACK(停止并等待),但是我还没有实现超时。我将文件保存到 receivedFiles 目录,文件长度是正确的,但我无法打开文件,它说它是空的。

服务器端代码:

printf(">>> SERVER <<<\n");
        int sock;
        struct sockaddr_in serverAddress;
        struct sockaddr_in clientAddress;
        unsigned int clientAddressLength;

        int port = 5150;
        int fragmentSize = 500;

        if ((sock = socket (PF_INET, SOCK_DGRAM, IPPROTO_UDP)) < 0) {
            printf("Socket () failed\n");
            exit(0);
        }

        memset (&serverAddress, 0, sizeof (serverAddress));
        serverAddress.sin_family = AF_INET;
        serverAddress.sin_addr.s_addr = INADDR_ANY;
        serverAddress.sin_port = htons (port);

        if (bind (sock, (struct sockaddr *) &serverAddress, sizeof (serverAddress)) < 0) {
            printf("bind() failed");
            exit(0);
        }

        int packetsReceived = -1;

        char * buffer;
        char fileNameBuffer[15];
        int dataLength;

        while (1) {
            clientAddressLength = sizeof (clientAddress);
            struct header currentHeader;
            memset(&currentHeader, 0, sizeof(currentHeader));
            if (recvfrom (sock, &currentHeader, sizeof (currentHeader), 0, (struct sockaddr *) &clientAddress, &clientAddressLength) == sizeof(currentHeader)) {
                printf("Prijata sprava %d\n", packetsReceived);
            }


            if (currentHeader.sequenceNumber == packetsReceived)
            {

                if (currentHeader.type == 0) { // initialization, here I receive the size of the next packet, and the filename
                    buffer = malloc(currentHeader.length * sizeof(char) + 1); // allocating size for the next packet
                    bzero (buffer, currentHeader.length * sizeof(char));
                    if (strcmp(currentHeader.data, "NOT_FILE") != 0) // if it's a file (not just a text then save the filename)
                        strcpy(fileNameBuffer, currentHeader.data);
                    dataLength = currentHeader.length; 

                }

                if (currentHeader.type == 1) { // this is for text only
                    int buff_offset = fragmentSize * currentHeader.sequenceNumber;
                    memcpy(&buffer[buff_offset], currentHeader.data, currentHeader.length);
                    printf("buffer: %s\n", buffer);
                }


                printf ("[+] ACK sent\n"); // sending the ACK
                struct header currAck;
                currAck.type = 0;
                currAck.sequenceNumber = packetsReceived;
                currAck.length = 0;

                if (sendto(sock, &currAck, sizeof (currAck), 0,(struct sockaddr *) &clientAddress, clientAddressLength) != sizeof (currAck)) {
                    printf("sendto() sent a different number of bytes than expected");
                    exit(0);
                }
                if (packetsReceived == currentHeader.fragmentCount-1) {

                    // If it's text
                    if (currentHeader.type == 1)
                        printf("%s", buffer);

                    // If it's file
                    if (currentHeader.type == 2) {
                        FILE *filePointer;
                        char filePath[100] = "receivedFiles/";
                        strncat(filePath, fileNameBuffer, 100);
                        filePointer=fopen(filePath, "w");
                        if (filePointer) {
                            printf("File path: %s\n", filePath);
                            fwrite(buffer, dataLength, 1, filePointer);
                        }
                        else
                            printf("Nebolo mozne vytvorit subor.\n");

                        memset(fileNameBuffer, '\0', sizeof(fileNameBuffer));
                        fclose(filePointer);
                    }
                    exit(0);
                }
                packetsReceived++;
            }
        }
    }

客户端:

 printf(">>> CLIENT <<<\n");
        int sock;
        struct sockaddr_in serverAddress;
        struct sockaddr_in clientAddress;
        unsigned int clientAddressLength;

        char * serverIP = "127.0.0.1";

        int fragmentSize = 500;

        int port = 5150;

        memset (&serverAddress, 0, sizeof (serverAddress));
        serverAddress.sin_family = AF_INET;
        serverAddress.sin_addr.s_addr = inet_addr (serverIP);
        serverAddress.sin_port = htons (port);


        if ((sock = socket (PF_INET, SOCK_DGRAM, IPPROTO_UDP)) < 0) {
            printf("Socket () failed\n");
            exit(0);
        }


        printf("Select type\n1 - Send text\n2 - Send file\n\n");
        int type;
        scanf("%d", &type);
        getchar();


        // For text
        char buffer[2049];
        bzero(buffer, sizeof(buffer));


        // For files
        FILE * filePointer;
        char fileName[] = "hello.mp3";
        char fileBuffer[125000];
        bzero(fileBuffer, sizeof(fileBuffer));


        unsigned long int dataLength = 0;
        if (type == 1) {
            fgets(buffer, 2048, stdin);
            // printf("%s", buffer);
            dataLength = strlen(buffer);
        }

        else if (type == 2) {
            filePointer = fopen(fileName, "r");
            if (filePointer) {
                fseek(filePointer, 0, SEEK_END);
                dataLength= ftell(filePointer);
                printf("DATALENGTH: %lu", dataLength);
                fseek(filePointer, 0, SEEK_SET);
                if(fread(fileBuffer, dataLength, 1, filePointer) <= 0)
                {
                    printf("Unable to copy file into buffer or empty file.\n");
                    exit(1);
                }
                // printf("fileBuffer: %s\n", fileBuffer);
                fclose(filePointer);

            }
        }


        int fragmentCount = dataLength / fragmentSize; // here i calculate how many sequences will I need to send the packet
        if (dataLength % fragmentSize)
            fragmentCount++;

        int buff = -1;
        while (buff < fragmentCount)
        {
            struct header currentFragment;
            memset(&currentFragment, 0, sizeof(currentFragment));

            if (buff == -1) { // sending the initialization, just the size of the file and the filename
                currentFragment.type = 0;
                currentFragment.length = dataLength;
                (type == 2) ? (strcpy(currentFragment.data, fileName)) : (strcpy(currentFragment.data, "NOT_FILE"));
            }

            else {
                currentFragment.type = type;
                int currlength;
                if ((dataLength - (buff * fragmentSize)) >= fragmentSize)
                    currlength = fragmentSize;
                else
                    currlength = dataLength % fragmentSize;
                currentFragment.length = currlength;

                if (type == 1) memcpy (currentFragment.data, buffer + ((buff) * fragmentSize), currlength);
                if (type == 2) memcpy (currentFragment.data, fileBuffer + ((buff) * fragmentSize), currlength);
            }

            currentFragment.sequenceNumber = buff;
            currentFragment.fragmentCount = fragmentCount;
            sendto(sock, &currentFragment, sizeof(currentFragment), 0, (struct sockaddr *) &serverAddress, sizeof (serverAddress));

            // Packet info

            printf("\n####################\n");
            printf(">>> INFO <<<\n");
            printf("type: %d\n", currentFragment.type);
            printf("sequenceNumber: %d\n", currentFragment.sequenceNumber);
            printf("fragment count: %d\n", currentFragment.fragmentCount);
            printf("length: %d\n", currentFragment.length);
            printf("data: %s\n", currentFragment.data);


            // Get a response
            clientAddressLength = sizeof (clientAddress);
            struct header currentAcknowledgement;
            int response = recvfrom (sock, &currentAcknowledgement, sizeof (currentAcknowledgement) , 0, (struct sockaddr *) &clientAddress, &clientAddressLength);
            if (waitForResponse(response) == 1) {
                int acktype = currentAcknowledgement.type;
                int ackNumber = currentAcknowledgement.sequenceNumber;
                if (ackNumber == buff && acktype == 0) {
                    printf ("[+] ACK received");
                    buff++;
                }
            }
            else
                continue;
            printf("\n");
        }
        close (sock);
        exit (0);

标签: cfilesocketsudpfile-transfer

解决方案


推荐阅读