1

我想创建一个异步/非阻塞 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, &readfds, &writefds, NULL, NULL);

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

4

1 回答 1

1

I see a couple of problems with your code.

First of all, if you want to wait for input from both the socket and the terminal, you should put both of those fds into the readfds set:

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

Since you're not doing any writing, you shouldn't be using writefds.

Next, you should make sure that you're only trying to read from the terminal if it has input ready. So, you should be doing something like:

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

You're currently trying to read each time, no matter what happens.

Last, you're measuring the size of your file_buffer incorrectly when you make your recvfrom call. strlen only works once you've already put data into it. You should be using sizeof(file_buffer).

于 2013-04-20T07:19:35.580 回答