代码之家  ›  专栏  ›  技术社区  ›  mmutilva

服务器是否可以使用相同的套接字向客户端发送响应?怎样

  •  11
  • mmutilva  · 技术社区  · 17 年前

    我正在使用Berkeley套接字(Internet域和Unix域),我想知道服务器是否可以使用相同的套接字来读取请求并向客户端写入响应。或者客户端应该创建另一个套接字来等待重播,服务器在处理收到的消息后连接到该套接字。

    顺便说一下,我说的是面向连接的套接字(流套接字、TCP等等)。

    这是简化的服务器代码(为了简单起见,我在这里检查系统调用的常见错误):

    int main() {
    
        int server_socket, connected_socket;
        struct sockaddr_in server_addr;
        char buf[1024];
        char aux[256];
        int bytes_read;
    
        server_socket = socket(AF_INET, SOCK_STREAM, 0);    
    
        server_addr.sin_family = AF_INET;
        server_addr.sin_addr.s_addr = INADDR_ANY;
        server_addr.sin_port = htons(1234);
        bind(server_socket, &server_addr, sizeof(server_addr))
    
        listen(server_socket, 5)
    
        connected_sodket = accept(server_socket, 0, 0);
        do {
            bzero(buf, sizeof(buf));
            bytes_read = read(connected_socket, buf, sizeof(buf));        
        } while (bytes_read > 0);          
    
        /* Here I want to use connected_socket to write the reply, can I? */
    
        close(connected_socket);       
    
        close(server_socket);
    
        return (EXIT_SUCCESS);
    }
    

    int main() {
    
        int client_socket;
        struct sockaddr_in server_addr;
    
        client_socket = socket(AF_INET, SOCK_STREAM, 0);
    
        hp = gethostbyname("myhost");
        server_addr.sin_family = AF_INET;
        memcpy(&server_addr.sin_addr, hp->h_addr_list[0], hp->h_length);
        server_addr.sin_port = htons(1234);
    
        connect(client_socket, &server_addr, sizeof(server_addr));
    
        write(client_socket, MSG, sizeof(MSG));
    
        /* Here I want to wait for a response from the server using client_socket, can I? */
    
        close(client_socket);
    
        return (EXIT_SUCCESS);
    }
    

    connected_socket 在服务器和 client_socket

    我曾尝试在显示注释的客户机/服务器中使用read/wrint,但这样两个程序都会被阻止,这似乎是一个死锁。

    提前谢谢!

    9 回复  |  直到 17 年前
        1
  •  10
  •   Federico A. Ramponi    17 年前

    使用相同的插座!


    • 客户端与服务器建立连接;
    • 客户 ,根据协议,服务器将回复;因此,它等待同一套接字上的数据(recv());
    • 验证响应后,客户端可以关闭套接字。

    • 服务器接受来自客户端的连接;
    • 服务器 第一步取决于客户机,因此它等待数据(recv());
    • 服务器验证请求;
    • 服务器现在关闭 知道 ,表示客户端正在等待数据;因此,它使用send()发送其响应;
    • 服务器
        2
  •  8
  •   Chris Dodd    17 年前

    您可以使用相同的套接字,但您的程序已设置为让服务器在尝试应答之前读取客户端发送的所有内容。因此,在客户端关闭其套接字的写端之前,服务器中的循环不会完成,因此服务器将获得EOF(读取0字节),因此服务器将永远不会发送回其响应。

    有几种方法可以解决这个问题。

    1. 您可以在看到整个请求后在服务器中中断循环,而不是在EOF之前读取。这要求客户端发送的数据以某种方式进行自我定界,以便服务器能够知道何时读取所有数据。
    2. 您可以使用第二个连接进行回复。可能不是最好的。
    3. 您可以使用非对称关闭套接字。让客户做些什么 shutdown(client_socket, SHUT_WR) 把插座半合上。然后,服务器将看到EOF(循环将完成),但套接字上的另一个方向仍将为应答打开。
        3
  •  3
  •   Marc Novakowski    17 年前
        4
  •  2
  •   Alnitak    17 年前

    你不仅应该使用同一个插座(正如费德里科所说),实际上 不得不

    防火墙知道TCP连接,如果防火墙内的计算机启动了连接,则会自动允许返回数据通过。如果您尝试从外部创建一个新的TCP套接字,防火墙将阻止它,除非该通信量被明确允许。

        5
  •  1
  •   MattK    17 年前

    是的,SOCK_流套接字是双向的。您应该能够读写连接两侧的同一插座。的手册页 socket(2)

        6
  •  1
  •   user52875    17 年前

    是的,你可以。TCP套接字是双向的。只需使用相同的read()和write()函数。另外,请确保检查对connect()、read()、write()和。。。因为你无法控制网络上发生的事情。

        7
  •  1
  •   mmutilva    17 年前

    很抱歉我没有说,但我确实这样试过

    此代码位于注释所在的服务器中:

    write(connected_socket, "Ok, I got it", sizeof("Ok, I got it"));
    

    以及客户端中的以下代码,其中注释为:

    read(client_socket, buf, sizeof(buf));
    

    这两个程序都会被阻止,当我杀死客户端时,服务器会显示它收到的消息(在服务器调用之后,我有一个printf) ).

    我尝试使用send和recv(都有0个标志)而不是read和write,并且没有改变。

        8
  •  1
  •   sth    17 年前

    在当前设置中,服务器尝试读取,直到客户端关闭套接字,而客户端直到服务器应答才关闭套接字。因此你有一种“僵局”。服务器没有停止读取,希望更多的数据可能会到达,而客户端无法告诉服务器它已经完成了。

    您需要某种方式让服务器在连接仍然打开时识别请求已完成。例如,如果您通过换行终止请求,服务器可以检查是否收到完整的行,然后停止读取并发送答案。

        9
  •  0
  •   Rowland Shaw    17 年前