我正在尝试编写一个简单的聊天应用程序,其中客户端从服务器接收一个字符串并发送一条新消息,该消息将被传递给下一个连接的客户端。我是套接字编程的新手,我真的无法理解这个错误发生的原因。客户端发送缓冲区后,服务器会在accept()
(返回-1)和错误的文件描述符上通知错误。这是服务器上运行的代码:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <time.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
void error(char *msg) {
perror(msg);
exit(1);
}
int main (int argc, char *argv[] ) {
if ( argc < 2 ) {
error("ERROR, no port provided\n");
}
int sockfd;
struct sockaddr_in serv_addr, cli_addr;
int cli_len, portno;
char message[256];
pid_t pid;
int n;
portno = atoi( argv[1] );
bzero( (char*)&serv_addr, sizeof(serv_addr) );
serv_addr.sin_family = AF_INET;
serv_addr.sin_addr.s_addr = INADDR_ANY;
serv_addr.sin_port = htons( portno );
sockfd = socket( AF_INET, SOCK_STREAM, 0 );
n = bind ( sockfd, (struct sockaddr*)&serv_addr, sizeof(serv_addr) );
if ( n < 0 ) {
error("ERROR on binding\n");
}
listen( sockfd, 5 );
do {
cli_len = sizeof(cli_addr);
int newsockfd;
newsockfd = accept( sockfd,(struct sockaddr*)&cli_addr,(socklen_t *)&cli_len);
if ( newsockfd < 0 ) {
printf("%i", newsockfd);
error("ERROR on accept\n");
}
pid = fork();
if( pid == 0 ) {
close( sockfd );
sockfd = -1;
n = send( newsockfd, message, strlen(message), 0);
if ( n < 0 ) error("ERROR sending\n");
bzero(message, 256);
n = recv( newsockfd, message, 256, 0);
if ( n < 0 ) error("ERROR receiving\n");
close( newsockfd );
newsockfd = -1;
}
}
while( 1 );
return 0;
}
答案 0 :(得分:2)
如果fork()
的结果为零,则需要使用接受的套接字执行I / O,然后退出进程。目前,您在关闭侦听套接字后允许在子进程中重复接受循环。
答案 1 :(得分:1)
分叉的孩子应该在read()
之后结束,但事实并非如此。它继续循环。可能不是你的意图。
然后,孩子调用accept()
作为套接字描述符传递-1
。 -1
不是有效的套接字描述符。
accept(sockfd, ...
孩子将sockfd
设置为-1
:
pid = fork();
if( pid == 0 ) {
close( sockfd );
sockfd = -1;
这样做会导致socket()
返回的有效套接字描述符被覆盖,丢失。
因此,您观察到的错误不是来自您的侦听服务器进程,而是来自分离的孩子。
要解决此问题,请在孩子内部添加对exit()
的调用,如下所示:
...
newsockfd = -1;
exit(EXIT_SUCCESS);
}
此int cli_len;
应为socklen_t cli_len;
。调用cli_len
时accept()
的演员阵容应该被移除。 不盲目抛弃错误!