2013-12-11 3 views
0

Я должен написать игру "Sea Battle" с использованием сокетов домена UNIX в качестве назначения. Сервер и клиент находятся на одной машине, и это просто узнать о IPC.Домен сокета UNIX read() всегда получает неправильное значение

Каждое судно имеет размер один.

У меня возникла проблема, которую я не могу решить, и надеюсь, у вас есть идея.

Сначала я знаю, что read(), write(), select(), ... имеет возвращаемое значение, и я проверяю их. Однако я оставлю их, что код лучше читаем. И я также оставляю другой ненужный код.

Сервер и клиент практически идентичны, кроме соединения (что не является проблемой), и они находятся в противоположном состоянии, которое проверяется с помощью turn == 0 и turn! = 0. Снова я просто пишу один.

Итак, моя проблема: в противном случае функция чтения не блокируется из-за ввода в консоль в if. Я попытался решить это с помощью select, но я всегда ошибаюсь. В первом ходу он всегда читает (0,0) дюйм. В вражеской очереди он использует данные с последнего входа.

int main(int argc, const char * argv[]) 
{ 
    if(argv[1]==NULL){ 
     std::cout << "no socket path" << std::endl; 
     return 1; 
    } 

    Playfield field(5); 

    fd_set rfds; 
    FD_ZERO(&rfds); 


    int turn = 0; 
    int sock; 
    struct sockaddr_un address; 
    int cordinate[2]; 
    int status[1]; 
    int gameInfo[1]; 

    if((sock = socket(AF_UNIX, SOCK_STREAM,0)) < 0){ 
     std::cerr << "error creating socket" << std::endl; 
    } 

    address.sun_family = AF_UNIX; 
    strcpy(address.sun_path, argv[1]); 

    std::cout << "trying to connect..." << std::endl; 

    if(connect(sock,(struct sockaddr*) &address, sizeof(address)) == 0){ 
     std::cout << "conected" << std::endl; 

    int inputHeight; 
    char inputLengthChar; 
    bool noWinnerFound=true; 
    FD_SET(sock, &rfds); 

    while(noWinnerFound){ 

     read(sock, gameInfo, 1); 
     if(gameInfo[0]<=0){ 
      std::cout << std::endl; 
      std::cout << "you have won. congratulation!" << std::endl; 
      noWinnerFound=false; 
      break; 
     } 
     gameInfo[0] = field.getRemainingShips(); 
     write(sock, gameInfo, 1); 

     if(field.getRemainingShips()<=0){ 
      std::cout << std::endl; 
      std::cout << "you have lost." << std::endl; 
      noWinnerFound=false; 
      break; 
     } 

     if(turn%2!=0){ 
      std::cout << "your turn: " << std::endl; 
      std::cout << std::endl; 
      field.print(); 
      std::cout << "enter which field you want to attack" << std::endl; 
      std::cin >> inputHeight >> inputLengthChar; 
      if(inputHeight>field.getHeight() || inputHeight<0 ||((int)(inputLengthChar-65))>=field.getLength() || (int)inputLengthChar-65<0){ 
       std::cin.setstate(std::cin.failbit); 
      } 
      else if(field.getEnemyField(inputHeight-1,((int)(inputLengthChar-65))!=field.EMPTY_FIELD)){ 
       std::cout << "you already attacked that field" << std::endl; 
       std::cin.setstate(std::cin.failbit); 
      } 
      while(std::cin.fail()){ 
       std::cout << "Please enter: number character" << std::endl; 
       std::cin.clear(); 
       std::cin.ignore(std::numeric_limits<std::streamsize>::max(), '\n'); 
       std::cin >> inputHeight >> inputLengthChar; 
       if(inputHeight>field.getHeight() || ((int)inputLengthChar)-65>=field.getLength()){ 
        std::cin.setstate(std::cin.failbit); 
       } 
       else if(field.getEnemyField(inputHeight-1,((int)(inputLengthChar-65))!=field.EMPTY_FIELD)){ 
        std::cout << "you already attacked that field" << std::endl; 
        std::cin.setstate(std::cin.failbit); 
       } 
      } 

      cordinate[0] = inputHeight-1; 
      cordinate[1] = ((int)(inputLengthChar-65)); 
      if(write(sock, cordinate, 2) == -1) 
       std::cerr << "error writing" << std::endl; 
      //select(sock2, &rfds, NULL, NULL, &stop); 
      int n = select(sock+1, &rfds, NULL, NULL, NULL); 
      if(n == -1){ 
       std::cerr << "error select" << std::endl; 
      } else{ 
       if(FD_ISSET(sock, &rfds)){ 
        if(read(sock, status, 1) == -1) 
         std::cerr << "error reading" << std::endl; 
        if(status[0]==field.SHIP){ 
         field.setEnemyField(cordinate[0], cordinate[1], field.SHIP); 
         std::cout << std::endl; 
         std::cout << "you hit a ship" << std::endl; 
        } 

        else{ 
         field.setEnemyField(cordinate[0], cordinate[1], field.ATTACKED); 
        } 
       } 
      } 

      field.print(); 
      ++turn; 

     } 

     else{ 
      std::cout << std::endl; 
      std::cout << "enemy turn please wait" << std::endl; 
      int n = select(sock+1, &rfds, NULL, NULL, NULL); 
      if(n == -1){ 
       std::cerr << "error select" << std::endl; 
      } else{ 
       if(FD_ISSET(sock, &rfds)){ 
        if(read(sock, cordinate, 2) <= 0) 
         std::cerr << "error reading" << std::endl; 
        status[0] = field.getField(cordinate[0], cordinate[1]); 
        write(sock, status, 1); 
        if(status[0]==field.SHIP){ 
         field.decreaseRemainingShips(); 
        } 
        else if(status[0]==field.EMPTY_FIELD){ 
         field.setField(cordinate[0], cordinate[1], field.ATTACKED); 
        } 
       } 
      } 
      ++turn; 
     } 
    } 
} 
else{ 
    std::cout << "no server found" << std::endl; 
    exit(1); 
} 

close(sock); 

return 0; 

}

Вот пример:

Давайте предположим, что корабли установлены таким образом: (X стенд для корабля, O означает нападение, которое не было судно)

server:   client: 
    A B C D E  A B C D E 
1 X    1 X 
2 X    2 X 
3 X    3  X 
4 X    4  X 
5 X    5   X 

В игре начинается белая доска, представляющая вражескую доску и поле атаки сервера (1, B):

server:   client: 
    A B C D E  A B C D E 
1 X   1 
2    2 
3    3  
4    4  
5    5   

, который явно ошибочен, но использует значение поля (1, A) в противнике, оно использует значение из поля ввода сервера. Допустим, клиент атаки (1, а), который ударит корабль, но так как последняя атака не попала на корабль выход:

server:   client: 
    A B C D E  A B C D E 
1 X   1 O 
2    2 
3    3  
4    4  
5    5  

Я надеюсь, что я мог бы сделать это ясно. Если бы кто-нибудь мог помочь, я был бы признателен.

+0

Вы не можете оставить возвращаемое значение для чтения. От этого зависит правильность. В проблемной строке вы игнорируете ее, которая, вероятно, является частью проблемы, которую вы испытываете. Что, если он вернется 1, хотя вы ожидали, что 2 байта будут прочитаны? – usr

+0

Спасибо вам за ответ. Как я уже упоминал в начале темы, я проверяю их, я просто оставляю их здесь, что здесь лучше читать. – user2962094

+0

У меня есть проблемы с поиском истинных ошибок при наличии очевидных «ложных» ошибок в образце кода. Пожалуйста, просто опубликуйте полную версию, которая, на ваш взгляд, на 100% правильная. Многие люди злоупотребляют «чтением» (потому что это трудно использовать правильно), и я не могу сказать из этого кода, правильно ли вы используете. Как я мог найти вашу проблему в этих условиях?Вы даже говорите, что проблема в этой самой строке! Как просмотреть строку кода, которую вы не показываете? – usr

ответ

0

Вы используете частично неинициализированную переменную. gameInfo - это int (обычно четыре байта), но вы читаете только 1 байт. Кроме того, поскольку вы на самом деле используете его как внутри других, проблемы с контентом вступают в игру.

Вам повезло, так как вы, вероятно, находитесь на платформе с маленькой платформой, но вы все равно не можете сделать отрицательный результат gameInfo, прочитав значение, если оно не было раньше и наоборот, не может сделать это положительный, если раньше был отрицательный.

+0

Теперь, когда вы упомянули об этом, он ударил меня, как грузовик. Я понятия не имею, почему я установил это только 1 байт, а другой смотрел и писал, что делал подобные ошибки. Спасибо – user2962094

+0

Я исправил все эти неисправности, и он работает сейчас, как и предполагалось. Спасибо вам за помощь. – user2962094

Смежные вопросы