2013-12-17 234 views
0

我目前正在使用通過WinSock使用套接字的項目,並遇到了一個奇怪的問題。在開始解釋之前,我會附上代碼。memcpy中的數據損壞

#include "Connection.h" 


Connection::Connection(SOCKET sock, int socketType) 
    : m_sock(sock), m_recvCount(0), m_sendCount(0), m_socketType(socketType) 
{ 
    printf("Succesfully created connection\n"); 
} 


Connection::~Connection(void) 
{ 
    printf("Closing socket %d", m_sock); 
    closesocket(m_sock); 
} 

void Connection::ProcessMessage(const NetMessage *message){ 
    printf("Got network message: type %d, data %s\n", message->type, message->data); 
} 


bool Connection::ReadSocket(){ 
    // Call this when the socket is ready to read. 
    // Returns true if the socket should be closed. 

    // used to store count between the sockets 
    int count = 0; 

    if(m_socketType == SOCK_STREAM){ 
     // attempt to read a TCP socket message 
     // Receive as much data from the client as will fit in the buffer. 
     count = recv(m_sock, &m_recvBuf[m_recvCount], sizeof(m_recvBuf) - m_recvCount, 0); 
    } 
    else if(m_socketType == SOCK_DGRAM){ 
     // attempt to read UDP socket message 

     // temporarily stores details of the address which sent the message 
     // since UDP doesn't worry about whether it's connected to the 
     // sender or not 

     sockaddr_in fromAddr; 
     int fromAddrSize = sizeof(fromAddr); 

     count = recvfrom(m_sock, &m_recvBuf[m_recvCount], sizeof(m_recvBuf) - m_recvCount, 0, (sockaddr*) &fromAddr, &fromAddrSize); 
    } 
    else{ 
     printf("Unknown socket type %d\n", m_socketType); 
     return true; 
    } 


    if (count <= 0) 
    { 
     printf("Tried to receive on socket %d and got %d bytes\n", m_sock, count); 
     printf("Client connection closed or broken\n"); 
     return true; 
    } 

    // if we get to this point we have essentially received a complete message 
    // and must process it 

    printf("Received %d bytes from the client (total %d)\n", count, m_recvCount); 
    m_recvCount += count; 

    // Have we received a complete message? 
    // if so, process it 
    if (m_recvCount == sizeof NetMessage) 
    { 
     ProcessMessage((const NetMessage *) m_recvBuf); 
     m_recvCount = 0; 
    } 

    return false; 
} 

bool Connection::WriteSocket(){ 
    // Sends the data in the send buffer through the socket 

    int count; 

    if(m_socketType == SOCK_STREAM){ 
     // attempt to read TCP socket message 
     count = send(m_sock, m_sendBuf, m_sendCount, 0); 
    } 
    else if(m_socketType == SOCK_DGRAM){ 
     // attempt to read UDP socket message 
     count = sendto(m_sock, m_sendBuf, m_sendCount, 0, 0, 0); 
    } 
    else{ 
     // unhandled type of socket, kill server 
     printf("Unknown socket type %d", m_socketType); 
     return true; 
    } 

    if (count <= 0) 
    { 
     // we have received an error from the socket 
     printf("Client connection closed or broken\n"); 
     return true; 
    } 

    m_sendCount -= count; 
    printf("Sent %d bytes to the client (%d left)\n", count, m_sendCount); 
    printf("Data: %s", m_sendBuf); 

    // Remove the sent data from the start of the buffer. 
    memmove(m_sendBuf, &m_sendBuf[count], m_sendCount); 

    return false; 
} 

bool Connection::WantWrite(){ 
    if(m_sendCount > 0){ 
     return true; 
    } 

    return false; 
} 

bool Connection::WantRead(){ 
    return true; 
} 

bool Connection::SetMessage(const NetMessage *message){ 
    // store contents of the message in the send buffer 
    // to allow us to send later 
    if (m_sendCount + sizeof(NetMessage) > sizeof(m_sendBuf)) 
    { 
     return true; 
    } 

    memcpy(&m_sendBuf, message, sizeof(message)); 
    m_sendCount += sizeof(NetMessage); 

    return false; 
} 

和協議

/* Definitions for the network protocol that the client and server use to communicate */ 

#ifndef PROTOCOL_H 
#define PROTOCOL_H 

// Message types. 
enum MessageType 
{ 
    MT_UNKNOWN = 0, 
    MT_WELCOME = 1, 
    MT_KEYPRESS = 2, 
    MT_CHATMESSAGE = 3 
}; 

// The message structure. 
// This is a "plain old data" type, so we can send it over the network. 
// (In a real program, we would want this structure to be packed.) 
struct NetMessage 
{ 
    MessageType type; 
    char* data; 

    NetMessage() 
     : type(MT_UNKNOWN) 
    { 
    } 
}; 

#endif 

本質上,協議認爲,客戶端和服務器扔圍繞彼此的消息的定義。我遇到的問題是,在connection.cpp行132(memcpy)中,消息在sendBuf中變成亂碼。

http://imgur.com/MekQfgm,9ShRtHi

上面的圖片顯示到底發生了什麼。正如在protocol.h中所說的那樣,struct是一個POD,所以當我執行memcpy時,它應該傳遞結構中保存的字節數(例如,消息類型應該是1個字節,接着是7或8個字節的數據,在這個例子中)。

任何人都可以對此有所瞭解嗎?這讓我瘋狂。

+3

您應該將代碼編輯到您的消息中。外部鏈接變壞。 –

+0

我只是認爲它是一個類,它會有點大,去標記到代碼。儘管如此,歡呼。 – Dillanm

回答

4

你寫將在32位系統中複製4個字節(的sizeof(指針))線:

memcpy(&m_sendBuf, message, sizeof(message)); 

你大概的意思是:

memcpy(&m_sendBuf, message, sizeof(NetMessage)); 

編輯:

另外,正如一位評論者所言,您的數據類型不是POD。它包含一個指針。您傳輸該指針。在目標系統中,它將指向RAM中的相同位置,但不會有任何內容。您需要通過使用數組實際使您的數據類型成爲POD,或者您需要找到一種方法來傳輸指向的數據。您可以通過傳輸類型,長度和多個字符來實現此目的。這意味着您的接收器不能依賴於固定大小的消息。

+0

感謝您的快速回答,不幸的是,添加仍然給出相同的問題,消息在緩衝區中出現亂碼。 – Dillanm

+0

@jogojapan,我會怎麼做? – Dillanm

+0

所以你說的是,如果我把它作爲char data [messageSize]而不是char *數據,它會起作用嗎? – Dillanm