Warning: file_get_contents(/data/phpspider/zhask/data//catemap/3/sockets/2.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C 我的服务器程序只在第二个请求到达时才响应第一个请求?_C_Sockets_Io_Client Server_Multiplexing - Fatal编程技术网

C 我的服务器程序只在第二个请求到达时才响应第一个请求?

C 我的服务器程序只在第二个请求到达时才响应第一个请求?,c,sockets,io,client-server,multiplexing,C,Sockets,Io,Client Server,Multiplexing,我试图通过编写一个服务器-客户机原型程序来学习套接字编程 服务器和客户端都需要能够处理来自stdin的命令,因此我使用select函数 我的问题是,服务器程序被阻止,只有在客户端发送另一个请求后才响应客户端请求 服务器.c 你能给我指一下正确的方向吗?我是否缺少有关发送和接收行为的信息?要使用select作为正确的IO多路复用工具,您需要正确维护FD_设置。由于每次select返回时,FD_集合只包含准备好进行操作的FD,这意味着您必须在每次调用select之前重新装备FD_集合 代码中还有另一

我试图通过编写一个服务器-客户机原型程序来学习套接字编程

服务器和客户端都需要能够处理来自stdin的命令,因此我使用select函数

我的问题是,服务器程序被阻止,只有在客户端发送另一个请求后才响应客户端请求

服务器.c

你能给我指一下正确的方向吗?我是否缺少有关发送和接收行为的信息?

要使用select作为正确的IO多路复用工具,您需要正确维护FD_设置。由于每次select返回时,FD_集合只包含准备好进行操作的FD,这意味着您必须在每次调用select之前重新装备FD_集合

代码中还有另一个问题,您不能只在循环中的FD_集合中添加新客户机,您需要保存它,然后在开始时重新配置它们

此外,您不需要检查集合中的每个FD,因为select将返回准备进行IO的FD数量

尝试以下更改:

int clients[MAX_CLIENTS] = {0};
int I;
int maxfd;
int server_sock = <the listening fd>;
FD_SET readfds;
int ret;
while(1) {
    // Setup SD_SET each time calling select
    FD_ZERO(&readfds);
    FD_SET(STDIN_FILENO, &readfds);
    maxfd = STDIN_FILENO;
    FD_SET(server_sock, &readfds);
    maxfd = max(maxfd, server_sock);
    for (I = 0; I < MAX_CLIENTS; I++) {
        if (clients[I] >= 0) {
            FD_SET(clients[I], &readfds);
            maxfd = max(maxfd, clients[I]);
    }

    if ((ret = select(maxfd+1,&readfds,NULL,NULL,NULL)) == -1) {
        error("Err in select");
    }
    for(i = 0; i < maxfd && ret; i++, ret--) {
        if(FD_ISSET(i, &readfds) {
            if (i == listenfd) {
                 // < add new client to clients array
            }
            else if (i == STDIN_FILENO) { /* keyboard input */
                 //  < parse server commands >
            }
            else {
                  // one of the client is ready
                  int nread = recv(i,buffer,BUFLEN,0);
                  if (nread == 0) {
                       // client is closed, remove I from clients array
                       continue;
                  }
                  process(buffer);
                  send(i,buffer,BUFLEN,0);
            }
        }
    }
}

最后但并非最不重要的一点是,作为对select的改进,可以在Linux上尝试类似epoll的功能,它可以为您维护状态,这样您就不需要像select那样重新武装所有FD。

默认情况下无限期地记住recv块。您可以使用setsockopt设置超时。此外,您需要管理循环中的fd_集数据,而您不需要。。。请注意,Linux声明,由于select修改其文件描述符集,因此如果在循环中使用调用,则必须在每次调用之前重新初始化这些集。如果使用linux,则更喜欢epoll而不是select。如果使用BSD,请选择kqueue而不是select。Windows有重叠的IO,Solaris有evpoll。。。如果您的代码预期在不同的系统上运行,请考虑使用抽象库即LIEBV。祝你好运@Myst我有两个fd_集变量,一个是constantread_fds,另一个是tmpfds,每次都会修改。我忘了在while循环的开头添加read_fds=tmpfds行,my bad。使用select,每次都需要在循环的顶部重建fd_集。如果不希望阻塞,则集合应包含所有文件描述符。除非FD_ISSET说文件描述符已经准备好,否则不要对文件描述符执行任何读写操作,否则会遇到阻塞。这意味着您可能处于这样一种情况,即您已经读取了一些数据,并且希望将其写入。。你还不能。。因此,你需要在做事的顺序上变得聪明。。或者将数据存储在缓冲区中。
while(1)
{
    if (select(fdmax + 1, &tmpfds, NULL, NULL, NULL) == -1)
    {
        error("Err in select");
    }
    if (FD_ISSET(0,&tmpfds))
    {
        fgets(buffer, BUFLEN, stdin);
        process_request(buffer);
        send(serverfd, buffer, BUFLEN, 0);
    }
    else if (FD_ISSET(serverfd,&tmpfds))
    {
        recv(serverfd, buffer, BUFLEN, 0);
        process_response(buffer); 
    }
}
int clients[MAX_CLIENTS] = {0};
int I;
int maxfd;
int server_sock = <the listening fd>;
FD_SET readfds;
int ret;
while(1) {
    // Setup SD_SET each time calling select
    FD_ZERO(&readfds);
    FD_SET(STDIN_FILENO, &readfds);
    maxfd = STDIN_FILENO;
    FD_SET(server_sock, &readfds);
    maxfd = max(maxfd, server_sock);
    for (I = 0; I < MAX_CLIENTS; I++) {
        if (clients[I] >= 0) {
            FD_SET(clients[I], &readfds);
            maxfd = max(maxfd, clients[I]);
    }

    if ((ret = select(maxfd+1,&readfds,NULL,NULL,NULL)) == -1) {
        error("Err in select");
    }
    for(i = 0; i < maxfd && ret; i++, ret--) {
        if(FD_ISSET(i, &readfds) {
            if (i == listenfd) {
                 // < add new client to clients array
            }
            else if (i == STDIN_FILENO) { /* keyboard input */
                 //  < parse server commands >
            }
            else {
                  // one of the client is ready
                  int nread = recv(i,buffer,BUFLEN,0);
                  if (nread == 0) {
                       // client is closed, remove I from clients array
                       continue;
                  }
                  process(buffer);
                  send(i,buffer,BUFLEN,0);
            }
        }
    }
}