我正在尝试使用Beej的套接字指南中的代码在Linux中实现C套接字服务器,该代码位于:
http://beej.us/guide/bgnet/examples/server.c
这很有效,我在C#中编写了一个Windows客户端来与之通信。一旦客户端连接,我就让它向服务器发送一个字节数组,服务器读取它,然后发回一个字节数组。这很有效。
然而,在此之后,如果我让客户端尝试发送另一个字节数组,我会得到一个Windows弹出窗口,说“已建立的连接已被主机中的软件中止”。然后我必须再次与客户端重新连接。我希望无限期地保持连接打开,直到客户端发送断开命令,但尽管通过Beej的指南阅读,我似乎似乎没有得到它。我现在甚至都没有尝试实现disconnect命令,我只是试图保持连接打开,直到我关闭服务器。
我尝试在Beej的代码中删除close()调用:
while(1) { // main accept() loop
sin_size = sizeof their_addr;
new_fd = accept(sockfd, (struct sockaddr *)&their_addr, &sin_size);
if (new_fd == -1) {
perror("accept");
continue;
}
inet_ntop(their_addr.ss_family,
get_in_addr((struct sockaddr *)&their_addr),
s, sizeof s);
printf("server: got connection from %s\n", s);
if (!fork()) { // this is the child process
close(sockfd); // child doesn't need the listener
ProcessRequest(new_fd); // this is not Beej's code, I've replaced his code here (which was a simple string send()) with a function call that does a read() call, processes some data, then sends back a byte array to the client using send().
close(new_fd);
exit(0);
}
close(new_fd); // parent doesn't need this
}
但是这只是让我得到一个“套接字接受:无效文件描述符”的无限循环(我尝试同时删除close(new_fd)行,一起和分开,以及关闭(sockfd)。 任何更精通C套接字编程的人都可以给我一个提示,我应该在哪里看?谢谢。
答案 0 :(得分:1)
accept()问题的原因是sockfd无效。你必须在某处关闭它。注意,如果你遇到这样的错误,你就不应该继续重试,就好像它没有发生一样。
客户端问题的原因是您只在ProcessRequest()中处理一个请求,顾名思义,并且正如您在评论中所描述的那样。使用循环,读取请求直到recv()返回零或发生错误。
答案 1 :(得分:-1)
客户端面临错误的原因是服务器父级或服务器级子级的close(new_fd)
。
在任何时候,服务器都可能会收到两种事件:
将服务器设计为并发服务器。在Beej的指南中,它是
7.2. select()—Synchronous I/O Multiplexing
http://beej.us/guide/bgnet/output/html/singlepage/bgnet.html#select 由于OP的方法不是这个,我们不会进一步探讨它。
在服务器上,每个客户端fork()
一个进程。这是OP采取的方法,我们在这里探讨。从本质上讲,它正在调整OP代码中的ProcessRequest()
函数。这是一个草图。
void ProcessRequest( int new_fd ) {
char buffer[ N ];
for( ; ; ) { // infinite loop until client disconnects or some error
int const recvLen = recv( new_fd, buffer, sizeof buffer, 0 );
if( recvLen == 0 ) { break; } // client disconnected
else if( recvLen == -1 ) { perror( "recv" ); break; }
int const sendLen = send( new_fd, buffer, recvLen, 0 );
if( sendLen == -1 ) { perror( "send" ); break; }
// TODO if( sendLen < recvLen ) then send() in loop
}
}
我很抱歉有四个小时的半生不熟的解决方案。当我编辑答案时,我失去了与stackoverflow.com的连接,这持续了几个小时。