为什么 select() 在我的代码中没有返回?

问题描述 投票:0回答:3

我需要帮助调试具有单个服务器(充当主服务器)和多个客户端的多人游戏的一些代码。我想使用 select 和 FD_Set 函数将多个客户端连接到服务器。

一旦客户端连接到服务器,我将它们的文件描述符保存在一个数组中,并检查文件上是否有数据可供读取(使用 select)。如果是,则读取数据,否则我想向所有客户端广播一条消息。这是在循环中重复运行的。每一秒,我都想向所有客户广播一条消息。同时,我也想从客户端接收数据。所以我正在借助 select 函数检查数据的可用性。

这是我的代码:

服务器.c:

#include"stdio.h"
#include"stdlib.h"
#include"sys/types.h"
#include"sys/socket.h"
#include"string.h"
#include"netinet/in.h"
#include "sys/select.h"
#include <fcntl.h>

#define PORT 5000
#define BUF_SIZE 2000
#define CLADDR_LEN 100

int arr[4] = { 0 };
char clientAddr[4][CLADDR_LEN];

void main() {
    struct sockaddr_in addr, cl_addr;
    int sockfd, len, ret, newsockfd;
    char buffer[BUF_SIZE];
    fd_set fds;
    int maxfd = -1;
    int i = 0, j = 0;
    sockfd = socket(AF_INET, SOCK_STREAM, 0);
    if (sockfd < 0) {
        printf("Error creating socket!\n");
        exit(1);
    }
    printf("Socket created...\n");

    memset(&addr, 0, sizeof(addr));
    addr.sin_family = AF_INET;
    addr.sin_addr.s_addr = INADDR_ANY;
    addr.sin_port = PORT;

    ret = bind(sockfd, (struct sockaddr *) &addr, sizeof(addr));
    if (ret < 0) {
        printf("Error binding!\n");
        exit(1);
    }
    printf("Binding done...\n");

    printf("Waiting for a connection...\n");
    listen(sockfd, 4);

    for (j = 0; j < 2; j++) { //infinite loop
        len = sizeof(cl_addr);
        newsockfd = accept(sockfd, (struct sockaddr *) &cl_addr, &len);
        if (newsockfd < 0) {
            printf("Error accepting connection!\n");
            exit(1);
        }
        printf("Connection accepted...\n");

        inet_ntop(AF_INET, &(cl_addr.sin_addr), clientAddr[j], CLADDR_LEN);

        arr[j] = newsockfd;
        printf("\n%d", newsockfd);
        //FD_ZERO(&fds);
        //FD_SET(newsockfd, &fds);

    }
    close(sockfd);

    for (j = 0; j < 2; j++) {
        if (arr[j] > maxfd)
            maxfd = arr[j];
//      FD_SET(arr[j], &fds);

    //  fcntl(arr[i], F_SETFL, O_NONBLOCK); //stop listening for new connections by the main process.
    } //the child will continue to listen.
      //the main process now handles the connected client.

    while (1) {
        for (i = 0; i < 2; i++) {
            FD_SET(arr[i], &fds);
        }

        int returned = select(maxfd + 1, &fds, NULL, NULL, NULL);

        if (returned) {
            for (i = 0; i < 2; i++) {
                if (FD_ISSET(arr[2], &fds)) {
                    ret = recvfrom(arr[i], (void*) &buffer, sizeof(buffer), 0,
                            NULL, NULL);
                    if (ret < 0) {
                        printf("Error receiving data!\n");
                        exit(1);
                    }
                    printf("%s", buffer);
                }
            }
        }
        for (j = 0; j < 2; j++) {
                    ret = sendto(arr[j], "abc", BUF_SIZE, 0,
                            (struct sockaddr *) &cl_addr, len);
                    if (ret < 0) {
                        printf("Error sending data!\n");
                        exit(1);
                    }
                    printf("Sent data to %s: %s\n", clientAddr[j], buffer);

                }

    }

    /*while (1) {
        for (j = 0; j < 2; j++) {
            memset(buffer, 0, BUF_SIZE);
            if (FD_ISSET(arr[j], &fds)) {
                ret = recvfrom(arr[j], buffer, BUF_SIZE, 0,
                        (struct sockaddr *) &cl_addr, &len);
                if (ret < 0) {
                    printf("Error receiving data!\n");
                    exit(1);
                }
                printf("Received data from %s: %s\n", clientAddr[j], buffer);
            }
        }
        for (j = 0; j < 2; j++) {
            ret = sendto(arr[j], "abc", BUF_SIZE, 0,
                    (struct sockaddr *) &cl_addr, len);
            if (ret < 0) {
                printf("Error sending data!\n");
                exit(1);
            }
            printf("Sent data to %s: %s\n", clientAddr[j], buffer);

        }
        /* close(arr[0]);
         close[arr[1]);
         close(arr[2]);
         close(arr[3]);
    }*/
}

client.c

#include"stdio.h"    
#include"stdlib.h"    
#include"sys/types.h"    
#include"sys/socket.h"    
#include"string.h"    
#include"netinet/in.h"    
#include"netdb.h"  

#define PORT 5555  
#define BUF_SIZE 2000   

int main(int argc, char**argv) {    
 struct sockaddr_in addr, cl_addr;    
 int sockfd, ret;    
 char buffer[BUF_SIZE];    
 struct hostent * server;  
 char * serverAddr;  

 if (argc < 2) {  
  printf("usage: client < ip address >\n");  
  exit(1);    
 }  

 serverAddr = argv[1];   

 sockfd = socket(AF_INET, SOCK_STREAM, 0);    
 if (sockfd < 0) {    
  printf("Error creating socket!\n");    
  exit(1);    
 }    
 printf("Socket created...\n");     

 memset(&addr, 0, sizeof(addr));    
 addr.sin_family = AF_INET;    
 addr.sin_addr.s_addr = inet_addr(serverAddr);  
 addr.sin_port = PORT;       

 ret = connect(sockfd, (struct sockaddr *) &addr, sizeof(addr));    
 if (ret < 0) {    
  printf("Error connecting to the server!\n");    
  exit(1);    
 }    
 printf("Connected to the server...\n");    

 memset(buffer, 0, BUF_SIZE);  
 //printf("Enter your message(s): ");  

 //while (fgets(buffer, BUF_SIZE, stdin) != NULL) {  

 sleep(10);
 ret = sendto(sockfd, "a", BUF_SIZE, 0, (struct sockaddr *) &addr, sizeof(addr));    
 if (ret < 0) {    
  printf("Error sending data!\n\t-%s", buffer);    
 }  
 ret = recvfrom(sockfd, buffer, BUF_SIZE, 0, NULL, NULL);    
 if (ret < 0) {    
  printf("Error receiving data!\n");      
 } else {  
  printf("Received: ");  
  fputs(buffer, stdout);  
  printf("\n");  
 }    

 return 0;      
}    

(向客户端传递一个 IP 地址。)

这是行不通的。调试服务器时,它在 select 处等待,但没有接收或发送任何内容。可能是什么问题?

c sockets networking
3个回答
0
投票

可能是因为您没有监听正确的端口。

sockaddr_in
成员需要按照网络字节顺序进行配置:

memset(&addr, 0, sizeof(addr));
addr.sin_family = AF_INET;
addr.sin_addr.s_addr = htonl(INADDR_ANY);
addr.sin_port = htons(PORT);

0
投票

上面是 select 工作原理的示例,在 while 循环中,您必须设置 timeval 结构和套接字 sd

 while (1) {

    FD_ZERO(&readfds);
    FD_SET(sd, &readfds);

    tv.tv_sec = 0;
    tv.tv_usec = 0;

    rv = select(sd + 1, &readfds, NULL, NULL, &tv);

    if (rv == 1) {        
         /*recvfrom*/

    }
 }

0
投票

安全第一

FD_ZERO(&readfds)
而且你不必每次循环都
FDSET
你的
clientfds
。您可以在此之前设置一个时间。

如果您检查客户端并且客户端发送数据成功,请检查此行

for (i = 0; i < 2; i++) {
    if (FD_ISSET(arr[2], &fds)) {
        ret = recvfrom(arr[i], (void*) &buffer, sizeof(buffer), 0,
                            NULL, NULL);

在你的代码中

FD_ISSET(arr[2], &fds)
你可以像这样改变

FD_ISSET(arr[i], &fds)   

因为如果你不能改变

arr[i]

,你的 for 循环在这里什么也不做
© www.soinside.com 2019 - 2024. All rights reserved.