内存中的数据损坏

Corruption of data in memcpy

本文关键字:损坏 数据 内存      更新时间:2023-10-16

我目前正在通过WinSock使用套接字进行一个项目,并遇到了一个特殊的问题。在开始解释之前,我将附加代码。

#include "Connection.h"

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

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 %sn", 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 %dn", m_socketType);
        return true;
    }

    if (count <= 0)
    {
        printf("Tried to receive on socket %d and got %d bytesn", m_sock, count);
        printf("Client connection closed or brokenn");
        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 brokenn");
        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

从本质上讲,协议包含客户端和服务器相互抛出的消息的定义。我遇到的问题是,在 132 行(memcpy).cpp消息在 sendBuf 中变得乱码。

https://i.stack.imgur.com/i0obh.png

上图准确地显示了正在发生的事情。如protocol.h中所述,结构是一个POD,因此当我执行memcpy时,它应该传输结构中保存的字节数(因此,例如消息类型应为1字节,后跟7或8字节的数据,在示例中)。

谁能对此有所了解?这让我发疯。

您编写的行将在 32 位系统上复制 4 个字节(sizeof(指针)):

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

您可能的意思是:

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

编辑:

此外,正如评论者所说,您的数据类型不是 POD。它包含一个指针。你转移那个指针。在目标系统上,它将指向RAM中的同一位置,但那里不会有任何内容。您需要使用数组实际使您的数据类型成为 POD,或者您需要找到一种方法来传输指向的数据。您可以通过传输类型、长度和字符数量来实现这一点。这意味着您的接收方不能依赖固定大小的消息。