【问题标题】:SFML TCP packets being changedSFML TCP 数据包被更改
【发布时间】:2012-09-03 18:04:44
【问题描述】:

在 SFML 论坛中未能获得任何帮助后,我决定看看这里是否有人可以提供帮助。我有一个应用程序,它通过与服务器应用程序的 TCP 连接进行自我更新。这工作得很好,除了一个特定的数据包传输,其中数据包以某种方式改变。服务器发送一个包含数字 1 的数据包:

pack << sf::Uint8(1);
ClientSocket.Send(pack);

(其中pack 是sf::Packet 类型,ClientSocket 是sf::SocketTCP 类型)

使用我的调试器单步执行实际上确实确认了这些行已执行,并且我的客户端中的下一个 Receive 调用是接下来的几行:

sock.Receive(pack);
sf::Uint8 conf;
pack >> conf;

(其中pack 又是一个 sf::Packet,sock 是一个 SocketTCP)

但是,不知何故,在我的客户端中,conf 显示为具有零值(我的调试器确认了这一点)并且它确实如此(下一行根据值切换)。我在同一台机器上运行这两个应用程序,并且它们都将彼此读取为“127.0.0.1”,因此数据包(如果我理解正确的话)不会通过我的路由器,或者真的不会离开我的机器。关于为什么我的数据包被损坏的任何想法?

作为记录,如果有任何帮助,我正在使用 SFML 1.6 和我的应用程序在 Debian Squeeze Linux 机器上运行。

编辑:根据请求,这是我的应用程序中的更多代码。

首先,我的客户中与此更新程序特别相关的部分:

cout << "Connecting to update server." << endl;
sf::IpAddress server = sf::IpAddress::LocalHost;
sf::TcpSocket sock;
if (sock.connect(server, PORT, sf::seconds(20.0f)) != sf::Socket::Done)
    return false;

cout << "Connected. Searching for updates for updater." << endl;

sf::Packet pack;
std::string lastUpdate = getLastUpdate();

#ifdef __WXGTK__
pack << "uupdate" << lastUpdate << sf::Uint8(1);
#elif defined(__WXMSW__)
pack << "uupdate" << lastUpdate << sf::Uint8(2);
#elif defined(__WXOSX__)
pack << "uupdate" << lastUpdate << sf::Uint8(3);
#endif

sock.send(pack);

pack.clear();

sock.receive(pack); //THIS IS THE PART WHERE IT BREAKS
sf::Int32 conf;
pack >> conf;

if (conf == 1) { //There is an update!
    cout << "Update found!" << endl;

    pack << "begin" << sf::Uint32(512);
    sock.send(pack);

    pack.clear();

    sock.receive(pack);
    pack >> conf;

    if (conf == 0) { //No errors
        wxFileOutputStream* out = new wxFileOutputStream(wxString(UPDATER, StrConv).append(".temp"));

        char* data = new char[512];
        while (data != chara("done") && data != chara("error")) {
            sock.receive(pack);
            sf::Int32 size;
            pack >> size;
            data = const_cast<char*>((const char*)pack.getData());

            out->Write(data, size);
        }
        out->Close();
        if (data == chara("done"))
            wxCopyFile(wxString(UPDATER, StrConv).append(".temp"), wxString(UPDATER, StrConv));
        wxRemoveFile(wxString(UPDATER, StrConv).append(".temp"));
    }
}

cout << "Updater is up-to-date. Executing updater." << endl;

sock.disconnect();

bool success;
if (wxTheApp->argc == 1)
    success = wxExecute(wxT(UPDATER));
else
    success = wxExecute(wxString(UPDATER, StrConv).append(wxTheApp->argv[1]));

return success;

然后是与这些更新相关的服务器部分:

    //ClientSocket has already been initalised by way of a TcpListener
cout << "Checking for updater patches for client at " << ClientAddress.toString() << endl;

std::string lastUpdate;
pack >> lastUpdate;
sf::Uint8 os;
pack >> os;

//Check last time updater was changed
struct tm* clock;
struct stat attribs;
if (os == 1)
stat("Linux/Updater", &attribs);
else if (os == 2)
stat("Windows/Updater.exe", &attribs);
else if (os == 3)
stat("Mac/Updater", &attribs);
clock = gmtime(&(attribs.st_mtime));
time_t lastWrite = mktime(clock);

time_t clientUpdate = stringToNumber<time_t>(lastUpdate.c_str());

if (lastWrite > clientUpdate) {
    cout << "Found updater patches for client at " << ClientAddress.toString() << endl;

    pack << sf::Int32(1);
    ClientSocket->send(pack); //THIS IS THE PART WHERE IT BREAKS

    pack.clear();

    ClientSocket->receive(pack);
    std::string mes;
    pack >> mes;

    if (mes != "begin") {
        cerr << "Client at " << ClientAddress.toString() << " sent unrecognised message: " << mes << ". Ending conversation." << endl;
        ClientSocket->disconnect();
        return false;
    }

    sf::Uint32 size;
    pack >> size;

    cout << "Beginning to send updater patch to " << ClientAddress.toString() << endl;

    ifstream in;

    if (os == 1)
        in.open(chara("Linux/Updater"), ios_base::in | ios_base::binary);
    else if (os == 2)
        in.open(chara("Windows/Updater.exe"), ios_base::in | ios_base::binary);
    else if (os == 3)
        in.open(chara("Mac/Updater"), ios_base::in | ios_base::binary);

    if (in.fail()) {
        pack << sf::Uint8(1);
        ClientSocket->send(pack);
        cerr << "Failed to open updater at request of " << ClientAddress.toString() << ". Closing connection." << endl;
        ClientSocket->disconnect();
        return false;
    }

    pack << sf::Uint8(0);
    ClientSocket->send(pack);

    pack.clear();

    //Get length of file
    in.seekg(0, ios::end);
    int length = in.tellg();
    in.seekg(0, ios::end);

    char* buf = new char[size];

    for (unsigned int i = 0; i < length / size; i++) { //Read and send every `size`-sized block we can
        in.read(buf, size);
        pack << sf::Int32(size) << buf;
        ClientSocket->send(pack);
    }

    in.read(buf, length % size);
    pack << sf::Int32(length % size) << buf;
    ClientSocket->send(pack);

    pack.clear();

    pack << "done";
    ClientSocket->send(pack);

    pack.clear();
} else {
    pack << sf::Int8(0);
    ClientSocket->send(pack);
}

编辑:我知道这里有任何帖子已经快一个月了,但我仍然对此有疑问。我不知道如何解决这个问题。

【问题讨论】:

  • 您确定您正在阅读此数据包而不是上一个数据包的剩余部分吗?
  • 是的。我正在使用阻塞套接字,并且我保证服务器上的每个 Send 调用都与客户端上的一个 Receive 调用匹配(反之亦然)。我还看到我的客户端确实挂在上面显示的 Receive 调用上,直到服务器发出上面显示的 Send 调用。更不用说之前的数据包在任何地方都没有 0。
  • 尝试更改数据类型/值,看看是全部还是 uint8。
  • 也许我正在以某种方式从前一个数据包中读取值。我将其更改为 Uint16 并继续获得 0,但后来我将其更改为 Int32 而现在却获得了 7。我不明白为什么。在客户端做的最后一件事是发送一个数据包,而不是接收一个数据包,sf::SocketTCP::Send(sf::Packet) 应该清空数据包的所有数据,我相信......
  • 在刚刚挖掘了 SFML 源代码之后,情况似乎并非如此:Send(sf::Packet) 是否清除数据包。所以看起来我仍然在读取数据包中的旧数据,而不是刚刚发送的数据。我会尝试向sf::Packet::Clear() 添加一些调用,看看是否能解决问题。

标签: c++ tcp packet sfml corruption


【解决方案1】:

这不是一个真正的答案,但我无法对这个问题添加评论,所以......

SFML 1.6 没有得到维护,如果 SFML 本身存在问题,它可能已经在 2.0 版中得到解决。您可以下载RChere

【讨论】:

  • 我可以按照 Apprentice Queue 明天的要求发布更多代码,但现在我想发表评论说我已经更新到 2.0,但我仍然看到同样的问题。正如我所说,我明天会发布更多代码。
  • @Apprentice,我已经把源代码加进去了,希望能解决问题。
【解决方案2】:

所以,事实证明问题相当简单。你知道我是如何添加很多pack.clear() 行的吗?结果我忘了在接收原始数据和在服务器上发送原始数据之间添加一个。所以我的数据包仍然有第一次调用sock.receive(pack) 时留下的数据(这是上面发布的服务器代码开头的几行)。我花了这么长时间才看到。给pack.clear()打个电话,问题就解决了。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2012-03-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2012-08-18
    • 2015-01-17
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多