2010-11-05 4 views
0

Начну с кодом:Winsock RECV дает 10014 ошибку

typedef std::vector<unsigned char> CharBuf; 
static const int RCV_BUF_SIZE = 1024; 
SOCKET m_socket = a connected and working socket; 

// ... 

CharBuf buf; // Declare buffer 
buf.resize(RCV_BUF_SIZE); // resize buffer to 1024 
char* p_buf = reinterpret_cast<char*>(&buf[0]); // change from unsigned char to char 
//char p_buf[RCV_BUF_SIZE]; 

int ret = recv(m_socket, p_buf, RCV_BUF_SIZE, 0); // Does not work 

for (int i=0; i<RCV_BUF_SIZE; ++i) // Works (does not crash, so the buffer is ok) 
    char c = p_buf[i]; 

//... 

Теперь, когда я запускаю этот код RET становится -1 и WSAGetLastError() возвращает 10014, что означает указатель плохо.
Однако я не понимаю, почему это не должно работать? Если я закомментирую строку reinterpret_cast и использую строку ниже, она работает!
Можно утверждать, что reinterpret_cast является рискованным, но я думаю, что это должно быть хорошо, поскольку и unsigned char, и signed char имеют тот же самый размер.
std :: векторы должны быть безопасными для прямого доступа в память, насколько я знаю.

Забавно, что когда я делаю то же самое с тем же векторным типом в send(), он работает! Отправить функцию:

void SendData(const CharBuf& buf) 
{ 
    buf.resize(RCV_BUF_SIZE); // resize buffer to 1024 
    const char* p_buf = reinterpret_cast<const char*>(&buf[0]); // change from unsigned char to char 

    int ret = send(m_socket, p_buf, (int)buf.size(), 0); // Works 
} 

Как мы видим, никакой разницы, кроме CharBuf, являющейся константой в этом случае, может это что-то изменить?

Почему recv() более чувствителен, чем send()? Как может recv() даже знать, что указатель недействителен (что явно не так)? все, что должно увидеть, это массив символов!

По запросу вся моя функция приема (имейте в виду, что я не могу заклинание каждую функцию в нем, но я думаю, что они должны быть понятны сами по себе.

bool TcpSocket::ReceiveData(CharBuf* pData) 
{ 
    if (!CheckInitialized("ReceiveData")) 
     return false; 


    if (m_status != CONNECTED_STAT) 
    { 
     AddToErrLog("Socket not connected", 1, "ReceiveData"); 
     return false; 
    } 

    int ret; 
    pData->resize(RCV_BUF_SIZE); 
    char* p_buf = reinterpret_cast<char*>(&pData[0]); 

    ret = recv(m_socket, p_buf, RCV_BUF_SIZE, 0); 

    switch (ret) 
    { 
    case 0: // Gracefully closed 
     AddToLog("Connection gracefully closed", 2); 
     Shutdown(); // The connection is closed, no idea to keep running 

     return true; 

    case SOCKET_ERROR: // Error 
     ret = WSAGetLastError(); 
     if (ret == 10004) // This indicates the socket was closed while we were waiting 
      AddToLog("Socket was shut down while waiting for data", 1, "ReceiveData(1)"); 
     else 
      AddToErrLog("Receive data failed with code: " + CStr(ret)); 

     AddToLog("Connection ended with error", 2); 

     Shutdown(); 
     return false; 

    default: // Normal operation 
     pData->resize(ret); // Remove unused space 

     return true; 
    } 
} 

Ничего. Я нашел это, когда я вставлял функцию. Как всегда, вы обнаружите свою ошибку, когда пытаетесь объяснить ее кому-то еще :) Я оставляю ее читателю, чтобы выяснить, что не так, но я дам & pData [0 ] как подсказка. Спасибо за вашу помощь: D

+0

OS может сказать, что вы передаете ему плохой указатель и можете вернуть EFAULT вместо того, чтобы просто убить вашу программу. Укажите точный код, который вы используете, или минимальный тестовый пример. Что у вас в порядке. – Thanatos

+0

Отрывки выглядят ОК. Итак ... В фактическом коде, который вы компилируете, вы дважды проверили, что 'buf' на самом деле имеет выделенный буфер? Вы проверили, случайно ли вы вызываете 'buf.reserve()' вместо 'buf.resize()'? Вы проверили значение 'p_buf', чтобы убедиться, что оно выглядит разумным, прежде чем передать его на' recv'? – TheUndeadFish

+0

Если вы проверите всю функцию, я уверен, что вы обнаружите, где я сделал ошибку, указатели могут обмануть вас иногда :) – DaedalusAlpha

ответ

0

Нашел ответ сам, вставляя всю функцию, & pData [0] - это подсказка.

+0

Yup, это проблема. Для ссылки других людей параметр 'pData' является указателем CharBuf *, поэтому доступ к' pData [0] 'не вызывает' std :: vector :: operator [] 'правильно. Вам нужно сначала разыменовать указатель, например: 'char * p_buf = reinterpret_cast (& (* pData) [0]);' –

+0

Вы также можете использовать функцию at(), например: char * p_buf = reinterpret_cast (& (pData-> в (0))); что я и делал. – DaedalusAlpha

Смежные вопросы