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