gpt4 book ai didi

c - 错误 - 接受()失败 : Bad file descriptor

转载 作者:行者123 更新时间:2023-11-30 19:00:30 36 4
gpt4 key购买 nike

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

server_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;
}

gj_server.c

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); }

int doTcpReceive(int connSock, char *request) {

struct timeval tval;
fd_set cset;
FD_ZERO(&cset);
FD_SET(connSock, &cset);
tval.tv_sec = 15;
tval.tv_usec = 0;
if(Select(FD_SETSIZE, &cset, NULL, NULL, &tval) == 1) {
// TODO: INSERIRE LOGICA RECEIVE QUI
ssize_t read = 0;
while (reqCompleted(request) == -1 ) {
ssize_t received = Recv(connSock, request, 256, 0);
read += received;
}
printf("Server[receive]: " ANSI_COLOR_CYAN "RECEIVED %s" ANSI_COLOR_RESET "\n", request);
return checkRequest(request);
}
// esco per timeout
//close(connSock);
return -1;
}

void doTcpSend(int connSock, char *request) {
// TODO: INSERIRE LOGICA SEND QUI

// 1. send ok message
char ok_msg[6] = "+OK\r\n";
send(connSock, ok_msg, 5, 0);

// 2. send file size
FILE *fp = fopen(request, "rb+");

// qui il file dovrebbe esistere, ma potrebbe essere inacessibile o
// l'apertura potrebbe fallire
if (fp == NULL) {
printf("SERVER[READING]" ANSI_COLOR_RED "CANNOT OPEN FILE %s " ANSI_COLOR_RESET "\n", request);
char err_buff[7] = "-ERR\r\n";
send(connSock, err_buff, 6, 0);
//close(connSock);
return;
}

struct stat stat_buf;

if (fstat(fileno(fp), &stat_buf) == 0) {

long f_size = stat_buf.st_size;
long f_time = stat_buf.st_mtime;
uint32_t net_f_size = htonl(f_size);
send(connSock, &net_f_size, 4, 0);

// 3. send file content
ssize_t sent = 0;
printf("fsize: %d", (int)f_size);
while (sent < f_size) {
sent += sendfile(connSock, fileno(fp), NULL, f_size);
showProgress((int)sent, (int)f_size, "Server[sending]: ");
}

fclose(fp);

// 4. send file timestamp
uint32_t net_f_time = htonl(f_time);
send(connSock, &net_f_time, 4, 0);
//close(connSock);

} else {
char err_buff[7] = "-ERR\r\n";
send(connSock, err_buff, 6, 0);
//close(connSock);
return;
}


}

int reqCompleted(char *request) {
int len = strlen(request);
return len > 6 && request[len - 2] == '\r' && request[len - 1] == '\n' ? 0 : -1;
}

int checkRequest(char *request) {
int len = strlen(request);
if (len > 6 && request[0] == 'G' && request[1] == 'E' && request[2] == 'T'
&& request[3] == ' ' && request[len - 2] == '\r' && request[len - 1] == '\n') {
memcpy(request, request + 4, (len - 6)); // estraggo il nome del file dalla richiesta
request[len - 6] = '\0';
return access(request, F_OK); // verifico che il file esista nella cartella di lavoro
}
return -1;
}

名为passiveSock的参数导致了问题,在while循环的第二次迭代中,我对C很陌生,我认为它与变量的生命周期有关。我已经尝试在接受调用之前打印 passiveSock 并给我一个错误。这是 valgrind 输出:

==1== Syscall param accept(s) contains uninitialised byte(s)
==1== at 0x4F21990: __accept_nocancel (syscall-template.S:84)
==1== by 0x10A7D4: Accept (sockwrap.c:97)
==1== by 0x109AA5: runIterativeTcpInstance (gj_server.c:28)
==1==
((null)) error - accept() failed: Bad file descriptor
==1==
==1== HEAP SUMMARY:
==1== in use at exit: 0 bytes in 0 blocks
==1== total heap usage: 2 allocs, 2 frees, 1,576 bytes allocated
==1==
==1== All heap blocks were freed -- no leaks are possible
==1==
==1== For counts of detected and suppressed errors, rerun with: -v
==1== Use --track-origins=yes to see where uninitialised values come from
==1== ERROR SUMMARY: 2 errors from 2 contexts (suppressed: 0 from 0)

编辑 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;
}

initStr 和 showProgress

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);

因此 request 是一个包含 256 个条目的数组。但是 initStr 写入了第 257 个条目,该条目不存在。

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

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

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

关于c - 错误 - 接受()失败 : Bad file descriptor,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/59506598/

36 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com