2014-02-06 54 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

相关问题