以太网传输时字节顺序的变化
change in endianness while ethernet transmission
我使用 zedboard 和 vivado v2017.3。我正在尝试发送存储在以下程序中由 baseaddr_p 指向的寄存器(slv_reg0 in Zynq 的 PL 部分)中的数据。
我使用 lwip echo 服务器应用程序读取这个地址并通过以太网将其发送到 PC。
这部分代码在回显请求(telnet)是时执行received.In这部分代码我还在 gtkterm 中打印读取的值,以便我可以验证接收到的数据。
void process_echo_request(void *p)
{
int sd = (int)p;
int RECV_BUF_SIZE = 2048;
char recv_buf[RECV_BUF_SIZE];
int n,i,nwrote;
unsigned long my_buffer[10];
i=0;
init_platform();
while(1){
while(i<11)
{
Xuint32 *baseaddr_p = (Xuint32 *)XPAR_MYIP_0_S00_AXI_BASEADDR;
my_buffer[i] = *(baseaddr_p);
xil_printf("0x%08x \n\r", my_buffer[i]);
i++;}
//xil_printf("0x%08x \n\r", my_buffer);
/* handle request */
if ((nwrote = write(sd, my_buffer, sizeof (my_buffer))) < 0) {
xil_printf("%s: ERROR responding to client echo request. received = %d, written = %d\r\n",
__FUNCTION__, n, nwrote);
xil_printf("Closing socket %d\r\n", sd);
break;
}
while (1) {
/* read a max of RECV_BUF_SIZE bytes from socket */
if ((n = read(sd, recv_buf, RECV_BUF_SIZE)) < 0) {
xil_printf("%s: error reading from socket %d, closing socket\r\n", __FUNCTION__, sd);
break;
}
/* break if the recved message = "quit" */
if (!strncmp(recv_buf, "quit", 4))
break;
/* break if client closed connection */
if (n <= 0)
break;
}
}
/* close connection */
close(sd);
vTaskDelete(NULL);
cleanup_platform();
}
gtkterm 结果:读取值
0x00000004
0x00000005
0x00000006
0x00000007
0x00000008
0x00000009
0x0000000A
0x0000000B
0x0000000C
0x0000000D
0x0000000E
在接收这些数据时,似乎发生了字节反转。
收到的数据:
04 00 00 00 05 00 00 00 06 00 00 00 07 00 00 00 08 00 00 00 09 00 00 00 0A 00 00 00 0B 00 00 00 0C 00 00 00 0D 00 00 00
关于它发生的原因和可能的解决方法有什么建议吗?
问题是由于 endianess。当您发送和接收数据时,最好进行主机到网络的转换,反之亦然。
有两个 POSIX API 可以进行这些字节顺序转换:htonl and ntohl
在接收方尝试进行网络到主机的字节顺序转换,如果您有权访问发送方,则在此处执行相反的操作。
您的源计算机对整数使用小端内部表示。它的 xil_printf()
函数解释了这一点,以规范的方式格式化数字以供人类使用。字节交换存在,而且是良性的。
另一方面,write()
不知道也不关心你交给它的数据的重要性。它将所有内容简单地视为一个字节序列,并按照它们出现的顺序进行传输。类似地,read()
函数按照字节通过网络传输的顺序接收和存储字节。那里没有字节交换发生。
如果你可以依靠接收数据的机器根据相同的数字格式(大小、字节顺序等)来解释它,那么就没有问题。如果不是,则您需要将数据放入标准格式以通过网络传输,或者发送一些源机器格式的指示符,接收方应适当处理。
前一种方法更为常见。这其实就是POSIX定义的the htonl()
and ntohl()
functions的作用。如果您没有这些,您自己实现起来也不会太难——最大的技巧(并不是 大)是确定本机字节顺序。
我使用 zedboard 和 vivado v2017.3。我正在尝试发送存储在以下程序中由 baseaddr_p 指向的寄存器(slv_reg0 in Zynq 的 PL 部分)中的数据。
我使用 lwip echo 服务器应用程序读取这个地址并通过以太网将其发送到 PC。
这部分代码在回显请求(telnet)是时执行received.In这部分代码我还在 gtkterm 中打印读取的值,以便我可以验证接收到的数据。
void process_echo_request(void *p)
{
int sd = (int)p;
int RECV_BUF_SIZE = 2048;
char recv_buf[RECV_BUF_SIZE];
int n,i,nwrote;
unsigned long my_buffer[10];
i=0;
init_platform();
while(1){
while(i<11)
{
Xuint32 *baseaddr_p = (Xuint32 *)XPAR_MYIP_0_S00_AXI_BASEADDR;
my_buffer[i] = *(baseaddr_p);
xil_printf("0x%08x \n\r", my_buffer[i]);
i++;}
//xil_printf("0x%08x \n\r", my_buffer);
/* handle request */
if ((nwrote = write(sd, my_buffer, sizeof (my_buffer))) < 0) {
xil_printf("%s: ERROR responding to client echo request. received = %d, written = %d\r\n",
__FUNCTION__, n, nwrote);
xil_printf("Closing socket %d\r\n", sd);
break;
}
while (1) {
/* read a max of RECV_BUF_SIZE bytes from socket */
if ((n = read(sd, recv_buf, RECV_BUF_SIZE)) < 0) {
xil_printf("%s: error reading from socket %d, closing socket\r\n", __FUNCTION__, sd);
break;
}
/* break if the recved message = "quit" */
if (!strncmp(recv_buf, "quit", 4))
break;
/* break if client closed connection */
if (n <= 0)
break;
}
}
/* close connection */
close(sd);
vTaskDelete(NULL);
cleanup_platform();
}
gtkterm 结果:读取值 0x00000004 0x00000005 0x00000006 0x00000007 0x00000008 0x00000009 0x0000000A 0x0000000B 0x0000000C 0x0000000D 0x0000000E
在接收这些数据时,似乎发生了字节反转。
收到的数据: 04 00 00 00 05 00 00 00 06 00 00 00 07 00 00 00 08 00 00 00 09 00 00 00 0A 00 00 00 0B 00 00 00 0C 00 00 00 0D 00 00 00
关于它发生的原因和可能的解决方法有什么建议吗?
问题是由于 endianess。当您发送和接收数据时,最好进行主机到网络的转换,反之亦然。
有两个 POSIX API 可以进行这些字节顺序转换:htonl and ntohl
在接收方尝试进行网络到主机的字节顺序转换,如果您有权访问发送方,则在此处执行相反的操作。
您的源计算机对整数使用小端内部表示。它的 xil_printf()
函数解释了这一点,以规范的方式格式化数字以供人类使用。字节交换存在,而且是良性的。
另一方面,write()
不知道也不关心你交给它的数据的重要性。它将所有内容简单地视为一个字节序列,并按照它们出现的顺序进行传输。类似地,read()
函数按照字节通过网络传输的顺序接收和存储字节。那里没有字节交换发生。
如果你可以依靠接收数据的机器根据相同的数字格式(大小、字节顺序等)来解释它,那么就没有问题。如果不是,则您需要将数据放入标准格式以通过网络传输,或者发送一些源机器格式的指示符,接收方应适当处理。
前一种方法更为常见。这其实就是POSIX定义的the htonl()
and ntohl()
functions的作用。如果您没有这些,您自己实现起来也不会太难——最大的技巧(并不是 大)是确定本机字节顺序。