2014-11-06 57 views
0

我需要使用單個服務器(作爲主服務器)和多個客戶端來調試多人遊戲的代碼。我想使用select和FD_Set函數將這些多個客戶端連接到服務器。爲什麼select()不會在我的代碼中返回?

一旦客戶端連接到服務器,我將它們的文件描述符保存在一個數組中,並檢查數據是否可用於文件讀取(使用select)。如果是,請閱讀數據,否則我想向所有客戶端廣播消息。這是循環重複運行。每一秒,我都想向所有客戶播放一條消息。同時,我也想從客戶端接收數據。所以我在選擇函數的幫助下檢查數據的可用性。

這裏是我的代碼:

Server.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地址)

This does 不行。在調試服務器時,它在選擇時等待並且沒有收到或發送任何內容。問題可能是什麼?

+0

你似乎檢查'if(FD_ISSET(arr [2]',但你從未在'arr [2]'中描述符上調用過FD_SET(),並且忘記檢查arr [0]上的FD_ISSET()和arr [1 ] – nos 2014-11-06 12:57:45

回答

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

以上例子,如何選擇工作,在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

它仍然不能正常工作 – emanuel 2014-11-06 14:26:25

0
In security firstly FD_ZERO(&readfds) 
and you not have to FDSET your clientfds every while loop. You can set one time before the while. 

Id u check the client side and clients send data succesfully check the this line 

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

In your code FD_ISSET(arr[2], &fds) you can change the like this 

FD_ISSET(arr[i], &fds) because your for loop do nothing here if you can not change the arr[i] 
相關問題