C++ 为什么我的TCP传输在cygwin上损坏?

C++ 为什么我的TCP传输在cygwin上损坏?,c++,tcp,cygwin,porting,endianness,C++,Tcp,Cygwin,Porting,Endianness,我正在尝试调试为什么从Cygwin发送TCP传输时会损坏。我发现在Centos上运行的服务器程序中,每个结构只有前24个字节。第25到28个字节被置乱,之后的所有字节被置零。另一方面,从Cygwin上的Centos接收到消息,在Cygwin上运行的服务器程序中,同样只显示每个块的前24个字节。第25到40个字节被置乱,之后的所有字节被置零。我还看到在Cygwin上向localhost发送或从localhost接收数据时出现的问题。对于localhost,前34个字节是正确的,之后的所有字节都是零

我正在尝试调试为什么从Cygwin发送TCP传输时会损坏。我发现在Centos上运行的服务器程序中,每个结构只有前24个字节。第25到28个字节被置乱,之后的所有字节被置零。另一方面,从Cygwin上的Centos接收到消息,在Cygwin上运行的服务器程序中,同样只显示每个块的前24个字节。第25到40个字节被置乱,之后的所有字节被置零。我还看到在Cygwin上向localhost发送或从localhost接收数据时出现的问题。对于localhost,前34个字节是正确的,之后的所有字节都是零

我正在开发的应用程序在Centos 4上运行良好,正在与Centos对话,我正在尝试将其移植到Cygwin。Valgrind在Centos上没有报告任何问题,我没有在Cygwin上运行Valgrind。这两种平台都是little endian x86

我在运行Cygwin的Windows XP主机系统上运行了Wireshark。当我用Wireshark嗅探数据包时,无论是从Cygwin发送的数据包还是从Cygwin接收的数据包,它们看起来都非常完美

不知何故,Wireshark查看的级别和程序本身之间的数据被破坏

<> > C++代码使用::(FD,缓冲,大小)< /C> >代码> >:读取(FD,缓冲,大小)< /C> >写和读取TCP包,其中FD是在客户端和服务器之间打开的套接字的文件描述符。此代码在Centos 4上与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;
}
显然,long-long被后面的四个字节搅乱了

CeNOS应用程序发送的C++内存,以Hyx序列开始,在十六进制中,看起来像要写入():

Wireshark在数据包中以网络大端格式显示内存:

_sequence: 45 43 34 33 44 35 44 45
    _type: 05
     _num: 33
    _size: 71 02

但是,在C++ CygWin小EnDead应用程序中读入()之后,看起来是这样的:

unsigned char _array[28];
long long _sequence;
unsigned char _type;
unsigned char _num;
short _size;
_sequence: 02 71 33 05 45 44 35 44
    _type: 00
     _num: 00
    _size: 00 00
我不明白这是怎么发生的。这似乎是big-endian和little-endian的问题,但这两个平台都是little-endian


这里_数组是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
收到时:

_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

Cygwin试验结果:

4
8
48
0x22be08
0x22be28
0x22be31
0x22be32
0x22be38
4
8
40
0xbfffe010
0xbfffe02c
0xbfffe035
0xbfffe036
0xbfffe038
Centos测试结果:

4
8
48
0x22be08
0x22be28
0x22be31
0x22be32
0x22be38
4
8
40
0xbfffe010
0xbfffe02c
0xbfffe035
0xbfffe036
0xbfffe038

希望最终更新:-)

根据您的最新更新,Centos正在字节级别打包您的结构,而CygWin则没有。这会导致对齐问题。我不确定为什么CygWin到CygWin的情况出现问题,因为填充应该是相同的,但我可以告诉您如何修复另一个情况

使用我前面给出的代码:

#include <stdio.h>
typedef struct {
    unsigned char _array[28];
    long long _sequence;
    unsigned char _type;
    unsigned char _num;
    short _size;
} tType;
int main (void) {
    tType t[2];
    printf ("%d\n", sizeof(long));
    printf ("%d\n", sizeof(long long));
    printf ("%d\n", sizeof(tType));
    printf ("%p\n", &(t[0]._array));
    printf ("%p\n", &(t[0]._sequence));
    printf ("%p\n", &(t[0]._num));
    printf ("%p\n", &(t[0]._size));
    printf ("%p\n", &(t[1]));
    return 0;
}
这给了你:

4
8
40
0x22cd42
0x22cd38
0x22cd5f
0x22cd40
0x22cd60
4
8
40
0x22cd3c
0x22cd58
0x22cd61
0x22cd62
0x22cd64
换句话说,每个结构正好是40个字节(8个表示序列,2个表示大小,28个表示数组,1个表示类型和num)。但是,如果您希望按照特定的顺序进行,这可能是不可能的

在这种情况下,您可以使用以下命令强制对齐到字节级别:

typedef struct {
    unsigned char _array[28];
    long long _sequence;
    unsigned char _type;
    unsigned char _num;
    short _size;
} __attribute__ ((aligned(1),packed)) tType;
aligned(1)
将其设置为字节对齐,但这不会产生太大影响,因为对象不喜欢减少对齐。要强制执行此操作,还需要使用
packed

这样做会让你:

4
8
40
0x22cd42
0x22cd38
0x22cd5f
0x22cd40
0x22cd60
4
8
40
0x22cd3c
0x22cd58
0x22cd61
0x22cd62
0x22cd64

早期繁荣史:

好吧,由于我从CygWin那里得到了
wget
ftp
大文件,我的心理调试技能告诉我,这更可能是你的代码而不是CygWin软件的问题

换句话说,关于“数据包在Wireshark查看的级别和程序本身之间被破坏”这句话,我会认真地关注该级别的上限,而不是下限:-)

通常情况下,您假设
读取
将获得发送的整个数据包,而不是一次发送的位,但是,在没有看到所讨论的代码的情况下,这是一个相当疯狂的猜测

确保您正在检查
read
的返回值,以查看实际接收的字节数。除此之外,发布负责
读取的代码
,以便我们可以进行更深入的分析


根据你发布的代码,看起来没问题。我唯一能建议的是,检查传入的缓冲区是否足够大,即使足够大,也要确保在返回后立即打印,以防其他代码损坏数据

事实上,在仔细阅读你的问题时,我有点困惑。你说你在Linux和CygWin上的服务器代码都有同样的问题,但说它在Centos上工作

在这一点上,我唯一的建议是将调试
printf
语句放在您显示的函数中,例如在
select
read
调用之后,输出相关变量,包括更改后的
got
buf
,以及每个代码路径中,以便您可以看到它在做什么。并在发送端逐字节转储整个结构

这将有希望立即向您显示问题所在,特别是因为您的数据似乎显示在错误的位置

并确保您的类型在两端都兼容。我的意思是,如果两个平台上的
long
大小不同,您的数据将不对齐


好的,检查两端的对齐,在两个系统上编译并运行这个程序:

#include <stdio.h>
typedef struct {
    unsigned char _array[28];
    long long _sequence;
    unsigned char _type;
    unsigned char _num;
    short _size;
} tType;
int main (void) {
    tType t[2];
    printf ("%d\n", sizeof(long));
    printf ("%d\n", sizeof(long long));
    printf ("%d\n", sizeof(tType));
    printf ("%p\n", &(t[0]._array));
    printf ("%p\n", &(t[0]._sequence));
    printf ("%p\n", &(t[0]._num));
    printf ("%p\n", &(t[0]._size));
    printf ("%p\n", &(t[1]));
    return 0;
}
唯一奇怪的一点是填充在_类型之前,但这肯定是有效的,尽管出乎意料

检查Centos的输出是否不兼容。但是你说CygWin是CygWi