【问题标题】:Using select(..) on client在客户端使用 select(..)
【发布时间】:2013-10-04 11:00:53
【问题描述】:

我正在尝试在客户端实现 select(..),方法是创建多个套接字,除了 TCP 套接字之外,还从服务器到 recv(..)。我想接收使用 select(..) 创建的不同套接字的不同 recv(..) 上的数据。代码似乎没有按预期运行。请帮忙。谢谢!

#include<stdio.h>
#include<stdlib.h>
#include<unistd.h>
#include<sys/socket.h>
#include<sys/types.h>
#include<fcntl.h>
#include<sys/stat.h>
#include<netinet/in.h>
#include <arpa/inet.h>

int main(int argc, char *argv[])
{
    int count, createsocket, chunks, newsocket[5], i;
    int bufsize = 2048;
    char *buffer = malloc(bufsize);
    char fname[256];
    struct sockaddr_in address;
    fd_set master;
    fd_set read_fds;
    int fdmax, j; 

    FD_ZERO(&master);
    FD_ZERO(&read_fds);

    if((createsocket = socket(AF_INET, SOCK_STREAM, 0)) > 0)
    {
        printf("Socket created.\n");
    }

    address.sin_family = AF_INET;
    address.sin_port = htons(15001);
    inet_pton(AF_INET, argv[1], &address.sin_addr);

    if(connect(createsocket, (struct sockaddr*)&address, sizeof(address)) == 0)
    {
        printf("Connected to server %s\n",argv[1]);
    }

    printf("Enter the file name to download\n");
    scanf("%s",fname);

    send(createsocket, fname, sizeof(fname), 0);

//    printf("Enter the chunks of file to receive");
    printf("waiting to receive the file from server..\n");

    //code to create a new socket based on the number of chunks required

    for(i=0;i<4;i++)
    {
        if((newsocket[i] = socket(AF_INET, SOCK_STREAM, 0)) > 0)
        {
                printf("new Socket %d created.\n", i);
        }
    }

    FD_SET(createsocket, &master);
    fdmax = createsocket;

    for(;;)
    {
        read_fds = master;
        if(select(fdmax+1, &read_fds, NULL, NULL, NULL) == -1){
            perror("select");
            exit(2);
        }
        for(i=0; i<=fdmax; i++){
            if(FD_ISSET(i, &read_fds)) {
                if(i == createsocket) {
                    printf("something is happening..\n");

                    if(newsocket[i] == -1){
                        printf("socket %d\n",i);
                    } else {
                        FD_SET(newsocket[i], &master);
                        if(newsocket[i] > fdmax) {
                            fdmax = newsocket[i];
                        }
                        printf("still something is going on..\n");
                    }
                } else {
                    printf("Doing something..\n");
                    for(j = 0; j <= fdmax; j++) {
                        if(FD_ISSET(j, &master)) {
                            if(j!= createsocket && j!= i) {
                                if((count = recv(createsocket, buffer, bufsize, 0)) > 0) {
                                    perror("recv");
                                } else {
                                    write(1, buffer, count);
                                }

                            }
                        }
                    }
                }
            }
        }
    }



//    while((count = recv(createsocket, buffer, bufsize, 0)) > 0)
//        write(1, buffer, count);

    printf("EOF.\n");

    for(i=0;i<4;i++)
    {
        close(newsocket[i]);
    }
    return close(createsocket);
}

【问题讨论】:

  • “似乎没有按预期运行”不是可接受的问题描述。请提供更多信息。
  • @EJP 好吧,在带有 tcp 连接的客户端上使用 select 我正在尝试创建一些新的套接字来接收来自连接的 tcp 服务器的数据。因为,recv 是一个阻塞协议,所以我使用 select(..) 在客户端的不同新创建的套接字上从服务器接收数据。事情有点清楚了吗?
  • @EJP 客户端创建 k 个 TCP 套接字(每个用于分块接收的块)并使用“select(...)”函数进行异步 IO。也就是说,客户端并行下载块,并使用 IO 多路复用而不是多线程。当收到所有块时,它只是将块合并到一个文件中。
  • 开始时,尝试让 select 仅使用 一个 套接字可能是个好主意。
  • @alk 我从一个套接字开始,它正在工作。我意识到我创建的其他套接字是悬空的并且无论如何都没有连接到服务器。一个套接字正在工作,因为它已经通过 tcp 连接连接到服务器。有什么方法可以将客户端的多个套接字连接到同一台服务器?

标签: c select tcp client


【解决方案1】:

两个快速cmets:

首先,我们需要在每次在 while 循环中调用 select() 之前,设置文件描述符 (fd)——根据应用程序逻辑的需要设置尽可能多的 fd。在执行上述步骤之前,我们还应该将 fd_set 设置为零。这是因为当 select 返回时,它会返回相同的 fd_set 但它只会设置那些设置了事件的。因此,一种方法是从一个干净的状态开始,然后设置我们感兴趣的所有 fd。像这样:

FD_ZERO(&read_fd_set);
FD_SET(createsocket, &master); // We should do this for all connections
if(select(fdmax+1, &read_fds, NULL, NULL, NULL) == -1){

其次,您正在创建所有其他套接字(除了 createsocket 套接字),您打开了一个 TCP 套接字,但什么也不做。如果它是客户端,至少,我们将不得不调用 connect()。如果不建立显式连接,我们就无法对 TCP 套接字做任何有用的事情。

因此,高级注释是,如果您想要拥有 N 个客户端套接字,则打开 N 个套接字并将所有套接字连接到服务器。接下来,将所有 N 个 fd 传递给 select()(每次调用 select())并在循环中执行此操作。

【讨论】:

  • 我同意这个分析,我在阅读这里之前实现了相同的分析。该程序适用于已经连接到服务器的单套接字。我需要将客户端上的多个套接字连接到同一服务器。
【解决方案2】:

问题是您在尚未准备好读取的套接字上调用recv()。这就是select() 的作用, 告诉您哪些套接字已准备好读取。您调用 recv() 的逻辑会处理整个 fd 集合,而不仅仅是就绪集中的 fd。

【讨论】:

  • 我意识到我在做什么的错误。我修复了代码。至少我无法使用 5 个 read_fds 中的 3 个上的选择来接收数据。非常感谢您的支持。
猜你喜欢
  • 2015-09-05
  • 2015-04-20
  • 2011-04-25
  • 1970-01-01
  • 2016-04-19
  • 1970-01-01
  • 2016-12-08
  • 2015-09-10
  • 1970-01-01
相关资源
最近更新 更多