【问题标题】:implementing a non blocking udp socket by select()通过 select() 实现非阻塞 udp 套接字
【发布时间】:2013-04-20 06:57:32
【问题描述】:

我想创建一个异步/非阻塞 udp 客户端服务器应用程序,在该应用程序中,客户端和服务器应该相互聊天,而无需等待对方轮到对方。 我才知道这可以通过 select() 来完成...

这是我的服务器(仅提及通信部分):

fd_set readfds,writefds;

while(1){
    FD_ZERO(&readfds);
    FD_ZERO(&writefds);
    FD_SET(sd,&readfds);
    FD_SET(sd,&writefds);

    int rv = select(n, &readfds, NULL, NULL, NULL);
    if(rv==-1) 
    {
        printf("Error in Select!!!\n");
        exit(0);
    }
    if(rv==0) 
    {
        printf("Timeout occurred\n");
    }
    if (FD_ISSET(sd, &readfds))
    {     
        int client_length = (int)sizeof(struct sockaddr_in);
        memset(&buffer,0,sizeof(buffer));
        int bytes_received = recvfrom(sd, buffer,SIZE, 0, (struct sockaddr *)&client, &client_length);
        if (bytes_received < 0) {
            fprintf(stderr, "Could not receive datagram.\n");
            closesocket(sd);
            WSACleanup();
            exit(0);
        }
    }

    printf("\nClient says: %s",buffer);
    printf("\nWrite :");
    fgets(buffer,SIZE,stdin); 
    if(FD_ISSET(sd,&writefds)) {
        int client_length = (int)sizeof(struct sockaddr_in);
        if(sendto(sd, buffer,strlen(buffer), 0, (struct sockaddr *) &client,client_length)<0) {
            printf("Error sending the file! \n");
            printf("%d\n",WSAGetLastError());
            exit(1);
        }
    }
}
closesocket(sd);
WSACleanup();

return 0;

}

这是我的客户:

fd_set readfds,writefds;
while(1)
{
    FD_ZERO(&readfds);
    FD_ZERO(&writefds);
    FD_SET(cs,&readfds);
    FD_SET(cs,&writefds);
    int rv=select(n,&readfds,&writefds,NULL,NULL);
            if(rv==-1)
    {
        printf("Error in Select!!!\n");
        exit(0);
    }
    if(rv==0)
    {
        printf("Timeout occurred\n");
    }
    printf("\nWrite  ");

    fgets(send_buffer,SIZE,stdin);
    if(FD_ISSET(cs,&writefds))
    {
        int server_length = sizeof(struct sockaddr_in);
        FD_CLR(cs,&writefds);

        if (sendto(cs, send_buffer, (int)strlen(send_buffer) + 1, 0, (struct sockaddr *)&server, server_length) == -1)
        {
            fprintf(stderr, "Error transmitting data.\n");
            closesocket(cs);
            WSACleanup();
            exit(0);
        }
    }

    char file_buffer[SIZE];
    //Reply reception from the server:"Ready to receive file"
    int data2=0;
    if (FD_ISSET(cs, &readfds))
    {
        FD_CLR(cs,&readfds);
        int server_length = sizeof(struct sockaddr_in);
        data2=recvfrom(cs,file_buffer,strlen(file_buffer)-1,0,(struct sockaddr *)&server,&server_length);
        //file_buffer[data2]='\0';
        if(data2<0)
        {
            printf("Server is not on:(\n");
            exit(0);
        }
    }
    //printf("%d",data2);
    printf("\nServer says:");
    for(int i=0;i<data2;i++)
    {
        putchar(file_buffer[i]);
    } 
}

return 0;
}

一开始在服务器端我写了:int rv = select(n, &amp;readfds, &amp;writefds, NULL, NULL);

但是除了服务器和客户端之间的通信不正确之外,当服务器初始化时,这会导致在服务器控制台上打印整个空数组。 删除“&writefds”确实删除了冗余数据,但不正确的通信问题仍然存在...... 所以如果有人帮助我,我会非常感激......

【问题讨论】:

  • select 不一定是非阻塞调用。 If timeout is NULL (no timeout), select() can block indefinitely.
  • 不,它不是无限期阻塞,它会在两边阻塞一段时间,此时服务器/客户端没有得到输入。
  • 至于计时器,我没有使用它,因为我希望我的应用程序等待用户输入。
  • OP 的来源看起来很乱。

标签: c++ c sockets select


【解决方案1】:

我发现您的代码存在一些问题。

首先,如果你想同时等待socket和终端的输入,你应该把这两个fds都放入readfds集合中:

FD_SET(cs, &readfds);
FD_SET(stdin, &readfds);

既然你没有写任何东西,你不应该使用writefds

接下来,您应该确保仅在终端已准备好输入时才尝试从终端读取。所以,你应该这样做:

if (FD_ISSET(stdin, &readfds)) {
    // Read in from terminal...
}

无论发生什么,您当前都在尝试每次阅读。

最后,当您拨打recvfrom 时,您错误地测量了file_buffer 的大小。 strlen 仅在您已将数据放入其中后才有效。你应该使用sizeof(file_buffer)

【讨论】:

  • 我的编译器不接受语句“FD_SET(stdin,&readfds)”,是否需要包含一些头文件或者我应该定义它...?
  • 错误是:"Error 1 error C2446: '==' : no conversion from 'FILE *' to 'SOCKET'"
  • 哦,哎呀,等一下。如果你只是将我所说的stdin 替换为0(比如数字零)怎么办?
  • 这给了我“选择错误”:(:(:(
  • @AaymanKhalid(您也可以包括unistd.h 并使用STDIN_FILENO
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2011-09-12
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多