__> ....
__> WSADATA WsaData;
__> WORD wVers = MAKEWORD( 2, 0 );
__> INT nError = WSAStartup(wVers, &WsaData);
__> if(nError) return FALSE;
__> if(LOBYTE( WsaData.wVersion ) != 2 || HIBYTE( WsaData.wVersion ) != 0 ){
__> MessageBox(NULL, "Версия winsock не должна быть ниже 2.0", "Внимание", MB_OK|MB_ICONWARNING);
__> WSACleanup();
__> return FALSE;
__> }
// Этот код, ИМХО, не нужен, если ошибка будет, до сюда не дойдёт, если не будет, то эта проверка не нужна
__> if(bind(hSocket, (SOCKADDR*)&tcpaddr, sizeof(SOCKADDR_IN)) == SOCKET_ERROR)
// Здесь лучше вывести код ошибки а не то что следует далее
__> if(WSAGetLastError() == WSAEADDRINUSE){ // если порт занят, то можно установить SO_REUSEADDR
__> //пусть выбирает порт сам
__> tcpaddr.sin_port = 0;
__> if(bind(hSocket, (SOCKADDR*)&tcpaddr, sizeof(SOCKADDR_IN)) == SOCKET_ERROR){
__> sprintf(szBuf, "WinSocket.dll. bind %d", WSAGetLastError());
__> MessageBox(NULL, szBuf, "Внимание", MB_OK|MB_ICONERROR);
__> }
__> else{
__> INT nLen;
__> getsockname(hSocket, (SOCKADDR*)&tcpaddr, &nLen);
__> nPort = ntohs(tcpaddr.sin_port);
__> sprintf(szBuf, "WinSocket.dll. Порт по умолчанию занят, новый порт %d", nPort);
__> MessageBox(NULL, szBuf, "Внимание", MB_OK|MB_ICONWARNING);
__> }
/* Можешь объяснить назначение этого кода? почитай про getsockname повнимательнее, ИМХО, у неё другое назначение,
и в данном контексте её вызов некорректен */
__> }
__> if(listen(hSocket, 32) == SOCKET_ERROR){
__> sprintf(szBuf, "WinSocket.dll. listen %d", WSAGetLastError());
__> MessageBox(NULL, szBuf, "Внимание", MB_OK|MB_ICONWARNING);
__> return FALSE;
__> }
__> return TRUE;
__>
__>Во-вторых, когда происходит accept, при вызове WSAAsyncSelect, выдается ошибка 10022(WSAEINVAL)
WSAEINVAL Indicates that one of the specified parameters was invalid such as the window handle not referring to an existing window, or the specified socket is in an invalid state.
__>Во-первых, если порт уже занят, то почему-то getsockname не возвращает новый порт. Говорит 0.
__>[ccode]
__>getsockname(hSocket, (SOCKADDR*)&tcpaddr, &nLen);
__>nPort = ntohs(tcpaddr.sin_port);
__>
Не работает потому, что 3-й параметр функции getsockname имеет тип "значение-результат".Инициализируй его длиной структуры tcpaddr и будет тебе счастье.
__>Во-вторых, когда происходит accept, при вызове WSAAsyncSelect, выдается ошибка 10022(WSAEINVAL)
__>
10022, как нетрудно убедиться, означает недопустимый аргумент. Поскольку в данном коде не видно, что хранят переменные hWnd, nEvent и что означает константа WM_SOCK_NETEVENT, то ничего определенного сказать нельзя. Скажу лишь, что набросал подобный код и у меня все работает.
ааа, всем спасибо, все, разобрался.
В первом случае и правда не инициализировал nLen(неприятно то, что в Builder-ре работало и без инициализации, там nLen, имел выходное значение
The Windows Sockets getsockname function gets the local name for a socket.
int getsockname (
SOCKET s,
struct sockaddr FAR* name,
int FAR* namelen
);
Parameters
s[in] A descriptor identifying a bound socket.
name [out] Receives the address (name) of the socket.
namelen[out] The size of the name buffer.
), а во-втором у меня правда hWnd некорректный был.
Тогда вопрос в догонку.
Когда клиентское приложение закрывают крестом. Как правильно закрыть соединение? Я думаю что вызвать на клиенте подряд shutdown, closesocket и потом DestroyWindow(связанный с сокетом), не совсем корректно.
Здравствуйте, __boolean, Вы писали:
__>Тогда вопрос в догонку. __>Когда клиентское приложение закрывают крестом. Как правильно закрыть соединение? Я думаю что вызвать на клиенте подряд shutdown, closesocket и потом DestroyWindow(связанный с сокетом), не совсем корректно.
Здравствуйте, butcher, Вы писали:
B>Здравствуйте, __boolean, Вы писали:
__>>Тогда вопрос в догонку. __>>Когда клиентское приложение закрывают крестом. Как правильно закрыть соединение? Я думаю что вызвать на клиенте подряд shutdown, closesocket и потом DestroyWindow(связанный с сокетом), не совсем корректно.
B>почему? вполне корректно..
Ну я проверял, если вызвать shutdown и не дожидаться FD_CLOSE, то на удаленной стороне
сработает WSAGETSELECTERROR(lParam).
Здравствуйте, __boolean, Вы писали:
__>Ну я проверял, если вызвать shutdown и не дожидаться FD_CLOSE, то на удаленной стороне __>сработает WSAGETSELECTERROR(lParam).
Обычный способ завершения соединения — вызов функции close (closesocket в Windows). При этом данный процесс не может больше использовать дескриптор сокета. Счетчик ссылок на этот дескриптор уменьшается на 1. Если он достигает нуля, то по умолчанию отправляются данные, поставленные в очередь для отправки, и осуществляется завершение соединения. (Поведение функции close можно изменить, воспользовавшись параметром сокета SO_LINGER). Если же он больше нуля, то завершения соединения не происходит.
Функция shutdown позволяет закрыть принимающий/отправляющий/оба конца соединения, несмотря на значение счетчика ссылок.
И еще. При завершении процесса все его открытые дескрипторы закрываются.
Теперь о примере. Что-то не совсем понятно, где что закрывается с помощью shutdown. Подробнее pls.
Если клиент поработал с сервером, и ему (клиенту) от него (сервера) уже ничего не нужно, то вызови close. Если клиент закончил отправку данных, но еще хочет что-то принять, то shutdown для отправляющего конца. Если наоборот — для принимающего.
А вообще, если собрался использовать все преимущества Winsock, то очень рекомендую посмотреть MSDN, как это делают ребята из Майкрософта.