如何在C中无限期地保持套接字连接?

时间:2014-04-18 01:21:35

标签: c sockets

我正在尝试使用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套接字编程的人都可以给我一个提示,我应该在哪里看?谢谢。

2 个答案:

答案 0 :(得分:1)

accept()问题的原因是sockfd无效。你必须在某处关闭它。注意,如果你遇到这样的错误,你就不应该继续重试,就好像它没有发生一样。

客户端问题的原因是您只在ProcessRequest()中处理一个请求,顾名思义,并且正如您在评论中所描述的那样。使用循环,读取请求直到recv()返回零或发生错误。

答案 1 :(得分:-1)

原因

客户端面临错误的原因是服务器父级或服务器级子级的close(new_fd)

解决方案

在任何时候,服务器都可能会收到两种事件:

  1. 来自新客户的连接请求
  2. 来自现有客户的数据 服务器必须尊重他们两个。有两种(主要)方法来处理这个问题。
  3. 解决方案方法1

    将服务器设计为并发服务器。在Beej的指南中,它是

    7.2. select()—Synchronous I/O Multiplexing
    

    http://beej.us/guide/bgnet/output/html/singlepage/bgnet.html#select 由于OP的方法不是这个,我们不会进一步探讨它。

    解决方案方法2

    在服务器上,每个客户端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的连接,这持续了几个小时。