Wil*_*mKF 2 c++ porting cygwin tcp endianness
我正在尝试调试从Cygwin发送时我的TCP传输被破坏的原因.我看到在Centos上运行的服务器程序中只显示每个结构的前24个字节.第25到第28个字节被加扰,之后的所有其他字节都被清零.走向另一个方向,从Cygwin上的Centos接收,再次只有每个块的前24个字节出现在我在Cygwin上运行的服务器程序中.第25到第40个字节被加扰,之后的所有其他字节都被清零.在Cygwin上发送或接收localhost时,我也看到了这个问题.对于localhost,前34个字节是正确的,之后全部归零.
我正在努力的应用程序在Centos4上与Centos交谈时正常工作,我正在尝试将其移植到Cygwin.Valgrind报告没有关于Centos的问题,我没有在Cygwin上运行Valgrind.这两个平台都是小端x86.
我在运行Cygwin的主机Windows XP系统上运行Wireshark.当我用Wireshark嗅探数据包时,它们看起来很完美,因为从Cygwin发送数据包并收到数据包给Cygwin.
不知何故,数据在Wireshark查看的级别与程序本身之间被破坏.
C++代码使用::write(fd, buffer, size)和::read(fd, buffer, size)写入和读取TCP数据包,其中fd是客户端和服务器之间打开的套接字的文件描述符.此代码在Centos4与Centos交谈时完美运行.
最奇怪的事情对我来说是,数据包嗅探器显示所有的情况下正确完整的数据包,但在cygwin应用程序从不读取完整的数据包或在其他方向,CentOS的应用程序从不读取完整的数据包.
任何人都可以建议我如何调试这个?
这是一些请求的代码:
size_t
read_buf(int fd, char *buf, size_t count, bool &eof, bool immediate)
{
if (count > SSIZE_MAX) {
throw;
}
size_t want = count;
size_t got = 0;
fd_set readFdSet;
int fdMaxPlus1 = fd + 1;
FD_ZERO(&readFdSet);
FD_SET(fd, &readFdSet);
while (got < want) {
errno = 0;
struct timeval timeVal;
const int timeoutSeconds = 60;
timeVal.tv_usec = 0;
timeVal.tv_sec = immediate ? 0 : timeoutSeconds;
int selectReturn = ::select(fdMaxPlus1, &readFdSet, NULL, NULL, &timeVal);
if (selectReturn < 0) {
throw;
}
if (selectReturn == 0 || !FD_ISSET(fd, &readFdSet)) {
throw;
}
errno = 0;
// Read buffer of length count.
ssize_t result = ::read(fd, buf, want - got);
if (result < 0) {
throw;
} else {
if (result != 0) {
// Not an error, increment the byte counter 'got' & the read pointer,
// buf.
got += result;
buf += result;
} else { // EOF because zero result from read.
eof = true;
break;
}
}
}
return got;
}
Run Code Online (Sandbox Code Playgroud)
我发现了更多关于这种失败的信息.正在读取数据包的C++类的布局如下:
unsigned char _array[28];
long long _sequence;
unsigned char _type;
unsigned char _num;
short _size;
Run Code Online (Sandbox Code Playgroud)
显然,漫长的时间会被随后的四个字节所扰乱.
Centos应用程序发送的C++内存,以_sequence开头,以十六进制表示,看起来像是write():
_sequence: 45 44 35 44 33 34 43 45
_type: 05
_num: 33
_size: 02 71
Run Code Online (Sandbox Code Playgroud)
Wireshark在数据包中显示网络大端格式的内存:
_sequence: 45 43 34 33 44 35 44 45
_type: 05
_num: 33
_size: 71 02
Run Code Online (Sandbox Code Playgroud)
但是,在C++ cygwin little-endian应用程序中的read()之后,它看起来像这样:
_sequence: 02 71 33 05 45 44 35 44
_type: 00
_num: 00
_size: 00 00
Run Code Online (Sandbox Code Playgroud)
我很难过这是怎么回事.这似乎是big-endian和little-endian的问题,但这两个平台都是小端的.
这里_array是7个整数而不是28个字符.
发件人完成内存转储:
_array[0]: 70 a2 b7 cf
_array[1]: 9b 89 41 2c
_array[2]: aa e9 15 76
_array[3]: 9e 09 b6 e2
_array[4]: 85 49 08 81
_array[5]: bd d7 9b 1e
_array[6]: f2 52 df db
_sequence: 41 41 31 35 32 43 38 45
_type: 05
_num: 45
_size: 02 71
Run Code Online (Sandbox Code Playgroud)
并在收到时:
_array[0]: 70 a2 b7 cf
_array[1]: 9b 89 41 2c
_array[2]: aa e9 15 76
_array[3]: 9e 09 b6 e2
_array[4]: 85 49 08 81
_array[5]: bd d7 9b 1e
_array[6]: f2 52 df db
_sequence: 02 71 45 05 41 41 31 35
_type: 0
_num: 0
_size: 0
Run Code Online (Sandbox Code Playgroud)
Cygwin测试结果:
4
8
48
0x22be08
0x22be28
0x22be31
0x22be32
0x22be38
Run Code Online (Sandbox Code Playgroud)
Centos测试结果:
4
8
40
0xbfffe010
0xbfffe02c
0xbfffe035
0xbfffe036
0xbfffe038
Run Code Online (Sandbox Code Playgroud)
现在您已经显示了数据,您的问题很明显.您没有控制结构的对齐,因此编译器会自动将8字节字段(long long)放在结构起始的8字节边界(偏移32)上,留下4个字节的填充.
将对齐更改为1个字节,一切都应该解决.这是您需要的代码段:
__attribute__ ((aligned (1))) __attribute ((packed))
Run Code Online (Sandbox Code Playgroud)
我也建议你使用被位块传输在网络上固定大小的类型结构,例如uint8_t,uint32_t,uint64_t
以前的想法:
使用TCP,您不需要read和write 数据包.您可以从字节流中读取和写入.数据包用于承载这些字节,但不保留边界.
您的代码看起来很合理,您可能想要更新问题的措辞.
| 归档时间: |
|
| 查看次数: |
508 次 |
| 最近记录: |