2013-12-11 42 views
0

我必須編寫一個使用UNIX域套接字的"Sea Battle"遊戲作爲分配。服務器和客戶端在同一臺機器上,只是爲了瞭解IPC。UNIX域套接字讀取()總是得到錯誤的值

每艘船都有一個尺寸。

我遇到了一個我無法解決的問題,我希望你有一個想法。首先我知道read(),write(),select(),...有一個返回值,我檢查它們。但是我會讓他們忘記代碼更好的可讀性。而且我還會留下其他不必要的代碼。

服務器和客戶端幾乎是相同的,除了連接(這不是問題),他們處於相反的狀態,這是檢查turn == 0並轉!= 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,A),但由於最後一攻沒打船的輸出是:

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%正確。很多人濫用'read'(因爲它很難正確使用),而且我無法從這段代碼中看出你的使用是否正確。在這種情況下我怎麼能找到你的問題?你甚至會說這個問題就在這一行!我如何查看不顯示的代碼行? – usr

回答

0

您正在使用部分未初始化的變量。 gameInfo是一個int(通常是4個字節),但您只讀入1個字節。此外,由於您實際上在其他地方將其用作int,因此排序問題發揮作用。

你很幸運,因爲你很可能在一個小端平臺上,但如果它不是之前和其他方式,不能使它成爲否定的gameInfo負面如果之前爲負值則爲正值。

+0

現在你提到它,它就像一輛卡車一樣打我。我不知道爲什麼我把它設置爲只有1個字節,看着其他的讀寫,我做了類似的錯誤。謝謝 – user2962094

+0

我糾正了所有這些故障,現在按預期工作。謝謝兩位的幫助。 – user2962094