【问题标题】:Network app works in simulator, but not on the iPhone网络应用可以在模拟器上运行,但不能在 iPhone 上运行
【发布时间】:2013-12-01 01:13:20
【问题描述】:

我目前正在为 iPhone 编写一个游戏,它通过 TCP/IP 与 C++ 服务器通信,以交换用户数据、好友列表、声音文件等。服务端和客户端在socket上读/写时使用相同的结构体:

//Packet used for small stuff
typedef struct small_packet {
    int msgtype:8;
    int size:16;
    int extra:16;
    int following:24;
    char data1[64];
    char data2[64];
} packet;

//Packet used for files
typedef struct file_packet {
    int msgtype:8; //For partial file packet this should be 0x02
    int size:16;
    int extra:16;
    int following:24;
    char data1[64];
    char fileBuffer[1024];
} filePacket;

//Used for file headers
typedef struct filehead_packet {
    int msgtype:8;
    int size:16;
    int extra:16;
    int following:24;
    char data1[64];
    int fileid;
    char rest[60];
} fileheadPacket;

在模拟器模式下,应用程序可以完美运行并通过互联网与服务器通信。然而,当在 iPhone 上运行时,它就不能正常工作了。登录数据包使用小数据包(上部结构)。 msgtype 为 0x01,大小为 sizeof(packet),following 为 0,extra 为 0,data1 保存用户名,data2 保存计算得到的密码哈希值。服务器似乎获得了 0x01,因为它将传入消息视为登录请求。它也得到大小。从data1和data2复制用户名和密码哈希时出现问题。

在服务器上进行计算时,似乎服务器未读取用户名的前三个字母。当我尝试使用“用户名”登录时,服务器获取“rname”,并且 PWHash 具有类似的偏移量(3*sizeof(char))。这只发生在我在实际单元上运行应用程序时,而不是在模拟器中。

我承认我最近修改了结构的布局——到目前为止,额外字段只有 8 位,并且在后续字段之后我还有一个额外的 int:8 字段。我已经在客户端和服务器上使用此信息更新了结构,并在两者上运行了 clean+rebuild,所以我不明白它为什么重要。事实上,8+8=16,这是额外字段的新大小,因此 data1 和 data2 字段应该在内存中的相同偏移处开始,就像它们过去使用旧结构一样。

对此的任何帮助将不胜感激!我非常坚持这一点,完全不知道出了什么问题真的很烦人......这可能是我所知道的字节顺序(iPhone是字节性,不是吗?),但如果是这样的话,我不知道怎么做服务器将 0x01 解释为 0x01 ......哦,好吧。提前致谢!

【问题讨论】:

  • 据我所知,服务器是一个实际的远程服务器,对吧?因为如果是localhost,你需要使用本地主机的IP,而不是在你的应用中使用localhost
  • 只是一个想法:会不会是 utf8 的问题?我的意思是你的用户名实际上是“用户名”还是用挪威语写的?
  • 服务器是远程的,我将完整的 ipv4 地址硬编码到我的应用程序中。 @gWiz:我的用户名仅由英文字母表中的纯字母组成。事实上,客户端只接受 [a...z] 中的用户名。
  • 我建议为所有结构记录 sizeof - 包装可能是不同的 mac/ios。如果是这样,clang 可能有一些指令可以像 mac 一样打包结构。此外,使用宏将所有数字转换为网络顺序也是一种很好的做法(请参阅 ntoh 宏)。
  • 谢谢@DavidH!我今晚回去工作时会试试这个。在这种情况下,我跳过了 htons/ntohs,因为两台机器都以网络字节序工作,但我同意使用它们是一种好习惯,我稍后会将它添加到我的程序中。不同的包装是我没有想到的——谢谢,我回去工作时看看是不是这样:)

标签: c++ ios iphone objective-c tcp


【解决方案1】:

我建议为所有结构记录一个 sizeof - 包装可能是不同的 mac/ios。如果是这样,clang 可能有一些指令可以像 mac 一样打包结构。此外,最好使用宏将所有数字转换为网络顺序(请参阅 ntoh 宏)。

还有一个问题是您对位域的使用是高度不可移植的,理论上可能会随着编译器更新而改变。我建议对发送器和接收器使用一组不同的“传输”结构,在其中使用 uint64_t 值作为标志:

typedef struct small_packet {
    uint64_t flags;
    char data1[64];
    char data2[64];
} packet;

您可以编写非常简单的 C 代码来将您的“真实”结构映射到用于传输的结构。 K&R C 警告不要跨平台使用位域(我只是查了一下 :-))。

【讨论】:

  • 但这需要我重写我的网络通信模块的主要部分。哦,好吧,还是谢谢你:)
  • 作为一个临时修复,看看问题是否真的是位域,我删除了结构中所有字段的长度标志,包括服务器端和客户端。这使得所有的整数都是 32 位长,这显然会导致一些不必要的 '\0' 位流量,但是现在服务器与客户端通信良好,并且“用户名”实际上被读取为“用户名”。谢谢@DavidH 为我指明了正确的方向:)
猜你喜欢
  • 2017-01-03
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2021-07-27
  • 1970-01-01
  • 2014-09-03
相关资源
最近更新 更多