| Версия для печати темы
Нажмите сюда для просмотра этой темы в оригинальном формате |
| Форум программистов > C/C++: Общие вопросы > Использовать WinSock 2 или...? |
| Автор: KPEHDEL 4.2.2011, 12:11 |
| Здравствуйте! Требуется создать архитектуру клиент -> сервер С++. Подскажите пожалуйста, что нынче используют для этого WinSock или есть какие-то более современнее, продвинутые программы. Требуется создать две простейшие проги, сервер ставится на один комп, клиент на другой, клиент пингует сервер и получает ответа чёнить типа "Пинг естЬ" или "Пинга нет". Заранее спасибо, жду вашего ответа" |
| Автор: KaraKum 4.2.2011, 12:46 |
| WinSock немножко виндовая - для компиляции в Линуксе нужно будет 2 строчки заменить, а среди кросс-платформенных есть http://enet.bespin.org/, http://www.boost.org/doc/libs/1_43_0/doc/html/boost_asio/overview.html. |
| Автор: boostcoder 4.2.2011, 13:40 |
| asio. libevent. |
| Автор: KPEHDEL 6.2.2011, 01:23 | ||||
| Перерыл весь инет вроде получилось собрать клиент и сервер, переписал немного код под себя,всё работает: Сервер:
Клиент:
Но получается что к серверу может подцепится только один клиент, если попробывать запустить второй клиент, приложение ответа от сервера не получит. Не сложно догадаться, что требуется дописать только сервер. С этим у меня и проблема не совсем пойму какие действия должны выполняться, чтобы сервер позволял приконнектится нескольким клиентам (winSock ток начал изучать). В коде сервера выделил для этого место, есть такой комментарий, туда надо дописать: //-------- /*Здесь надо написать что-то, для того чтобы можно было присоединить несколько Klientov*/ //-------- Помогите понять какие действия требуется дописать, если будут примеры, буду благодарен. Заранее спасибо. |
| Автор: KaraKum 6.2.2011, 01:28 | ||
В приведённом примере сервер ждёт только одно подключение, после чего получает только одно сообщение от клиента и завершается, а нужно чтобы процесс получения сообщений длился вечно:
|
| Автор: KPEHDEL 6.2.2011, 07:07 | ||
Дописал сервер, клиент не изменял, всё работает. Вот изменёный код сервера:
Посмотрите, всё ли записанно граматно, или может можно записать в чём то более правильно. Укажите на ошибки) Хочется приблизить написание к более правильному) И ещё вопрос, как правильнее указать ограничение на количество присоединённых клиентов? |
| Автор: KaraKum 6.2.2011, 14:14 | ||
В примере всё верно, однако сервер отправляет клиенту лишь одно сообщение и то сразу после подключения оного, но не удастся реализовать "произвольное общение", например как это происходит в играх, базах данных и прочее. Для этого, поддержку соединения с каждым клиентом нужно отправлять в отдельный поток, а в текущем потоке продолжать "слушать" попытки создания входящих соединений.
|
| Автор: KaraKum 6.2.2011, 14:49 |
| А вот при использовании http://enet.bespin.org/ отдельных потоков для каждого клиента создавать не нужно |
| Автор: KPEHDEL 6.2.2011, 20:06 | ||
Примерно понял, но не совсем... немного пожанглировал, получилось чё-то типа этого(прекрасно понимаю, что не правильно):
Помогите добиться правильного результата)) ENet, libevent и asio обязательно посмотрю, после того как с этим разбирусь |
| Автор: KaraKum 6.2.2011, 20:08 | ||||
ENet не экзотичнее чем какие-либо другие. |
| Автор: KaraKum 6.2.2011, 21:07 |
| Функции recv() достаточно только в ThreadFunction() - больше нигде её вызывать не нужно. В остальном всё верно. А что нужно реализовать? Какие действия должны выполняться? В чём цель написания этого клиент-сервера? Если что-то из этого знать, то можно посоветовать что-то по-конкретнее. А вообще архитектура клиент-сервера такая (для TCP): - сервер: - поднятие сервера - ожидание подключений - поддержка каждого созданного подключения (обычно в отдельном потоке) - возможность узнать от какого конкретно клиента приходят данные и возможность отправить данные любому из текуще подключённых клиентов - клиент: - подключение к серверу и поддержка одного-единственного соединения - отправка/получение данных В последнем варианте, в принципе, всё это реализовано. |
| Автор: KPEHDEL 6.2.2011, 23:10 | ||
| Изначально цель была просто изучение, возникла эта цель вспонтанно, когда проснулся утром в общаге, не знал чем заняться. Теперь вот думаю, что цель можно будет поставить как клиент-сервер для игры. Оставил recv() только в ThreadFunction(), удалил из вайла в main(). Всё ещё остались следующие вопросы: Не пойму что надо вбить в CreateThread(..., ..., ThreadFunction, opaqueData, ...); за место троеточий. И например вот здесь: recv(opaqueData->socket, buf, 1024,0); за место buf тоже надо использовать размер буфера например 1024? SOCKET connection = accept(); - функция accept ведь не может быть пустой. Правильно ли сделал, что в нижепредставленном коде вынес SOCKET socket,SSock;//как глобальную переменную, так как используется не только в функции? Где лучше объявить addr_klienta? Изменённый код сервера:
Так как C++ изучаю относитльно недавно, бывают сложности с синтаксом. Синтаксические ошибки на которые ругается Visual Studio 2010: [/quote]1>Server_V0.01.cpp(10): error C2327: OpaqueData::addr_klienta: не является именем типа, статическим членом или перечислителем 1>Server_V0.01.cpp(10): error C2065: addr_klienta: необъявленный идентификатор 1>Server_V0.01.cpp(10): error C2070: 'unknown-type': недопустимый оператор sizeof 1>Server_V0.01.cpp(10): error C2864: OpaqueData::size_client_addr: в пределах класса могут быть инициализированы только статические константные данные-члены целого типа 1>Server_V0.01.cpp(11): error C2327: OpaqueData::addr_klienta: не является именем типа, статическим членом или перечислителем 1>Server_V0.01.cpp(11): error C2065: addr_klienta: необъявленный идентификатор 1>Server_V0.01.cpp(11): error C2327: OpaqueData::size_client_addr: не является именем типа, статическим членом или перечислителем 1>Server_V0.01.cpp(11): error C2065: size_client_addr: необъявленный идентификатор 1>Server_V0.01.cpp(11): error C4430: отсутствует спецификатор типа - предполагается int. Примечание. C++ не поддерживает int по умолчанию 1>Server_V0.01.cpp(11): error C2864: OpaqueData::socket: в пределах класса могут быть инициализированы только статические константные данные-члены целого типа 1>Server_V0.01.cpp(12): error C2059: синтаксическая ошибка: if 1>Server_V0.01.cpp(12): error C2238: непредвиденные лексемы перед ";" 1>Server_V0.01.cpp(12): error C2059: синтаксическая ошибка: else 1>Server_V0.01.cpp(12): error C2238: непредвиденные лексемы перед ";" 1>Server_V0.01.cpp(22): error C2227: выражение слева от "->socket" должно указывать на тип класса, структуры или объединения либо на универсальный тип 1> тип: void * 1>Server_V0.01.cpp(22): error C2065: buf: необъявленный идентификатор 1>Server_V0.01.cpp(23): error C2065: buf: необъявленный идентификатор 1>Server_V0.01.cpp(23): error C2227: выражение слева от "->someData" должно указывать на тип класса, структуры или объединения либо на универсальный тип 1> тип: void * 1>Server_V0.01.cpp(54): error C2660: accept: функция не принимает 0 аргументов 1>Server_V0.01.cpp(55): error C2061: синтаксическая ошибка: идентификатор "SomeData" 1>Server_V0.01.cpp(55): error C2661: OpaqueData::OpaqueData: нет перегруженной функции, принимающей 2 аргументов 1>Server_V0.01.cpp(58): error C2664: send: невозможно преобразовать параметр 1 из "SOCKET (__stdcall *)(int,int,int)" в "SOCKET" 1> Не существует контекста, в котором такое преобразование возможно 1>Server_V0.01.cpp(59): error C2143: синтаксическая ошибка: отсутствие ")" перед "..." 1>Server_V0.01.cpp(59): error C2660: CreateThread: функция не принимает 0 аргументов 1>Server_V0.01.cpp(59): error C2059: синтаксическая ошибка: ) Вот это всё надо мне отладить, чтобы успокоится)))) С вашей помощью получится точно |
| Автор: KaraKum 7.2.2011, 00:40 |
| Ну, приведённый мною код не подразумевался компилироваться В некомпилируемости много причин, можно начать "отлаживать" со следующего: - в OpaqueData нужно передавать только ту информацию, которую хочется - в данном случае нужно передавать только SOCKET чтобы можно было вызвать функцию recv() в ThreadFunction() - SOCKET socket переменная не может быть глобальной - она конкретна для каждого отдельного соединения, поэтому её и нужно передавать в функцию ThreadFunction() - в объявлении класса (в данном случае OpaqueData) не должны вызываться функции - CreateThread() вызывать так: CreateThread(NULL, 0, (LPTHREAD_START_ROUTINE)ThreadFunction, opaqueData, 0, NULL); |
| Автор: KPEHDEL 7.2.2011, 09:09 | ||
| В OpaqueData чтобы передовался только сокет стираем две верхних строчки: class OpaqueData { socket=accept(SSock,(sockaddr*)&addr_klienta,&size_client_addr); if (socket==INVALID_SOCKET) puts("4) ERROR! client connection."); else puts("4) The client is connected.\n"); void* someData; }; Так? Подправил CreateThread. Убрал обозначение сокет переменных как глобальных. В исправлении дальнейших ошибок по прежнему путаюсь. Код:
|