Форум программистов «Весельчак У»
  *
Добро пожаловать, Гость. Пожалуйста, войдите или зарегистрируйтесь.
Вам не пришло письмо с кодом активации?

  • Рекомендуем проверить настройки временной зоны в вашем профиле (страница "Внешний вид форума", пункт "Часовой пояс:").
  • У нас больше нет рассылок. Если вам приходят письма от наших бывших рассылок mail.ru и subscribe.ru, то знайте, что это не мы рассылаем.
   Начало  
Наши сайты
Помощь Поиск Календарь Почта Войти Регистрация  
 
Страниц: [1]   Вниз
  Печать  
Автор Тема: Создание эхо-сервера  (Прочитано 21034 раз)
0 Пользователей и 7 Гостей смотрят эту тему.
Денисrf
Постоялец

ru
Offline Offline
Пол: Мужской

« : 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
Технический
Администратор

ru
Offline Offline
Пол: Мужской

WWW
« Ответ #1 : 04-05-2010 15:42 » 

Денисrf, что значит "отследить попытку подключения"?
Судя по общей неаккуратности, ошибка может быть где угодно.
Записан

... мы преодолеваем эту трудность без синтеза распределенных прототипов. (с) Жуков М.С.
Денисrf
Постоялец

ru
Offline Offline
Пол: Мужской

« Ответ #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
Технический
Администратор

ru
Offline Offline
Пол: Мужской

WWW
« Ответ #3 : 05-05-2010 13:32 » new

Зачем получать IP? Для всех IP хоста есть специальный адрес - INADDR_ANY (0.0.0.0).

accept() вернет управление только после поступления запроса на слушающий сокет.

Не нравится мне проверка ошибок: проверять надо на корректное выполнение, а не на одну определенную ошибку. Ошибки бывают разные!
« Последнее редактирование: 05-05-2010 13:35 от RXL » Записан

... мы преодолеваем эту трудность без синтеза распределенных прототипов. (с) Жуков М.С.
Денисrf
Постоялец

ru
Offline Offline
Пол: Мужской

« Ответ #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
Молодой специалист

fr
Offline 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
Молодой специалист

ru
Offline Offline
Пол: Мужской

« Ответ #6 : 05-05-2010 15:18 » 

Цитата: darkelf
лучше, наверное, без htons().
в случае INADDR_ANY - абсолютно  без разницы. Он всё равно нулю равен
Записан
Денисrf
Постоялец

ru
Offline Offline
Пол: Мужской

« Ответ #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
Молодой специалист

ru
Offline Offline
Пол: Мужской

« Ответ #8 : 05-05-2010 17:35 » 

зачем функции socket() передаешь нуль вместо TCP протокола ? Эдак ты по IP конектишься (хотя так нельзя сказать про IP-протокол) а не по TCP

ЗЫ это что принцип такой - не помню, что писать, напишу 0
« Последнее редактирование: 05-05-2010 17:37 от resource » Записан
RXL
Технический
Администратор

ru
Offline Offline
Пол: Мужской

WWW
« Ответ #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
Постоялец

ru
Offline Offline
Пол: Мужской

« Ответ #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
Технический
Администратор

ru
Offline Offline
Пол: Мужской

WWW
« Ответ #11 : 07-05-2010 11:29 » 

И что в итоге?

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

... мы преодолеваем эту трудность без синтеза распределенных прототипов. (с) Жуков М.С.
Денисrf
Постоялец

ru
Offline Offline
Пол: Мужской

« Ответ #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
Молодой специалист

ru
Offline Offline
Пол: Мужской

« Ответ #13 : 07-05-2010 14:31 » 

WSAAsyncSelect  и вообще WSA* это, как я понимаю, относится исключительно к windows-сокетам. Впринципе вещь удобная. Не нужно вручную перебирать select'ом. Но сказать, что это лучше или хуже..... не могу (не знаю).
Записан
Денисrf
Постоялец

ru
Offline Offline
Пол: Мужской

« Ответ #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.
Вад
Модератор

ru
Offline Offline
Пол: Мужской

« Ответ #15 : 11-05-2010 13:40 » 

А кто сказал, что структура sockaddr содержит  char* - указатель на строку с адресом хоста? Там только ulong. Его нельзя так приводить.
Записан
Денисrf
Постоялец

ru
Offline Offline
Пол: Мужской

« Ответ #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
Технический
Администратор

ru
Offline Offline
Пол: Мужской

WWW
« Ответ #17 : 11-05-2010 16:34 » 

Функция inet_ntoa() не безопасна в многопоточной программе, т.к. возвращает указатель на статический внутренний буфер. Надо помнить об этом и использовать осторожно.
Записан

... мы преодолеваем эту трудность без синтеза распределенных прототипов. (с) Жуков М.С.
Денисrf
Постоялец

ru
Offline Offline
Пол: Мужской

« Ответ #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
Технический
Администратор

ru
Offline Offline
Пол: Мужской

WWW
« Ответ #19 : 11-05-2010 17:44 » 

Денисrf, буфер у inet_ntoa() всего один на процесс. Представь себе, что один поток вызвал эту функцию со своими параметрами и получил адрес статического буфера, но пока он не не закончил обработку буфера другой поток тоже делает вызов этой функции и буфер перезаписывается. Не трудно догадаться, что для программы это — нештатная ситуация. Первая ошибка новичков в многопоточном программировании — игнорирование подобных ситуаций (типа, вероятность мала — авось пронесет).
« Последнее редактирование: 11-05-2010 17:46 от RXL » Записан

... мы преодолеваем эту трудность без синтеза распределенных прототипов. (с) Жуков М.С.
Денисrf
Постоялец

ru
Offline Offline
Пол: Мужской

« Ответ #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
Технический
Администратор

ru
Offline Offline
Пол: Мужской

WWW
« Ответ #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
Постоялец

ru
Offline Offline
Пол: Мужской

« Ответ #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.
Страниц: [1]   Вверх
  Печать  
 

Powered by SMF 1.1.21 | SMF © 2015, Simple Machines