Денисrf
|
|
« : 04-05-2010 13:03 » |
|
Доброго времени! Вот такая проблема возникла, при создании простого эхо-сервера не получается отследить попытку подключения к сервер по получаемому IP адресу сервер-сокета. WSADATA wsadata; SOCKET ServerSocket; SOCKADDR_IN socketaddr; HOSTENT* pHostent; // Информация о хосте. // инициализация WinSock. if ((WSAStartup(MAKEWORD(2,2), &wsadata))==NULL) std::cout<<"Inization socket is complite"<<std::endl; else std::cout<<"Inization socket finished with error"<<std::endl; Sleep(150); //=====================Создание сокета================================== ServerSocket=socket(AF_INET,SOCK_STREAM,0); if (ServerSocket==INVALID_SOCKET) std::cout<<"INVALID_SOCKET"<<std::endl; else std::cout<<"ServerSocket created"<<std::endl; Sleep(150); //Заполним структуру адреса сокета на который будем его вешат socketaddr.sin_family=AF_INET; socketaddr.sin_port=PORT_ADDR; socketaddr.sin_addr.s_addr=0;//htons(INADDR_ANY) - принимает подключения на все IP адреса Sleep(150); //Вешаем сокет на сируктуру socketaddr if (bind(ServerSocket,(LPSOCKADDR)&socketaddr,sizeof(socketaddr))==SOCKET_ERROR) std::cout<<"Can't conect with 80 port"<<std::endl; else { std::cout<<"_____________________________________________________________________________"<<std::endl; std::cout<<"ServerSocket created: Type - SOCK_STREAM, Transport protcool - TCP, Port - 80"<<std::endl; std::cout<<"_____________________________________________________________________________"<<std::endl; } Sleep(150);
//Перевод сокета в ждущий режим if (listen(ServerSocket,QUEUE_SIZE)==SOCKET_ERROR) std::cout<<"Server is not in listen mode"<<std::endl; else std::cout<<"Server is in listen mode"<<std::endl;
pHostent = gethostbyname(chHostname); std::cout<<"Your IP adress: "<<inet_ntoa (*(reinterpret_cast<in_addr *>(*(pHostent->h_addr_list))))<<std::endl;
SOCKET client_socket; sockaddr_in client_addr; // адрес клиента // (заполняется системой) // функции accept необходимо передать размер // структуры int client_addr_size=sizeof(client_addr); while ((client_socket=accept(ServerSocket,(sockaddr *)&client_addr,&client_addr_size))) { nclients++; HOSTENT* pClientHostent; pClientHostent=gethostbyaddr((char *)client_addr.sin_addr.s_addr,4,AF_INET); //std::cout<<"New conect! "<<std::endl; printf("+%s [%s] new connect!\n",(pClientHostent)?pClientHostent->h_name:"",inet_ntoa(client_addr.sin_addr));
} Если есть у кого подозрения прошу поделиться. Спасибо!
|
|
|
Записан
|
Your password is personal - do not share it with anyone and make sure it is not easy to crack.
|
|
|
RXL
|
|
« Ответ #1 : 04-05-2010 15:42 » |
|
Денисrf, что значит "отследить попытку подключения"? Судя по общей неаккуратности, ошибка может быть где угодно.
|
|
|
Записан
|
... мы преодолеваем эту трудность без синтеза распределенных прототипов. (с) Жуков М.С.
|
|
|
Денисrf
|
|
« Ответ #2 : 05-05-2010 12:59 » |
|
Спасибо за замечание. Но вот что я пытаюсь сделать: Я получив IP хоста и повесив сокет на все IP хоста пробую в опере прописать найденный IP. По идее фнкция
client_socket=accept(ServerSocket,(sockaddr *)&client_addr,&client_addr_size)
должна бы вернуть управления и тогда выполнится тело цикла, но этого не происходит. Почему?
|
|
|
Записан
|
Your password is personal - do not share it with anyone and make sure it is not easy to crack.
|
|
|
RXL
|
|
« Ответ #3 : 05-05-2010 13:32 » |
|
Зачем получать IP? Для всех IP хоста есть специальный адрес - INADDR_ANY (0.0.0.0).
accept() вернет управление только после поступления запроса на слушающий сокет.
Не нравится мне проверка ошибок: проверять надо на корректное выполнение, а не на одну определенную ошибку. Ошибки бывают разные!
|
|
« Последнее редактирование: 05-05-2010 13:35 от RXL »
|
Записан
|
... мы преодолеваем эту трудность без синтеза распределенных прототипов. (с) Жуков М.С.
|
|
|
Денисrf
|
|
« Ответ #4 : 05-05-2010 13:56 » |
|
Ошибки я переработаю на проверку отрицательного значения позже, умаю так норм будет? Ну да, в структуре
socketaddr.sin_addr.s_addr=htons(INADDR_ANY); Так я поймаю любое подкбчение к IP хоста. Вот я и узаю один из них. Прописываю в опере и ничего, пишет срвер недоступен или подключается но сервер сообщений не передает. Вроде все правильно?
|
|
|
Записан
|
Your password is personal - do not share it with anyone and make sure it is not easy to crack.
|
|
|
darkelf
Молодой специалист
Offline
|
|
« Ответ #5 : 05-05-2010 14:48 » |
|
socketaddr.sin_addr.s_addr=htons(INADDR_ANY);
лучше, наверное, без htons(). Прописываю в опере и ничего, пишет срвер недоступен или подключается но сервер сообщений не передает. Вроде все правильно?
что Вы прописываете в Opere? Вообще, для тестирования серверов обычно используют telnet.
|
|
« Последнее редактирование: 05-05-2010 14:51 от darkelf »
|
Записан
|
|
|
|
resource
Молодой специалист
Offline
Пол:
|
|
« Ответ #6 : 05-05-2010 15:18 » |
|
лучше, наверное, без htons().
в случае INADDR_ANY - абсолютно без разницы. Он всё равно нулю равен
|
|
|
Записан
|
|
|
|
Денисrf
|
|
« Ответ #7 : 05-05-2010 17:11 » |
|
в случае INADDR_ANY - абсолютно без разницы. Он всё равно нулю равен Да, все равно нулю и так и так. В опере писал IP, Telnet тоже использовал, пишет сбой подключения. IP ipconfig видет такой же как и программа определяет, так что он правильный.
|
|
|
Записан
|
Your password is personal - do not share it with anyone and make sure it is not easy to crack.
|
|
|
resource
Молодой специалист
Offline
Пол:
|
|
« Ответ #8 : 05-05-2010 17:35 » |
|
зачем функции socket() передаешь нуль вместо TCP протокола ? Эдак ты по IP конектишься (хотя так нельзя сказать про IP-протокол) а не по TCP
ЗЫ это что принцип такой - не помню, что писать, напишу 0
|
|
« Последнее редактирование: 05-05-2010 17:37 от resource »
|
Записан
|
|
|
|
RXL
|
|
« Ответ #9 : 05-05-2010 19:02 » |
|
Денисrf, будь внимателен!
htons() => Host To Network, Short. Применяется для 16-битных величин. Таких как TCP или UDP порт. Обратное действие: ntohs().
htonl() => Host To Network, Long. Применяется для 32-битных величин. Таких как IP-адрес. Обратная функция: ntohl().
В протоколе можно указать 6 (TCP). По теории, должен использоваться TCP и при 0, но в винде все по особому и протокол указывать надо.
|
|
« Последнее редактирование: 05-05-2010 19:07 от RXL »
|
Записан
|
... мы преодолеваем эту трудность без синтеза распределенных прототипов. (с) Жуков М.С.
|
|
|
Денисrf
|
|
« Ответ #10 : 07-05-2010 10:50 » |
|
Я на TCP протокол так указываю - ServerSocket=socket(AF_INET,SOCK_STREAM,IPPROTO_TCP);
|
|
|
Записан
|
Your password is personal - do not share it with anyone and make sure it is not easy to crack.
|
|
|
RXL
|
|
« Ответ #11 : 07-05-2010 11:29 » |
|
И что в итоге?
Кстати, браузером лучше в последнюю очередь тестировать - вдруг он через прокси пытается...
|
|
|
Записан
|
... мы преодолеваем эту трудность без синтеза распределенных прототипов. (с) Жуков М.С.
|
|
|
Денисrf
|
|
« Ответ #12 : 07-05-2010 13:27 » |
|
Я пробую и через Telnet, и через Opera (на всякий). Вообще адресную структуру вот так задаю: socketaddr.sin_family=AF_INET; socketaddr.sin_port=htons(PORT_ADDR); socketaddr.sin_addr.s_addr=htonl ( INADDR_ANY );//htons(INADDR_ANY) - принимает подключения на все IP адреса
//=====================Создание сокета================================== ServerSocket=socket(AF_INET,SOCK_STREAM,IPPROTO_TCP);
И в результате обработка корректна. А вот интересный вопрос, а как широко применяются способы типа: 1) //Завязываем сообщения от сервера на сокет /*int Errors; const int WM_SERVER_ACCEPT = WM_USER+1; Errors=WSAAsyncSelect(ServerSocket,GetConsolHWND (),WM_SERVER_ACCEPT,FD_ACCEPT); if (Errors == SOCKET_ERROR) { printf(" AsyncSelect BAD\n"); exit(1); } else printf("Good AsyncSelect \n");*/ 2) ////Создаем событие, првязываем к скету, определяем о чем ему сообщать //HANDLE hEventConect;// = WSA_INVALID_EVENT; //hEventConect = WSACreateEvent(); //::WSAEventSelect(ServerSocket,hEventConect,FD_ACCEPT | FD_CLOSE); //// = (WSAEVENT*)::calloc(2, WSAEVENT);
//WSAEVENT* pEvents; //pEvents= &hEventConect; //INFINITE ////Сокет - одна переменная событий, НЕ ждать наступления всех событий, ждать 30с, НЕ получать алерты //Sleep(150); // //for (;;) //{ //if (WSA_WAIT_FAILED!=::WSAWaitForMultipleEvents(1, &hEventConect, FALSE, 30, FALSE)) // { // WSANETWORKEVENTS hConnectEvent; // if (0==::WSAEnumNetworkEvents(ServerSocket,hEventConect,&hConnectEvent)) // { // if (hConnectEvent.lNetworkEvents & FD_ACCEPT) // { // std::cout<<"Client connecting attempt"<<std::endl; // if(hConnectEvent.lNetworkEvents & FD_CLOSE) // { //Если хост разорвал соединение // WSACloseEvent(hEventConect); //Освобождаем ресурсы // return 0; //Завершаем поток // } // } // } // } //} //===================================================================================== Ведь это все тоже, верно? Конечно может не совсем корректный вопрос, все зависит от задач и плтформы сервера, но все же. Что по вашему мнению эффективнее?
|
|
« Последнее редактирование: 07-05-2010 13:29 от Денисrf »
|
Записан
|
Your password is personal - do not share it with anyone and make sure it is not easy to crack.
|
|
|
resource
Молодой специалист
Offline
Пол:
|
|
« Ответ #13 : 07-05-2010 14:31 » |
|
WSAAsyncSelect и вообще WSA* это, как я понимаю, относится исключительно к windows-сокетам. Впринципе вещь удобная. Не нужно вручную перебирать select'ом. Но сказать, что это лучше или хуже..... не могу (не знаю).
|
|
|
Записан
|
|
|
|
Денисrf
|
|
« Ответ #14 : 11-05-2010 13:30 » |
|
Доброго времени всем! По ходу возникла еще одна ошибка. В этом модуле возникает ошибка нарушения прав доступа при попытке заполнить структуру HOSTENT* pClientHostent; для того, чтобы в последствии определить IP адрес клиента. while ((client_socket=accept(ServerSocket,(sockaddr *)&client_addr,&client_addr_size))) { nclients++; HOSTENT* pClientHostent;
pClientHostent=gethostbyaddr((char *)client_addr.sin_addr.s_addr,4,AF_INET); ----Эта строка вызывает ошибку!!! std::cout<<"New conect! Users online: "; std::cout<<nclients<<std::endl; DWORD thID; if (CreateThread(NULL,NULL,SexToClient,&client_socket,NULL,&thID)) std::cout<<"New user in new thread... Thread's descriptor: "<<thID<<std::endl;
} Ошибка не при компиляции, а при выполнении программы при подключении клиента. Необработанное исключение в "0x71a9e3e1" в "Socket_Server.exe": 0xC0000005: Нарушение прав доступа при чтении "0xf98ae90a". Какие ваши мысли?
|
|
« Последнее редактирование: 11-05-2010 13:36 от Вад »
|
Записан
|
Your password is personal - do not share it with anyone and make sure it is not easy to crack.
|
|
|
Вад
|
|
« Ответ #15 : 11-05-2010 13:40 » |
|
А кто сказал, что структура sockaddr содержит char* - указатель на строку с адресом хоста? Там только ulong. Его нельзя так приводить.
|
|
|
Записан
|
|
|
|
Денисrf
|
|
« Ответ #16 : 11-05-2010 16:23 » |
|
А точно так я не внимателен. Спасибо. Вот как решил: HOSTENT* pClientHostent; pClientHostent=gethostbyaddr((char *)inet_ntoa(client_addr.sin_addr),4,AF_INET);
|
|
|
Записан
|
Your password is personal - do not share it with anyone and make sure it is not easy to crack.
|
|
|
RXL
|
|
« Ответ #17 : 11-05-2010 16:34 » |
|
Функция inet_ntoa() не безопасна в многопоточной программе, т.к. возвращает указатель на статический внутренний буфер. Надо помнить об этом и использовать осторожно.
|
|
|
Записан
|
... мы преодолеваем эту трудность без синтеза распределенных прототипов. (с) Жуков М.С.
|
|
|
Денисrf
|
|
« Ответ #18 : 11-05-2010 17:02 » |
|
Как это может повлиять на многопотчную программу? Будет не правильно IP адрес последующих клиентов определяться? Ну не обнулять же структуру каждый раз.
|
|
|
Записан
|
Your password is personal - do not share it with anyone and make sure it is not easy to crack.
|
|
|
RXL
|
|
« Ответ #19 : 11-05-2010 17:44 » |
|
Денисrf, буфер у inet_ntoa() всего один на процесс. Представь себе, что один поток вызвал эту функцию со своими параметрами и получил адрес статического буфера, но пока он не не закончил обработку буфера другой поток тоже делает вызов этой функции и буфер перезаписывается. Не трудно догадаться, что для программы это — нештатная ситуация. Первая ошибка новичков в многопоточном программировании — игнорирование подобных ситуаций (типа, вероятность мала — авось пронесет).
|
|
« Последнее редактирование: 11-05-2010 17:46 от RXL »
|
Записан
|
... мы преодолеваем эту трудность без синтеза распределенных прототипов. (с) Жуков М.С.
|
|
|
Денисrf
|
|
« Ответ #20 : 11-05-2010 18:12 » |
|
Буфер один на процесс, что же при порождении второго потока, или при повторном вызове он не перезаписывается? Это вообще действительно такая критичная ошибка?
|
|
|
Записан
|
Your password is personal - do not share it with anyone and make sure it is not easy to crack.
|
|
|
RXL
|
|
« Ответ #21 : 11-05-2010 18:18 » |
|
Денисrf, вот тебе пример: char * some_func(int val) { static char buffer[32];
buffer[snprintf(buffer, 31, "%d", val)] = 0; return buffer; }
Подумай на досуге о подводных камнях такого подхода. За одно ответишь на свои вопросы. Функция inet_ntoa очень старая и тогда о многопоточности не задумывались.
|
|
|
Записан
|
... мы преодолеваем эту трудность без синтеза распределенных прототипов. (с) Жуков М.С.
|
|
|
Денисrf
|
|
« Ответ #22 : 12-05-2010 05:32 » |
|
Спасибо за примерчик )) обязательно проанализирую.
|
|
|
Записан
|
Your password is personal - do not share it with anyone and make sure it is not easy to crack.
|
|
|
|