TCP/IP ошибка инициализации
От: __boolean Россия  
Дата: 19.01.04 08:20
Оценка:
подскажите пожалуйста, что я делаю не правильно
для примера вырезал

        ....

    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;
    }
    CHAR szBuf[64];
    INT nPort = 5555;
    hSocket = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
    SOCKADDR_IN tcpaddr;
    tcpaddr.sin_family = AF_INET;
    tcpaddr.sin_port = htons((short)nPort);
    tcpaddr.sin_addr.s_addr = htonl(INADDR_ANY);
    if(bind(hSocket, (SOCKADDR*)&tcpaddr, sizeof(SOCKADDR_IN)) == SOCKET_ERROR)
        if(WSAGetLastError() == WSAEADDRINUSE){
        //пусть выбирает порт сам
            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);                
            }
        }
    if(listen(hSocket, 32) == SOCKET_ERROR){
        sprintf(szBuf, "WinSocket.dll. listen %d", WSAGetLastError());
        MessageBox(NULL, szBuf, "Внимание", MB_OK|MB_ICONWARNING);                
                return FALSE;  
    }
        return TRUE;


Во-первых, если порт уже занят, то почему-то getsockname не возвращает новый порт. Говорит 0.
getsockname(hSocket, (SOCKADDR*)&tcpaddr, &nLen);
nPort = ntohs(tcpaddr.sin_port);


Во-вторых, когда происходит accept, при вызове WSAAsyncSelect, выдается ошибка 10022(WSAEINVAL)

    SOCKADDR_IN saddr;
    INT nsaddr = sizeof(SOCKADDR_IN); 
    SOCKET hAcceptSocket = accept(hSocket,(SOCKADDR*)&saddr, &nsaddr); 
    if(hAcceptSocket != INVALID_SOCKET)
                if(WSAAsyncSelect(hAcceptSocket , hWnd, WM_SOCK_NETEVENT, nEvent) == SOCKET_ERROR){
                     char szBuf[64];
                     sprintf(szBuf, "WinSocket.dll. WSAAsyncSelect %d", WSAGetLastError());
                     MessageBox(NULL, szBuf, "Внимание", MB_OK|MB_ICONERROR);
                }


уже голову сломал, не могу понять где у меня баги.
Заранее спасибо
Re: TCP/IP ошибка инициализации
От: butcher Россия http://bu7cher.blogspot.com
Дата: 19.01.04 12:56
Оценка:
Здравствуйте, __boolean, Вы писали:

__>
__>        ....

__>    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.

почитай тут, может что и поможет:

Нет ничего невозможного..
Re: TCP/IP ошибка инициализации
От: _monster_  
Дата: 19.01.04 18:58
Оценка:
Здравствуйте, __boolean, Вы писали:

__>

__>Во-первых, если порт уже занят, то почему-то getsockname не возвращает новый порт. Говорит 0.
__>[ccode]
__>getsockname(hSocket, (SOCKADDR*)&tcpaddr, &nLen);
__>nPort = ntohs(tcpaddr.sin_port);
__>


Не работает потому, что 3-й параметр функции getsockname имеет тип "значение-результат".Инициализируй его длиной структуры tcpaddr и будет тебе счастье.

__>Во-вторых, когда происходит accept, при вызове WSAAsyncSelect, выдается ошибка 10022(WSAEINVAL)


__>
__>    SOCKADDR_IN saddr;
__>    INT nsaddr = sizeof(SOCKADDR_IN); 
__>    SOCKET hAcceptSocket = accept(hSocket,(SOCKADDR*)&saddr, &nsaddr); 
__>    if(hAcceptSocket != INVALID_SOCKET)
__>                if(WSAAsyncSelect(hAcceptSocket , hWnd, WM_SOCK_NETEVENT, nEvent) == SOCKET_ERROR){
__>                     char szBuf[64];
__>                     sprintf(szBuf, "WinSocket.dll. WSAAsyncSelect %d", WSAGetLastError());
__>                     MessageBox(NULL, szBuf, "Внимание", MB_OK|MB_ICONERROR);
__>                }
__>


10022, как нетрудно убедиться, означает недопустимый аргумент. Поскольку в данном коде не видно, что хранят переменные hWnd, nEvent и что означает константа WM_SOCK_NETEVENT, то ничего определенного сказать нельзя. Скажу лишь, что набросал подобный код и у меня все работает.
Re[2]: TCP/IP ошибка инициализации
От: __boolean Россия  
Дата: 20.01.04 07:51
Оценка:
ааа, всем спасибо, все, разобрался.
В первом случае и правда не инициализировал 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(связанный с сокетом), не совсем корректно.
Re[3]: TCP/IP ошибка инициализации
От: butcher Россия http://bu7cher.blogspot.com
Дата: 20.01.04 08:35
Оценка:
Здравствуйте, __boolean, Вы писали:

__>Тогда вопрос в догонку.

__>Когда клиентское приложение закрывают крестом. Как правильно закрыть соединение? Я думаю что вызвать на клиенте подряд shutdown, closesocket и потом DestroyWindow(связанный с сокетом), не совсем корректно.

почему? вполне корректно..

Нет ничего невозможного..
Re[4]: TCP/IP ошибка инициализации
От: __boolean Россия  
Дата: 20.01.04 13:22
Оценка:
Здравствуйте, butcher, Вы писали:

B>Здравствуйте, __boolean, Вы писали:


__>>Тогда вопрос в догонку.

__>>Когда клиентское приложение закрывают крестом. Как правильно закрыть соединение? Я думаю что вызвать на клиенте подряд shutdown, closesocket и потом DestroyWindow(связанный с сокетом), не совсем корректно.

B>почему? вполне корректно..


Ну я проверял, если вызвать shutdown и не дожидаться FD_CLOSE, то на удаленной стороне
сработает WSAGETSELECTERROR(lParam).
Re[5]: TCP/IP ошибка инициализации
От: _monster_  
Дата: 20.01.04 17:38
Оценка:
Здравствуйте, __boolean, Вы писали:

__>Ну я проверял, если вызвать shutdown и не дожидаться FD_CLOSE, то на удаленной стороне

__>сработает WSAGETSELECTERROR(lParam).

Обычный способ завершения соединения — вызов функции close (closesocket в Windows). При этом данный процесс не может больше использовать дескриптор сокета. Счетчик ссылок на этот дескриптор уменьшается на 1. Если он достигает нуля, то по умолчанию отправляются данные, поставленные в очередь для отправки, и осуществляется завершение соединения. (Поведение функции close можно изменить, воспользовавшись параметром сокета SO_LINGER). Если же он больше нуля, то завершения соединения не происходит.
Функция shutdown позволяет закрыть принимающий/отправляющий/оба конца соединения, несмотря на значение счетчика ссылок.

И еще. При завершении процесса все его открытые дескрипторы закрываются.

Теперь о примере. Что-то не совсем понятно, где что закрывается с помощью shutdown. Подробнее pls.
Если клиент поработал с сервером, и ему (клиенту) от него (сервера) уже ничего не нужно, то вызови close. Если клиент закончил отправку данных, но еще хочет что-то принять, то shutdown для отправляющего конца. Если наоборот — для принимающего.

А вообще, если собрался использовать все преимущества Winsock, то очень рекомендую посмотреть MSDN, как это делают ребята из Майкрософта.
 
Подождите ...
Wait...
Пока на собственное сообщение не было ответов, его можно удалить.