Warning: file_get_contents(/data/phpspider/zhask/data//catemap/4/c/59.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
错误-accept()失败:文件描述符错误_C_Sockets_Tcp - Fatal编程技术网

错误-accept()失败:文件描述符错误

错误-accept()失败:文件描述符错误,c,sockets,tcp,C,Sockets,Tcp,我必须实现两个进程,它们必须通过TCP进行交互,基本上是服务器和客户端之间的文件传输(学校作业)。第一次文件传输时一切都正常,但当客户端结束其工作时,服务器会因为错误-accept()失败:错误的文件描述符而崩溃 server\u main.c int main (int argc, char *argv[]) { char cwd[100]; if (getcwd(cwd, sizeof(cwd)) != NULL) { printf("App[startin

我必须实现两个进程,它们必须通过TCP进行交互,基本上是服务器和客户端之间的文件传输(学校作业)。第一次文件传输时一切都正常,但当客户端结束其工作时,服务器会因为
错误-accept()失败:错误的文件描述符
而崩溃

server\u main.c

int main (int argc, char *argv[]) {

    char cwd[100];

    if (getcwd(cwd, sizeof(cwd)) != NULL) {
       printf("App[starting]: " ANSI_COLOR_CYAN "%s" ANSI_COLOR_RESET "\n", cwd);
    } else {
       printf("App[quitting]: " ANSI_COLOR_RED "UNABLE TO LOCATE WDIR" ANSI_COLOR_RESET "\n");
       return 1;
    }

    // procedo solo se vengono passati esattamente due parametri allo script
    // 1. il nome dello script (default)
    // 2. la porta
    if (argc == 2) {
        int passiveSocket = startTcpServer(argv[1]);
        runIterativeTcpInstance(passiveSocket);
        close(passiveSocket);
        return 0;
    }

    // se arrivo qui ho app crash
    printf("App[quitting]: " ANSI_COLOR_RED "USAGE: <PORT>" ANSI_COLOR_RESET "\n");

    return 1;
}
int startTcpServer(const char* port) {

    uint16_t i_port;
    int sockfd;

    sockfd = Socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
    parsePort(port, &i_port);
    bindToAny(sockfd, i_port);
    Listen(sockfd, 516);
    printf("Server[listening]: " ANSI_COLOR_GREEN "PORT = %d, BACKLOG = 516" ANSI_COLOR_RESET "\n", (int) i_port);

    return sockfd;
}

void runIterativeTcpInstance(int passiveSock) {

    struct sockaddr_in cli_addr;
    socklen_t addr_len = sizeof(struct sockaddr_in);

    while(1) {
        printf("Server[accepting]: " ANSI_COLOR_YELLOW "WAITING FOR A CONNECTION..." ANSI_COLOR_RESET "\n");
        int connSock = Accept(passiveSock , (struct sockaddr *) &cli_addr, &addr_len);
        doTcpJob(connSock);
        close(connSock);
    }

}

void doTcpJob(int connSock) {
    //TODO: uscire in caso di errore di una delle due fasi
    printf("Server[connection]:" ANSI_COLOR_GREEN "STARTED A NEW ON CONNECTION (PID=%d)" ANSI_COLOR_RESET "\n", getpid());
    char request[256];
    initStr(request, 256);
    if(doTcpReceive(connSock, request) == 0)
        doTcpSend(connSock, request);
    else {
        printf("Server[error]: " ANSI_COLOR_RED "INVALID REQUEST FROM CLIENT: %s" ANSI_COLOR_RESET "\n", request);
        char err_buff[7] = "-ERR\r\n";
        send(connSock, err_buff, 6, 0);
        //close(connSock);
    }
//关闭(connSock); }

编辑sockwrap.c接受定义

int Accept (int listen_sockfd, SA *cliaddr, socklen_t *addrlenp)
{
    int n;
again:
    if ( (n = accept(listen_sockfd, cliaddr, addrlenp)) < 0)
    {
        if (INTERRUPTED_BY_SIGNAL ||
            errno == EPROTO || errno == ECONNABORTED ||
            errno == EMFILE || errno == ENFILE ||
            errno == ENOBUFS || errno == ENOMEM         
            )
            goto again;
        else
            err_sys ("(%s) error - accept() failed", prog_name);
    }
    return n;
}

当然,这个bug出现在我想检查的第一个函数中。仔细观察:

    void initStr(char* string, int length) {
        memset(string, '\0', length);
        string[length] = '\0'; // <-- BOOM!
    }
因此,
request
是一个包含256个条目的数组。但是
initStr
写入第257个条目,该条目不存在

你应该摆脱这个功能,永远不要使用任何类似它的东西。用零填充整个缓冲区是没有用的。相反,请正确跟踪缓冲区中数据的长度,并始终停止调用strlen。由于这个原因,您的代码中还有其他错误,更微妙的错误

例如,您尝试从连接中读取256个字节。这可能会填满整个缓冲区,替换所有零字节。然后将缓冲区传递给strlen,但不能保证缓冲区中的任何位置都有零字节


通过网络连接接收的数据不是字符串。它是从
read
recv
函数返回的具有已知长度的原始数据。不要假装它是一根绳子。这是一个会一次又一次地咬你的坏习惯。

被动检查的生命周期是
runIterativeTcpInstance
运行的整个时间。我看不到任何改变它的东西,它在函数返回之前不会关闭(它从未关闭)。我看不出这是怎么发生的,除非写入它的缓冲区溢出。你能显示
Accept
包装函数吗?因此,由于缓冲区溢出,我们在你发布的代码中看不到的东西一定在覆盖它。@GJCode我去检查的第一个函数是
initStr
,我们没有它的代码:(第二个是
showProgress
,同上。我怀疑否决票是因为你没有确认你可以用给出的代码复制bug,这使得问题无法回答。如果你选择不给我们任何代码,你必须100%确认你可以在没有代码的情况下复制问题。第二行是有趣的无论如何,Action是不必要的,整个函数也是如此。您不需要初始化要读入的缓冲区。
recv()
给出了接收到的长度。@user207421他这样做是因为他将缓冲区传递给了
strlen
。但是我更新了我的答案,解释了为什么这很糟糕,糟糕,糟糕!正如我说的,我是C语言新手,我正在努力理解事情是如何工作的(我的意思是我认为在一周内我无法理解一切)我知道此错误与C无关,但有时很难看出明显的错误,我错过了错误的数组位置。我很欣赏你的所有评论,我将更深入地学习C语言。@GJCode你可能需要花一些时间编写稍微简单一点的代码,然后将其发布到a以获取建议。这将有助于你提高C语言的使用效率整理代码中的许多小东西,这些小东西可以帮助你避免养成坏习惯,并让你养成一些好习惯。
void initStr(char* string, int length) {
    memset(string, '\0', length);
    string[length] = '\0';
}

void showProgress(int done, int tot, char * progMsg) {
    int progress = ((double) done / (double) tot) * 100;
    printf("\r%s " ANSI_COLOR_CYAN "%d bytes (%d%%)" ANSI_COLOR_RESET, progMsg, done, progress);
    fflush(stdout);
}
    void initStr(char* string, int length) {
        memset(string, '\0', length);
        string[length] = '\0'; // <-- BOOM!
    }
    char request[256];
    initStr(request, 256);