Я должен написать игру "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
Я надеюсь, что я мог бы сделать это ясно. Если бы кто-нибудь мог помочь, я был бы признателен.
Вы не можете оставить возвращаемое значение для чтения. От этого зависит правильность. В проблемной строке вы игнорируете ее, которая, вероятно, является частью проблемы, которую вы испытываете. Что, если он вернется 1, хотя вы ожидали, что 2 байта будут прочитаны? – usr
Спасибо вам за ответ. Как я уже упоминал в начале темы, я проверяю их, я просто оставляю их здесь, что здесь лучше читать. – user2962094
У меня есть проблемы с поиском истинных ошибок при наличии очевидных «ложных» ошибок в образце кода. Пожалуйста, просто опубликуйте полную версию, которая, на ваш взгляд, на 100% правильная. Многие люди злоупотребляют «чтением» (потому что это трудно использовать правильно), и я не могу сказать из этого кода, правильно ли вы используете. Как я мог найти вашу проблему в этих условиях?Вы даже говорите, что проблема в этой самой строке! Как просмотреть строку кода, которую вы не показываете? – usr