Winsocks 2 асинхронная проблема - PullRequest
0 голосов
/ 16 сентября 2011

Я пытаюсь использовать winsock2 в асинхронном режиме. Я могу отправлять сообщения от клиента к серверу, но не от сервера к клиенту. Когда я вызываю recv на стороне клиента, в буфере ничего не принимается.

Вот мой код клиента

ClientSocket::ClientSocket (HWND& pHwnd)
{   
    WSADATA     wsdata;

    vSzIncoming     =   0;

    int error = WSAStartup (MAKEWORD(2,2), &wsdata);

    vSocket = socket (AF_INET, SOCK_STREAM, IPPROTO_TCP);

    error = WSAAsyncSelect (vSocket, pHwnd, WM_SOCKET, (FD_CLOSE | FD_READ));

    vHwnd           =   pHwnd;
    vIsConnected    =   false;
}

bool ClientSocket::ConnectToServer () 
{       

SockAddr.sin_port           =   htons (20000);
SockAddr.sin_family         =   AF_INET;
SockAddr.sin_addr.s_addr    =   inet_addr ("127.0.0.1");

if(connect (vSocket, (LPSOCKADDR)(&SockAddr), sizeof (SockAddr)) == SOCKET_ERROR) {


    vIsConnected = false;
    return false;
}

vIsConnected = true;
return true;
}

void ClientSocket::SendMsg (const MessageGenerator& pMessageGenerator)
{   
    send(vSocket, pMessageGenerator.GetMessage ().Buffer (), pMessageGenerator.GetLength (), 0);
}

char * ClientSocket::ReceiveMsg ()
{   
char temp[1024];
ZeroMemory (temp, sizeof (temp));

int inDataLength = recv (vSocket,
                    (char*)temp,
                     sizeof (temp) / sizeof (temp [0]),
                     0);
return temp;
}

Вот код сервера

WSADATA WsaDat;
        int nResult=WSAStartup(MAKEWORD(2,2),&WsaDat);


        Socket=socket(AF_INET,SOCK_STREAM,IPPROTO_TCP);

        SOCKADDR_IN SockAddr;
        SockAddr.sin_port=htons(nPort);
        SockAddr.sin_family=AF_INET;
        SockAddr.sin_addr.s_addr=htonl(INADDR_ANY);

        if(bind(Socket,(LPSOCKADDR)&SockAddr,sizeof(SockAddr))==SOCKET_ERROR)
        {

        }

        nResult=WSAAsyncSelect(Socket,
                hWnd,
                WM_SOCKET,
                (FD_CLOSE|FD_ACCEPT|FD_READ));

        if(listen(Socket,(1))==SOCKET_ERROR)
        {

        }

// отправить часть

String str ="1;yahoo;|";
send(Socket,str.Buffer(),str.GetLength(),0);

// получить часть

case WM_SOCKET:
    {
        switch(WSAGETSELECTEVENT(lParam))
        {
            case FD_READ:
            {
                char szIncoming[1024];
                ZeroMemory(szIncoming,sizeof(szIncoming));

                int inDataLength=recv(Socket,
                    (char*)szIncoming,
                    sizeof(szIncoming)/sizeof(szIncoming[0]),
                    0);

                String str(szIncoming);

                wcsncat(szHistory,str.GetTChar(),inDataLength);
                wcscat(szHistory,L"\r\n");


                SendMessage(hEditIn,
                    WM_SETTEXT,
                    sizeof(szIncoming)-1,
                    reinterpret_cast<LPARAM>(&szHistory));
            }

case FD_ACCEPT:
            {
                int size=sizeof(sockaddr);
                Socket=accept(wParam,&sockAddrClient,&size);                
            }

Пожалуйста, помогите мне

1 Ответ

1 голос
/ 16 сентября 2011

Трудно сказать, где твоя проблема. Лучшее решение - систематически устранять все возможные препятствия:

  • Проверьте возвращаемое значение recv. Если есть ошибка, ваш буфер остается нетронутым, поэтому возвращается «пустая» строка.
  • Проверьте на стороне сервера, используется ли правильный клиентский сокет. Вы используете слишком много раз имя «Socket». Лучше всего различать клиентский сокет и серверный сокет. Также: как хранить клиент-сокет? Это в глобальной или статической переменной? Вы уверены, что это значение верно? (Этот пункт в основном относится к вашему серверному коду)
  • Расширьте свой код с помощью ведения журнала, чтобы вы могли отслеживать, что происходит на стороне клиента и на сервере. Отладчик также может помочь с этим.

Также есть одна довольно большая ошибка, которую вы должны немедленно исправить в своем коде:

char * ClientSocket::ReceiveMsg ()
{   
    char temp[1024];
    ZeroMemory (temp, sizeof (temp));

    int inDataLength = recv (vSocket,
                        (char*)temp,
                         sizeof (temp) / sizeof (temp [0]),
                         0);
    return temp; // ** don't return a local memory "object" **
}

Не делай этого. Либо верните дубликат, используя _strdup , либо используйте и верните свой объект "String". Конечно, если вы используете _strdup, вызывающая сторона должна освободить память с помощью соответствующей функции (free). Ах да, третья возможность - просто ожидать, что буфер будет задан как параметр, как это делает recv.

...