Сокеты TCP-IP C: ошибка неверного адреса при попытке подключения к сокету сервера - PullRequest
0 голосов
/ 31 января 2019

Я пытаюсь создать клиент-серверную игру в крестики-нолики в качестве домашней работы.Я настраиваю сервер-слушатель и соединения в отдельных функциях, а не в основной программе.Создание сокета сервера прошло успешно, но клиентские соединения не работают, что, по-моему, и является причиной сбоя seg.

Я уже искал подобные проблемы и как можно лучше вносил изменения в мой код,как установка переменной для sizeof (cli_addr) вместо прямой передачи в accept ().Я не знаю, почему он не работает.

Это функция, которая устанавливает соединения

void setup_connections(int serversocket,int *clientsocket,int portnum){
int cli_size,con_num = 0;
struct sockaddr_in cli_addr;

//server is listening for clients
listen(serversocket,5);

while(con_num<2){


    cli_addr.sin_family = AF_INET;
    cli_addr.sin_addr.s_addr = INADDR_ANY;
    cli_addr.sin_port = htons(portnum);

    //accept connection while creating client socket
    cli_size = sizeof(cli_addr);
    clientsocket[con_num] = accept(serversocket,(struct sockaddr *) &cli_addr,cli_size);

    if(clientsocket[con_num]<0){
        perror("Error: ");
    }

    con_num++;

    }
}

При компиляции о типе cli_size я получаю предупреждение.

* предупреждение: несовместимое преобразование целочисленного значения в указатель, передающее 'int' параметру типа 'socklen_t *' (также известный как unsigned int * ') [-Wint-преобразование] clientsocket [con_num] = accept (serversocket, (struct sockaddr *)1011 *) & cli_addr, cli_size);

Однако все проверенные мной примеры передаются следующим образом.

Это функция, которая устанавливает сокет сервера.

int setup_server(int portnum){
int serversocket,serv_bind;
struct sockaddr_in server_addr;


serversocket = socket(AF_INET, SOCK_STREAM, 0);
if(serversocket<0){
    printf("Failed to create server\n");
}

//set up server info
server_addr.sin_family = AF_INET;
server_addr.sin_addr.s_addr = INADDR_ANY;
server_addr.sin_port = htons(portnum); //port number given by user

//link server address to socket
serv_bind = bind(serversocket,(struct sockaddr *) &server_addr,sizeof(server_addr));
if(serv_bind<0){
    printf("Failed to bind\n");
}

return serversocket;
}

И это код в main.c, который их вызывает:

int portnum,serversocket, clientsocket[2]; //sockets


portnum = atoi(argv[1]);
if(argc < 2){
    printf("Port number not given");
}

//create sockets
serversocket = setup_server(portnum);
setup_connections(serversocket,clientsocket);

Что я получаю после запуска программы:

Ошибка:: Плохой адрес

Ошибка:: Плохой адрес

Ошибка сегментации: 11

Если вы можете объяснить мне, что я делаю неправильно, это было бы очень полезно.

Ответы [ 2 ]

0 голосов
/ 31 января 2019

При компиляции о типе cli_size я получаю предупреждение.

* предупреждение: несовместимое целочисленное преобразование в указатель, передающее 'int' параметру типа 'socklen_t *' (он же unsigned int * ')[-Wint-преобразование] clientsocket [con_num] = accept (serversocket, (struct sockaddr) & cli_addr, cli_size);

Однако все примеры, которые я проверял, передают его так:

Нет, они этого не делают.Если они это сделают, они получат ту же ошибку, что и вы, при компиляции.

Это прототип для accept

int accept(int sockfd, struct sockaddr *addr, socklen_t *addrlen);
//                                                      ^ Note the asterisk

Вы можете ясно видеть, что он ожидает указатель на socklen_t , а не a socklen_t.Ваша строка accept должна выглядеть следующим образом:

clientsocket[con_num] = accept(serversocket,(struct sockaddr *) &cli_addr,&cli_size); 
//                                                                        ^ Note the pointer indirection

Если вы собираетесь использовать структуру cli_addr, вам следует проверить, что возвращаемый размер не больше, чем переданный вами размер, потому что еслиэто означает, что структура адреса была усечена.

Вот что говорит Справочная страница Linux :

Аргумент addrlen является аргументом значение-результат: вызывающая сторона должна инициализировать его так, чтобы он содержал размер (в байтах) структуры, на которую указывает addr;по возвращении он будет содержать фактический размер адреса узла.

0 голосов
/ 31 января 2019

Вы вправе принять к сведению полученное предупреждение:

предупреждение: несовместимое целочисленное преобразование в указатель, передающее 'int' параметру типа 'socklen_t *' (также известный как unsigned int * ') [-Wint-преобразование] clientocket [con_num] = принять (serversocket, (struct sockaddr) & cli_addr, cli_size);

Вы не допустите скидку на это:

Тем не менее, все примеры, которые я проверял, проходят так:

Если во всех рассмотренных вами примерах используется код, аналогичный вашему, то вам крайне необходимо найти лучшие примеры.Что еще более важно, однако, вам нужно научиться полагаться на документацию , предпочтительно в качестве первого обращения, но, по крайней мере, для устранения неопределенностей, таких как "это предупреждение - то, о чем я должен заботиться?"(Подсказка: до тех пор, пока вы не сможете выразить основанную на документации причину, ответ всегда будет «да, я должен заботиться о предупреждениях».)

Быстрый просмотр документов для accept() показывает, что третий параметр, как ожидается, будет указателем на переменную , содержащую размер объекта адреса, который вы передаете, и функция обновит эту переменную (черезуказатель), чтобы содержать фактическую длину возвращенного адреса.Вместо этого вы передаете сам размер, и преобразование в указатель почти наверняка приведет к неправильному.Вам действительно повезло, что это так, и вы получите ошибку во время выполнения, поскольку альтернативой является то, что вы молча производите повреждение памяти в каком-то случайном месте в вашей программе.

Обратите внимание, что bind() отличается.Требуется передать размер адреса напрямую, а не косвенно.Это разумно, потому что нет причин для изменения размера.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...