2014-02-06 53 views
2

我試圖寫一個遊戲,可以讓多個客戶端連接和播放 - 下面是相關的代碼(這是非常混亂的 - 後來清理):socket編程:「接受:錯誤的文件描述符」

編輯:我意識到這是一個大量的滾動......對待比賽的過程中到底發生崩潰:

std::cout << black_hits << " black hits & " << white_hits 
       << " white hits.\n"; 

    if (black_hits == 4) { 
     std::cout << "you won!\n"; 
     std::cin.ignore().get(); 
     close(client); //<<<< CRASH HERE 
     return 0; 
    } 

不是一個真正的崩潰我猜...但足夠接近:)


#include <iostream> 
#include <vector> 
#include <algorithm> 
#include <cstdlib> 
#include <ctime> 
#include <string> 
#include <sstream> 
#include <stdio.h> 
#include <stdlib.h> 
#include <unistd.h> 
#include <errno.h> 
#include <string.h> 
#include <sys/types.h> 
#include <sys/socket.h> 
#include <netinet/in.h> 
#include <netdb.h> 
#include <arpa/inet.h> 
#include <sys/wait.h> 
#include <signal.h> 

#define BACKLOG 10 
#define MAXDATASIZE 100 

typedef enum {RED,GREEN,BLUE,YELLOW,ORANGE} color; 
int StartMasterMind(int client, sockaddr_storage addr_in); 

struct msgstruct { 
     int length; 
     char* send_data; 
}; 

void sigchld_handler(int s) 
{ 
    while(waitpid(-1, NULL, WNOHANG) > 0); 
} 

// get sockaddr, IPv4 or IPv6: 
void *get_in_addr(struct sockaddr *sa) 
{ 
    if (sa->sa_family == AF_INET) { 
     return &(((struct sockaddr_in*)sa)->sin_addr); 
    } 

    return &(((struct sockaddr_in6*)sa)->sin6_addr); 
} 

int tcp_connect(const char *serv, const char *host = NULL) 
{ 
    int sockfd, new_fd; // listen on sock_fd, new connection on new_fd 
    struct addrinfo hints, *servinfo, *p; 
    struct sockaddr_storage their_addr; // connector's address information 
    socklen_t sin_size; 
    struct sigaction sa; 
    int yes=1; 
    char s[INET6_ADDRSTRLEN]; 
    int rv; 

    memset(&hints, 0, sizeof hints); 
    hints.ai_family = AF_UNSPEC; 
    hints.ai_socktype = SOCK_STREAM; 
    hints.ai_flags = AI_PASSIVE; // use my IP 

    if ((rv = getaddrinfo(host, serv, &hints, &servinfo)) != 0) { 
     fprintf(stderr, "getaddrinfo: %s\n", gai_strerror(rv)); 
     return 1; 
    } 

    // loop through all the results and bind to the first we can 
    for(p = servinfo; p != NULL; p = p->ai_next) { 
     if ((sockfd = socket(p->ai_family, p->ai_socktype, 
       p->ai_protocol)) == -1) { 
      perror("server: socket"); 
      continue; 
     } 

     if (setsockopt(sockfd, SOL_SOCKET, SO_REUSEADDR, &yes, 
       sizeof(int)) == -1) { 
      perror("setsockopt"); 
      exit(1); 
     } 

     if (bind(sockfd, p->ai_addr, p->ai_addrlen) == -1) { 
      close(sockfd); 
      perror("server: bind"); 
      continue; 
     } 

     break; 
    } 

    if (p == NULL) { 
     fprintf(stderr, "server: failed to bind\n"); 
     return 2; 
    } 

    freeaddrinfo(servinfo); // all done with this structure 

    if (listen(sockfd, BACKLOG) == -1) { 
     perror("listen"); 
     exit(1); 
    } 

    sa.sa_handler = sigchld_handler; // reap all dead processes 
    sigemptyset(&sa.sa_mask); 
    sa.sa_flags = SA_RESTART; 
    if (sigaction(SIGCHLD, &sa, NULL) == -1) { 
     perror("sigaction"); 
     exit(1); 
    } 

    printf("server: waiting for connections...\n"); 

    while(1) { // main accept() loop 
     sin_size = sizeof their_addr; 
     new_fd = accept(sockfd, (struct sockaddr *)&their_addr, &sin_size); 
     if (new_fd == -1) { 
      perror("accept"); 
      continue; 
     } 

     inet_ntop(their_addr.ss_family, 
      get_in_addr((struct sockaddr *)&their_addr), 
      s, sizeof s); 
     printf("server: got connection from %s\n", s); 

     if (!fork()) { // this is the child process 
      close(sockfd); // child doesn't need the listener 
      //if (send(new_fd, "Hello, world!", 13, 0) == -1) 
      // perror("send"); 
      //close(new_fd); 
      StartMasterMind(new_fd,their_addr); 
      // exit(0); 
     } 
     close(new_fd); // parent doesn't need this 
    } 

    return 0; 
} 

void InitializeGame(const char* port) 
{ 
    tcp_connect(port); 
} 

std::vector<color> GetInputAsColorMap(char* input) 
{ 
[...]//redacted for clarity 
} 

int StartMasterMind(int client, sockaddr_storage addr_in) 
{ 
    struct msgstruct message; 
    struct sockaddr_storage their_addr = addr_in; 
    socklen_t addr_len; 

    message.send_data = "Welcome to ... M A S T E R M I N D.\n"; 
    message.length = strlen(message.send_data); 
    send(client, message.send_data, message.length, 0); 

[...]//redacted for clarity 

    if (strcmp(theValue, "random") == 0 || strcmp(theValue, "Random") == 0) 
    { 
[...]//redacted for clarity 
    } 
    else 
    { 
[...]//redacted for clarity 
    } 


    char* buf; 

    for (int i = 0; i < 8; ++i) { 
     std::vector<color> current_try(4); 
     int black_hits = 0, white_hits = 0; 
     std::vector<int> correctColorIndex; 
     std::vector<int> correctColor; 

     bool exclude[4] = {false}; 
     std::cout << "test\n"; 
     message.send_data = "Please enter your guess: "; 
     message.length = strlen(message.send_data); 
     send(client, message.send_data, message.length, 0); 

     addr_len = sizeof their_addr; 
     std::cout << "addr_len: " << addr_len << std::endl;  

     recvfrom(client, buf, MAXDATASIZE-1, 0, (struct sockaddr *)&their_addr, &addr_len); 

     current_try = GetInputAsColorMap(buf); 
     std::cout << "the buffer: " << buf << std::endl; 
     std::cout << "current_try: " << current_try[0] << current_try[1] << current_try[2] << current_try[3] << std::endl; 

[...]//redacted for clarity 

     std::cout << black_hits << " black hits & " << white_hits 
        << " white hits.\n"; 

     if (black_hits == 4) { 
      std::cout << "you won!\n"; 
      std::cin.ignore().get(); 
      close(client); //<<<< CRASH HERE 
      return 0; 
     } 
    } 

[...]//redacted for clarity 
} 

int main(int argc, char** argv) 
{ 
    InitializeGame(argv[1]); 
    return 0; 
} 

下面是示例輸出:

server: waiting for connections... 
server: got connection from 127.0.0.1 
value or random: 
1122 
test 
addr_len: 128 
the buffer: 1123� 
current_try: 1123 
3 black hits & 0 white hits. 
test 
addr_len: 128 
the buffer: 1223� 
current_try: 1223 
2 black hits & 1 white hits. 
test 
addr_len: 128 
the buffer: 1122� 
current_try: 1122 
4 black hits & 0 white hits. 
you won! 
accept: Bad file descriptor 
accept: Bad file descriptor 
accept: Bad file descriptor 
... // continuously, hundreds of times 

我很新的Socket編程;有人能幫我一把嗎?在遊戲結束時有或沒有嘗試close(client)時崩潰。

+2

如果它顯示'accept:Bad file descriptor',那麼'close(client)'處的「crash」如何?這肯定意味着'接受'問題。 –

+0

你是對的,對不起 - 我是超級新手,並且還沒有想出如何在gdb下有效地進行調試 - 然而,'接受:'應該已經把它拿走了,我想.. :) – MrDuk

回答

7

我認爲,當子進程被包裹回至開始while(1)循環,它試圖accept與服務器socket描述符=「sockfd」你已經關閉了孩子的連接:

if (!fork()) { // this is the child process 
      close(sockfd); 
.... 
} 

嘗試this link閱讀如何在其工作完成後終止子進程。

+1

我認爲與上述答案相同,可能您可能會將服務器套接字打開。我這種情況下,你所有的孩子都會嘗試接受這些關係。或者您可能希望在完成後退出子進程。 – pmverma

+0

我剛剛測試註釋'關閉(sockfd)',它似乎工作!然而,這似乎很糟糕......我想在什麼時候關閉sockfd? – MrDuk

+1

因爲服務器套接字正在接受連接,所以應該在代碼的最後部分關閉套接字。就像之前從函數返回一樣。 – pmverma

2

該消息意味着你打電話給accept()一個無效的文件描述符,即可能是一個關閉。

+0

[編輯] - 斯克,我撒謊。看起來好像我完全按照@MadHatter的建議關閉了sockfd。 – MrDuk

相關問題