read() 和 write() 函数在 C 上的本地连接(同一台计算机)上的 TCP 连接期间返回 -1

read() and write() functions return -1 during a TCP connection on local connection (same computer) on C

提问人:Msain 提问时间:9/4/2022 更新时间:9/6/2022 访问量:258

问:

我编写了一个代码,用于将文件内容从客户端传输到服务器。这意味着我们在服务器端更新某个文件。此过程根据用户输入每 N 秒继续一次。但是,我遇到了一个错误,即:

即使在本地连接(同一台计算机)上,write() 和 read() 函数在文件传输过程中也会返回 -1。这个问题甚至可能不会不时表现出来。但是,当用户传输较大的文件(超过 30MB)时,它更有可能显现出来。因此,这个问题肯定在那里等待某些东西来触发它,这对于任何程序来说都是一个非常不方便的方面。奇怪的是,如果我使用 sleep() 函数,例如等待 1 秒钟,然后在套接字上 write()/read(),则不会发生此问题。请解释为什么会发生这种情况以及我该如何补救。 此外,在所有其他代码中,我所看到的只是 exit(0),如果 read() 或 write() 在连接期间返回 -1。 感谢您的指导

不幸的是,在类似的问题中,我找不到任何解决方案。如果您能解释为什么会出现此类问题以及我如何解决它,我将不胜感激。为了您的方便,我在下面解释了完整的过程。

  1. 此代码背后的主要思想是从定期更新的文件中传输数据。因此,我们应该每 N 秒向服务器发送一次剩余数据。
  2. 服务器(接收方)和客户端(发送方)相互连接(对于像您这样的专业用户来说并不是什么新鲜事)。
  3. 服务器(接收器)发送持久化的数据量,用户计算剩余的数据量。完成此步骤后,服务器和客户端都知道在当前迭代中应传输多少数据。
  4. client 将所有剩余数据读取到 cacheBuffer 并关闭该文件。(我应该说 cacheBuffer 等于剩余的字节,并且在客户端和服务器中都有效)
  5. 在 main(内部)while 循环中,我们从 cacheBuffer 复制到 mssg 结构,然后通过套接字发送该结构。
  6. 同样,客户端内部的 while 循环读取结构 mssg 并将数据复制到其缓存缓冲区
  7. 最后,当发送/接收结束时,接收方(服务器)将缓存缓冲区内容写入目标文件,该过程将继续。

客户端代码

/*
    How to compile ->
    (1) make all
        if no make was provided then gcc server.c utilityFunctionsMHZ.h -o server
    (2) ./server FILENAME PORT_NUMBER SLEEP_TIMER MAX_BUFFER_SIZE
        Example: ./server mainFile2.log 5500 10 4096
    (3) ./client FILENAME SERVER_ADDR PORT_NUMBER 
        Example: ./client mainFile.log 172.17.34.89 5500
*/  

#include "utilityFunctionsMHZ.h"

int main (int argc, char* argv[])
{
    // Initial Error Check And Call Initializer
    if (argc < 4) 
    {   
        fprintfSwitchable(NULL, 0, "[+client] Please use the given format: ./client FILENAME SERVER_ADDR PORT_NUMBER\n");
        exit(0);
    }
    else if (!isFileAvailable(argv[1], "client", NULL))
    {
        exit(0);
    }
    else
    {
        Initializer ("client", NULL);
        fprintfSwitchable(NULL, 0, "[+%s] Make Sure to Run server First.\n", "client");
    }
        
    // Input Parameters  
    const char* fileLocFull = argv[1];
    char* serverIP          = argv[2];
    int portNumber          = atoi(argv[3]);

    // Buffer & Cache Properties and Size 
    struct bufferTCP* mssg = CreateBufferTCP();
    size_t MAX_CACHE_SIZE, CACHE_SIZE;
    char* cacheBuffer;

    // File Process, Data Structure (NACK-Sender & ACK-Reciever)
    FILE* filePtr_NACK;
    size_t fileMemory_NACK = 0;
    size_t fileMemory_ACK = 0;
    size_t fileRemainMemory = 0;

    // Create Socket via TCP Protocol & Error Check
    int sockfd = socket(AF_INET, SOCK_STREAM, 0);
    if (sockfd == -1)
        fprintfSwitchable(NULL, 1, "[-client] Error in Socket Initiation!\n");
    else
        fprintfSwitchable(NULL, 0, "[+client] Socket Successfully Initiated.\n");
    // Socket main Structures
    struct sockaddr_in* serverAddr = malloc(sizeof(struct sockaddr_in));
    
    // Socket Structures Memory Allocation Test
    if (serverAddr == NULL) 
        fprintfSwitchable(NULL, 1, "[-client] Memory Allocation for sockadd_in strctures Failed!\n");
    else
        fprintfSwitchable(NULL, 0, "[+client] Memory Allocation for sockadd_in strctures Successfully Completed.\n");
    
    // Set-up server parameters
    bzero(serverAddr, sizeof(struct sockaddr_in));   //memset(serverAddr, 0x00, sizeof(struct sockaddr_in));
    serverAddr->sin_family      = AF_INET;
    //serverAddr->sin_addr.s_addr = inet_addr(serverIP);
    inet_pton(AF_INET, serverIP, &(serverAddr->sin_addr));
    serverAddr->sin_port        = htons(portNumber);

    // Connection Request to Server
    if (connect(sockfd, (struct sockaddr*) serverAddr, sizeof(struct sockaddr_in)) == -1)
        fprintfSwitchable(NULL, 1, "[-client] Error in Connecting to Server!\n");
    else
        fprintfSwitchable(NULL, 0, "[+client] Connection Successfully Accepted.\n");

    if (read(sockfd, &MAX_CACHE_SIZE, sizeof(size_t)) == -1)
        fprintfSwitchable(NULL, 1, "[-client] Error in MAX CACHE Size Negitiation!\n"); 
    else 
        fprintfSwitchable(NULL, 0, "[+client] CACHE Size is Set Equal to Server: %lu.\n", MAX_CACHE_SIZE);
    
    // Initializing Sender Sleep Clock
    size_t sleepTimer;
    if (read(sockfd, &sleepTimer, sizeof(size_t)) == -1)
        fprintfSwitchable(NULL, 1, "[-client] Error in Sleep Timer Negitiation!\n", 1, 1); 
    else 
        fprintfSwitchable(NULL, 0, "[+client] Sleep Timer is Set Equal to Server: %lu\n", sleepTimer); 
    
    int iack;
    int ACKFLAG = 0;
    size_t OveralIteration = 0;
    size_t SentBytes;
    size_t Not_Written = 0;
    ssize_t readFLAG;
    ssize_t writeFLAG;
    size_t InnerIteration = 0;

    fprintfSwitchable(NULL, 0, "**********************Client-Side::Sending Started**************************\n"); 
    while (1)
    {
        fileMemory_NACK = FileSizeCalculator(fileLocFull);

        // File Status @ Server (Reciever) 
        if (read(sockfd, &fileMemory_ACK, sizeof(size_t)) == -1)
            fprintfSwitchable(NULL, 1, "[-client] Error in reading File Info!\n"); 
        else
            fprintfSwitchable(NULL, 0, "[+client] File (Size) Info is Recieved Successfully.\n"); 

        // Send-Recieve Validity
        fileRemainMemory = fileMemory_NACK - fileMemory_ACK;
            
        // Send Expecting Data Size For Server
        if (write(sockfd, &fileRemainMemory, sizeof(size_t)) == -1)
            fprintfSwitchable(NULL, 1, "[-client] Failed To Send Remaining Memory Info!\n"); 
        else
            fprintfSwitchable(NULL, 0, "[+client] Session [%lu] Overview: \nACK Memory is %lu\nNACK Memory is %lu\nRemaining Memory is: %lu\n\n", 
                                        OveralIteration, fileMemory_ACK, fileMemory_NACK, fileRemainMemory); 
        // Assess Sending
        if (fileMemory_NACK == fileMemory_ACK) 
        {
            fprintfSwitchable(NULL, 0, "[+client] Remaining Memory is Zero. Send Process Will Contine After %lu[s] Timeout.\n", sleepTimer);;  
            continue;
        }
        else if (fileRemainMemory < BUFFER_MAX)
        {
            fprintfSwitchable(NULL, 0, "[+client] Remaining Buffer is Smaller Than Cache Limit %lu. Send Process Will Contine After %lu[s] Timeout.\n",
                              BUFFER_MAX, sleepTimer);  
            Not_Written++;
            if (Not_Written < 10) 
                continue;
            else
                Not_Written = 0;
        }
        
        // Creating Cache
        CACHE_SIZE = fileRemainMemory;
        cacheBuffer = (char*) calloc (CACHE_SIZE, sizeof(char));
        bzero(cacheBuffer, CACHE_SIZE);
        
        // Copy Data From File to CACHE-Buffer
        filePtr_NACK = fopen(fileLocFull, "r");
        fseek(filePtr_NACK, fileMemory_ACK, SEEK_SET);
        fread(cacheBuffer, sizeof(char), CACHE_SIZE, filePtr_NACK);
        fclose(filePtr_NACK);
        
        ACKFLAG = 0;
        SentBytes = 0;
        fileRemainMemory = CACHE_SIZE;
        InnerIteration = 0;
        while (1)
        {
            // EXIT CONDITION
            if (fileRemainMemory == 0) break;
            
            // Evaluate Buffer Size
            if (fileRemainMemory >= BUFFER_MAX)                     
                mssg->BUFFER_USED = BUFFER_MAX;
            else 
                mssg->BUFFER_USED = fileRemainMemory;
                
            // Copy From CACHE to Socket Buffer and Send
            memcpy(mssg->mssgPtr, cacheBuffer+SentBytes, mssg->BUFFER_USED);
            writeFLAG = write(sockfd, mssg, sizeof(struct bufferTCP)); 
            fprintfSwitchable(NULL, 0, "[+client] Iter %ld :: %ld/%ld Sent!\n", InnerIteration++, writeFLAG, sizeof(struct bufferTCP)); 
            // Cases:
            if (writeFLAG == -1)
            {
                // Display Problem
                fprintfSwitchable(NULL, 0, "[-client] Error While Sending Buffer!\n");
                fprintfSwitchable(NULL, 0, "[-client] %s\n", strerror(errno));
            } 
            else if (writeFLAG < sizeof(struct bufferTCP))
            {
                // Display Problem
                fprintfSwitchable(NULL, 0, "[-client] Only %ld/%ld Sent!\n", writeFLAG, sizeof(struct bufferTCP)); 
            }   
            else
            {
                // In Session Statistics    
                fileRemainMemory -= mssg->BUFFER_USED;
                SentBytes        += mssg->BUFFER_USED;
                fprintfSwitchable(NULL, 0, "[+client] (%lu) Current-Iteration | (%lu) Total-Sent | (%lu) Remaining.\n", writeFLAG, SentBytes, fileRemainMemory);
            }   
            bzero(mssg->mssgPtr, BUFFER_MAX); 
        }
        if (writeFLAG != -1 && fileRemainMemory == 0)
        {
            fileMemory_ACK = SentBytes;
            OveralIteration++;
        }
            
        // Session Summary
        fprintfSwitchable(NULL, 0, "[+client] Session %lu Summary:\nACK Memory is %lu :: Remaining Memory is: %lu\n\n", 
                                          OveralIteration, fileMemory_ACK, fileRemainMemory);   
        free(cacheBuffer);
        // Exit Condition
        if (isEnd (sleepTimer, "client"))  break;

    }
    fprintfSwitchable(NULL, 0, "\n***********************Client-Side::Sending Ended***************************\n"); 

    close(sockfd);
    free(serverAddr);
    free(mssg);

    return 0;
}

服务器代码:


/*
    How to compile ->
    (1) make all
        if no make was provided then gcc server.c utilityFunctionsMHZ.h -o server
    (2) ./server FILENAME PORT_NUMBER SLEEP_TIMER CHACHE_SIZE_MAX
        Example: ./server mainFile2.log 5500 10 4096
    (3) ./client FILENAME SERVER_ADDR PORT_NUMBER
        Example: ./client mainFile.log 172.17.34.89 5500
*/  

#include "utilityFunctionsMHZ.h"

int main (int argc, char* argv[])
{
    // Initial Error Check And Call Initializer
    if (argc < 5) 
    {
        fprintfSwitchable(NULL, 0, "[+server] Please use the following format to initiate the ./server FILENAME PORT_NUMBER SLEEP_TIMER MAX_CACHE_SIZER\n");
        exit(0);
    }   
    else
    {
        Initializer ("server", NULL);
    }
        
    // Input Parameters  
    const char* fileLocFull = argv[1];
    int portNumber          = atoi(argv[2]);         
    size_t sleepTimer       = atoi(argv[3]); 
    size_t MAX_CACHE_SIZE   = atoi(argv[4]);
    size_t WaitQueue        = 5;
    
    // server :: Socket Accept Client Request
    socklen_t socklen = sizeof(struct sockaddr_in);

    // File Process, Data Structure (NACK is the Sender/Client Side)
    if (!isFileAvailable(argv[1], "server", NULL))
    {
        FILE* filePtr_ACK = fopen(fileLocFull, "w");
        fclose(filePtr_ACK);
    }
    
    //size_t checker = FileCorrector (fileLocFull);
    size_t checker = FileModifier (fileLocFull);

    // File Process, Data Structure (NACK-Sender & ACK-Reciever)
    FILE* filePtr_ACK;
    size_t fileMemory_ACK = 0;
    size_t fileRemainMemory = 0;
    
    // Buffer Properties and Size (Set Sender/Client Buffer-Size Equal to Server)
    struct bufferTCP* mssg = CreateBufferTCP();
    // Cache properties
    size_t CACHE_SIZE;
    char* cacheBuffer;

    // socket End-Point
    int sockfd, sockfd_new;
    // client :: Initiation Socket via TCP Protocol & Error Check
    sockfd = socket(AF_INET, SOCK_STREAM, 0);
    if (sockfd == -1)
        fprintfSwitchable(NULL, 1, "[-server] Error in Socket Initiation!\n");
    else
        fprintfSwitchable(NULL, 0, "[+server] Socket Successfully Initiated.\n");

    // Socket main Structures
    struct sockaddr_in* serverAddr;
    struct sockaddr_in* clientAddr;
    serverAddr =  malloc(sizeof(struct sockaddr_in));       
    clientAddr =  malloc(sizeof(struct sockaddr_in));
    
    // Socket Structures Memory Allocation Test
    if (clientAddr == NULL || serverAddr == NULL)
        fprintfSwitchable(NULL, 1, "[-server] Memory Allocation for sockadd_in strctures Failed!\n");
    else
        fprintfSwitchable(NULL, 0, "[+server] Memory Allocation Successfully Completed.\n");
    
    bzero(serverAddr, sizeof(struct sockaddr_in)); //memset(serverAddr, 0x00, sizeof(struct sockaddr_in));
    bzero(clientAddr, sizeof(struct sockaddr_in)); //memset(clientAddr, 0x00, sizeof(struct sockaddr_in));
    
    // set-up Server parameters
    serverAddr->sin_family      = AF_INET;
    serverAddr->sin_addr.s_addr = INADDR_ANY;   // inet_addr(clientIP);
    serverAddr->sin_port        = htons(portNumber);

    // server :: Socket Binding
    if (bind(sockfd, (struct sockaddr*) serverAddr, sizeof(struct sockaddr_in)) == -1)
        fprintfSwitchable(NULL, 1, "[-server] Error in Socket Binding!\n");
    else
        fprintfSwitchable(NULL, 0, "[+server] Socket Successfully Binded.\n");
    
    // server :: Socket Listening
    if (listen(sockfd, WaitQueue) == -1)
        fprintfSwitchable(NULL, 1, "[-server] Error while Listening!\n");
    else
        fprintfSwitchable(NULL, 0, "[+server] Listening...\n");
    
    // server :: Socket Listening
    sockfd_new = accept(sockfd, (struct sockaddr*) clientAddr, &socklen);
    if (sockfd_new == -1)
        fprintfSwitchable(NULL, 1, "[-server] Error in Accepting Client Connection!\n");
    else
        fprintfSwitchable(NULL, 0, "[+server] Connection Successfully Accepted.\n");

    // Establishing BUFFER_MAX_SIZE (Set Sender/Client Buffer-Size Equal to Server)
    if (write(sockfd_new, &MAX_CACHE_SIZE, sizeof(size_t)) == -1)
        fprintfSwitchable(NULL, 1, "[-server] Error in Buffer Size Negitiation!\n");
    else 
        fprintfSwitchable(NULL, 0, "[+server] MAX Buffer-Size is Sent to client: %lu.\n", MAX_CACHE_SIZE);
    
    // Initializing Sender Sleep Clock (Set Sender/Client Buffer-Size Equal to Server)
    if (write(sockfd_new, &sleepTimer, sizeof(size_t)) == -1)
        fprintfSwitchable(NULL, 1, "[-server] Error in Sleep Timer Negitiation!\n");
    else 
        fprintfSwitchable(NULL, 0, "[+server] Sleep-Timer is Sent to client: %lu\n", sleepTimer);

    int ACKFLAG = 0, CONFLAG = 0;
    size_t OveralIteration = 0;
    size_t SentBytes;
    size_t Not_Written;
    int iack = 0;
    ssize_t readFLAG;
    ssize_t writeFLAG;
    size_t InnerIteration = 0;

    fprintfSwitchable(NULL, 0, "**********************Server-Side::Recieving Started**************************\n");
    while (1)
    {
        // File Status @ Server (Reciever) 
        fileMemory_ACK = FileSizeCalculator(fileLocFull);
        
        // Send ACK Status
        if (write(sockfd_new, &fileMemory_ACK, sizeof(size_t)) == -1)
            fprintfSwitchable(NULL, 1, "[-server] Error in Sending File Info!\n");
        else
            fprintfSwitchable(NULL, 0, "[+server] File (Size) Info Sent Successfully.\n"); 

        // Recieve Expecting Data Size From Client
        if (read(sockfd_new, &fileRemainMemory, sizeof(size_t)) == -1)
            fprintfSwitchable(NULL, 1, "[-server] Failed to Recieve Remaining Memory Info!\n"); 
        else
            fprintfSwitchable(NULL, 0, "[+server] Session [%lu] Overview:\nACK Memory is: %lu\nRemaining Memory is: %lu\n\n", 
                                    OveralIteration, fileMemory_ACK, fileRemainMemory); 
        if (fileRemainMemory == 0) 
        {
            fprintfSwitchable(NULL, 0, "[+server] Remaining Memory is Zero. Process Will Contine After %lu[s] Timeout.\n", sleepTimer); 
            continue;
        }
        else if (fileRemainMemory < BUFFER_MAX)
        {
            fprintfSwitchable(NULL, 0, "[+server] Remaining Buffer is Smaller Than Cache Limit %lu. Recieve Process Will Contine After %lu[s] Timeout.\n",
                              BUFFER_MAX, sleepTimer);  
            Not_Written++;
            if (Not_Written < 10) 
                continue;
            else
                Not_Written = 0;
        }

        // Creating Cache
        CACHE_SIZE = fileRemainMemory;
        cacheBuffer = calloc (CACHE_SIZE, sizeof(char));
        bzero(cacheBuffer, CACHE_SIZE);

        ACKFLAG = 0;
        SentBytes = 0;
        fileRemainMemory = CACHE_SIZE;
        InnerIteration = 0;
        while (1)
        {
            // EXIT CONDITION
            if (fileRemainMemory == 0) break;

            // Recieve Buffer
            readFLAG = read(sockfd_new, mssg, sizeof(struct bufferTCP));    
            fprintfSwitchable(NULL, 0, "[+server] Iter %ld :: %ld/%ld Sent!\n", InnerIteration++, readFLAG, sizeof(struct bufferTCP)); 
            // Cases:
            if (readFLAG == -1) 
            {
                // Display Problem
                fprintfSwitchable(NULL, 0, "[-server] Error While Reading Buffer Size!\n"); 
            }
            else if (readFLAG < sizeof(struct bufferTCP))
            {
                // Copy From CACHE to Socket Buffer
                fprintfSwitchable(NULL, 0, "[-server] Only %ld/%ld Recieved!\n",readFLAG, sizeof(struct bufferTCP)); 
                fprintfSwitchable(NULL, 0, "[-server] %s\n", strerror(errno));
            }
            else
            {
                // Copy From CACHE to Socket Buffer
                memcpy(cacheBuffer+SentBytes, mssg->mssgPtr, mssg->BUFFER_USED);
                // In Session Statistics    
                fileRemainMemory -= mssg->BUFFER_USED;
                SentBytes        += mssg->BUFFER_USED;
                fprintfSwitchable(NULL, 0, "[+server] (%lu) Current-Iteration | (%lu) Total-Sent | (%lu) Remaining.\n", readFLAG, SentBytes, fileRemainMemory);
            }   
            bzero(mssg->mssgPtr, BUFFER_MAX); 
        }       
        if (readFLAG != -1 && fileRemainMemory == 0)
        {
            fileMemory_ACK = SentBytes;
            // Copy Data From File to CACHE-Buffer
            filePtr_ACK = fopen(fileLocFull, "a");
            fwrite(cacheBuffer, sizeof(char), CACHE_SIZE, filePtr_ACK);
            fclose(filePtr_ACK);
            OveralIteration++;
        }
        
        // Session Summary-alIteration, fileMemory_ACK, fileRemainMemory);  
        free(cacheBuffer);
        // Exit Condition
        if (isEnd (sleepTimer, "server"))  break;
    }
    fprintfSwitchable(NULL, 0, "\n***********************Server-Side::Recieving Ended***************************\n");
    
    close(sockfd);
    close(sockfd_new);
    free(serverAddr);
    free(clientAddr);
    free(mssg);

    return 0;
}

使用的库


#ifndef utilityFunctionsMHZ_H
#define utilityFunctionsMHZ_H

#include <stdio.h>      //:: standard IO c-functions
#include <string.h>     //:: standard c-string functions
#include <unistd.h>     //:: standard POSIX operating system API (read/write/send/recv)
#include <stdlib.h>     //:: standard ALLOC c-functions (malloc, atoi)
#include <sys/types.h>  //:: definitions of data types used in sys/socket & netinet/in
#include <sys/socket.h> //:: definitions of structures needed for internet domain such as (struct sockaddr)
#include <netinet/in.h> //:: definitions of (struct sockaddr_in)
#include <netdb.h>      //:: definitions of (struct hostnet) to store info of a given host & IPV-4
#include <arpa/inet.h>  //:: inet()
#include <sys/stat.h>
#include <stdarg.h>     //:: Variable Input function
#include <errno.h>
#define BUFFER_MAX 1024

struct bufferTCP
{
    char mssgPtr[BUFFER_MAX];
    size_t BUFFER_USED;
};

// Usefull functions
struct bufferTCP* CreateBufferTCP();
void WriteLog(const char* logFileName, const char* mssg);
size_t FileCorrector (const char* fileName);;
FILE* FileOpenSafe (const char* fileName, const char* rwaMode);
size_t FileSizeCalculator (const char* fileName);
void fprintfSwitchable(FILE* stream, int errFlag, const char* mssg, ...);
FILE* FileOpenSafe (const char* fileName, const char* rwaMode);
size_t FileSizeCalculator (const char* fileName);
size_t FileCorrector (const char* fileName);
size_t FileModifier(const char* fileName);
void Initializer (const char* caller, FILE* stream);
int isEnd (size_t sleepTimer, const char* caller);
int isFileAvailable (const char* fileLocFull, const char* caller, FILE* stream);

void WriteLog(const char* logFileName, const char* mssg)
{
    FILE* logFilePtr = fopen(logFileName, "a");
    //fputs(mssg, logFilePtr);
    fclose(logFilePtr);
}


void fprintfSwitchable(FILE* stream, int errFlag, const char* mssg, ...)
{
    va_list args;

    va_start(args, mssg);

    if (stream == NULL)
    {
        vfprintf(stdout, mssg, args);
        fflush(stdout);
    }
    else
    {
        vfprintf(stream, mssg, args);
        fflush(stream);
    }    

    if (errFlag)  exit(1);
        
    va_end(args);
}


FILE* FileOpenSafe (const char* fileName, const char* rwaMode)
{
    if (fileName == NULL)
        fprintfSwitchable(NULL, -1, "FileName or Location is Incorrect!\n");

    FILE* filePtr = fopen(fileName, rwaMode);

    if (filePtr == NULL)
        fprintfSwitchable(NULL, -1, "File Location is Invalid Or File Does Not Exists!\n");

    return filePtr;
}


size_t FileSizeCalculator (const char* fileName)
{
    FILE* filePtr = FileOpenSafe(fileName, "r");
    int fileDescriptor = fileno(filePtr);
    struct stat fileInfo;
    bzero(&fileInfo, sizeof(struct stat));
    fstat(fileDescriptor, &fileInfo);
    size_t fileSize =  fileInfo.st_size;
    fclose(filePtr);

    return fileSize;
}

size_t FileCorrector (const char* fileName)
{
    size_t fileSize = FileSizeCalculator (fileName);
    size_t fileSizeTrue;
    if (fileSize == 0)
    {
        fprintfSwitchable(NULL, 0, "File is Empty, thus requires no correction!\n");
        return 0;
    }
        
    // Main & Temp File
    FILE* mainFile = FileOpenSafe (fileName, "r");
    FILE* tempFile = FileOpenSafe("temp", "w");
    
    // Fault Detection (\00 0\0 00) and correct
    char checkBuff[3];
    char curserrChar;
    
    size_t ii;
    for (ii = 0; ii < fileSize; ii++)
    {
        curserrChar = fgetc(mainFile);
        //printf("%c", curserrChar);
        if (curserrChar == '\00')
        {    
            fileSizeTrue = ftell(mainFile)-2;
            break;
        }
        fputc(curserrChar, tempFile);
    }
    fclose(mainFile);
    fclose(tempFile);

    // Remove The Old File
    if (remove(fileName) == 0) 
        fprintfSwitchable(NULL, 0, "Faulty File (%s) Removed Successfully.\n", fileName);
    else
        fprintfSwitchable(NULL, 1, "Error while Removing the Faulty File: %s!\n", fileName);


    // Remove The Old File
    if (rename("temp", fileName) == 0) 
        fprintfSwitchable(NULL, 0, "Corrected File Renamed Successfully.\n");
    else
        fprintfSwitchable(NULL, 1, "Error while Removing the Faulty File: %s!\n");

    fprintfSwitchable(NULL, 0, "Correction Implemented Successfully.\n");

    return fileSizeTrue;
}


size_t FileModifier(const char* fileName)
{
    size_t fileSize = FileSizeCalculator (fileName);
    size_t fileSizeTrue;
    if (fileSize == 0)
    {
        fprintfSwitchable(NULL, 0, "[+server] File is Empty, thus requires no correction.\n");
        return 0;
    }
        
    // Main & Temp File
    FILE* mainFile = FileOpenSafe (fileName, "r");
    FILE* tempFile = FileOpenSafe("temp", "w");
    
    // Fault Detection (\00 0\0 00) and correct
    char checkBuff[3];
    char curserrChar;
    size_t ii;
    for (ii = 0; ii < fileSize; ii++)
    {
        curserrChar = fgetc(mainFile);
        if (curserrChar == '\00') break;
        fputc(curserrChar, tempFile);
    }
    fclose(mainFile);
    fclose(tempFile);


    mainFile = FileOpenSafe (fileName, "w");
    tempFile = FileOpenSafe("temp", "r");
    fileSizeTrue = FileSizeCalculator ("temp");

    ii=0;
    for (ii = 0; ii < fileSizeTrue; ii++)
    {
        curserrChar = fgetc(tempFile);
        fputc(curserrChar, mainFile);
    }
    
    fclose(mainFile);
    fclose(tempFile);

    // Remove The Old File
    if (remove("temp") == 0) 
        fprintfSwitchable(NULL, 0, "[+server] Temp File Removed Successfully.\n");
    else
        fprintfSwitchable(NULL, 1, "[-server] Error while Removing the Faulty File!\n");

    fprintfSwitchable(NULL, 0, "[+server] File Modifier Executed Successfully.\n");

    return fileSizeTrue;
}


void Initializer (const char* caller, FILE* stream)
{
    // Initial confirmation client side
    char checkSend;
    fprintfSwitchable(stream, 0, "[+%s] Start Process [Y/N]: ", caller);
    scanf(" %c", &checkSend);
    if (checkSend == 'N' || checkSend == 'n')
    {
        fprintfSwitchable(stream, 0, "[-%s] Abort Process As Requested!\n", caller);
        exit(0);
    } 
    else
        return;
}
    
int isEnd (size_t sleepTimer, const char* caller)
{
    // Exit Material
    fd_set          s;
    struct timeval  timeout;
    char exitFlag[12];
    memset(&exitFlag, 'F', 12);
    int sFlag;

    fflush(stdout);
    FD_ZERO(&s);
    FD_SET(0, &s);
    timeout.tv_sec = sleepTimer; timeout.tv_usec = 0;
    sFlag = select(1, &s, NULL, NULL, &timeout);
    
    if      (sFlag < 0) 
        return 0;
    else if (sFlag == 0) 
    {
        fflush(stdout);
        fprintfSwitchable(NULL, 0, "-\n");
        return 0;
    }
    else
    {
        fgets(exitFlag, 12, stdin);
        fprintfSwitchable(NULL, 0, "[+%s] To Quit, please enter \"exit\": ", caller); 
        fflush(stdout);
        if ( memcmp(&exitFlag, "exit", 4) == 0 ) 
            return 1;
        else
            return 0;
    }

}

int isFileAvailable (const char* fileLocFull, const char* caller, FILE* stream)
{
    // Checks if The Target Send File Exists!
    FILE* filePtr_NACK = fopen(fileLocFull, "r");
    if (filePtr_NACK == NULL)
    {
        fprintfSwitchable(stream, 0, "[-%s] Not Such File Name Exists!\n", caller);
        return 0;
    }
    else
    {
        fprintfSwitchable(stream, 0, "[+%s] File Found Successfully.\n", caller);
        fclose(filePtr_NACK);
        return 1;
    }
    
}


void copyWithOffsetDest(char* dest, const char* src, size_t start, size_t length)
{
    size_t i = 0;
    for (i = 0; i < length; i++)
        dest[start+i] = src[i];
}

void copyWithOffsetSource(char* dest, const char* src, size_t start, size_t length)
{
    size_t i = 0;
    for (i = 0; i < length; i++)
        dest[i] = src[i+start];
}


struct bufferTCP* CreateBufferTCP()
{
    struct bufferTCP* mssg = (struct bufferTCP*) 
                malloc(sizeof(struct bufferTCP));
    return mssg;
}

#endif

生成文件

all:    client server

ftpclient: client.c
    gcc -std=gnu99 -Wall $< -o $@

ftpserver: server.c
    gcc -std=gnu99 -Wall $< -o $@

clean:
    rm -f client server *.o *~ core
    rm server client

C 套接字 TCP IO

评论

1赞 aulven 9/4/2022
请创建一个最小的可重现示例。没有人会费心阅读数百行代码。
1赞 Martin James 9/4/2022
无论如何都无聊,因为当应用于 TCP 字节流时,无法正确和完整地处理从 read()、write() 等系统调用返回的结果。不确定所有“sleepTimer”“N 秒”的东西是什么 - 对我来说听起来很不对劲,这只是为了测试吗?
0赞 Msain 9/4/2022
@aulven 感谢您的回复。我将举一个较小的例子。我感谢我们的建议。同时,您能否回答我一个小问题,即为什么在 tcp 连接期间读取和写入会在本地连接上返回 -1?更重要的是,我该如何补救这种情况,并可能重新建立连接(而不仅仅是退出)?提前致谢
0赞 Martin James 9/4/2022
我的意思是。。如果是我,我会先组装一个固定大小的标头结构,包括 filespec、filesize 等,然后将其写入一个循环中,累积发送的 actua 字节(由写入返回的结果扣除),直到我确定所有标头都消失了。在对等处类似 - 循环读取,直到我收到所有标头。然后,文件 xfer 可以开始、写入、读取,直到文件结束,然后在客户端关闭套接字,因此从服务器读取返回 0 并发出关闭文件的信号。你的设计似乎有点过于复杂了'
1赞 Jeremy Friesner 9/4/2022
“连接重置对等体”表示TCP连接另一端的程序已关闭其连接端。如果另一个程序调用或在套接字上调用,或者程序因任何原因崩溃或退出,则可能会发生这种情况。close()shutdown()

答:

0赞 Msain 9/6/2022 #1

我已经找到了问题的答案。 正如 @user207421 和 @Martin James 所建议的那样(谢谢你们俩),问题出在 write() read() IO 上。我还不明白它是如何导致分割的,但教训是 read() 和 write() 函数需要循环来发送和接收数据,正如我们预期的那样。否则,他们会做其他事情,我们不能简单地预测它。在下面,我附加了我如何修复代码。我希望它能使其他人免于犯同样的错误。

服务器环路

readFLAG = 0;
bzero(mssg->mssgPtr, BUFFER_MAX);
while ( (readFLAG = read(sockfd_new, (mssg->mssgPtr)+readFLAG, BUFFER_MAX-readFLAG)) != BUFFER_MAX )
{
    if (readFLAG == 0 ||  mssg->mssgPtr[readFLAG] == '\0')
        break;
}

mssg->BUFFER_USED = readFLAG;
            

客户端循环

bzero(mssg->mssgPtr, BUFFER_MAX);
memcpy(mssg->mssgPtr, cacheBuffer+SentBytes, mssg->BUFFER_USED);
            
while ( (writeFLAG = write(sockfd, mssg->mssgPtr, mssg->BUFFER_USED)) != mssg->BUFFER_USED );

评论

1赞 Jeremy Friesner 9/6/2022
它的作用是为您提供与内存中当前可用的尽可能多的传入字节(或者,如果它当前没有任何字节可以提供给您,它将阻止您,直到它确实有东西)。它的作用是接受你当前有缓冲区空间的字节数,或者如果它不能接受所有字节,它将阻塞,直到有足够的缓冲区空间来接受它们。需要注意的是,对于 TCP,这两个函数的行为与远程程序之前在任何给定调用中发送/接收的数据量无关。read()write()
0赞 Msain 9/6/2022
谢谢@JeremyFriesner你的笔记很有价值。