我在客户端有这段代码(从更大的代码块简化)
int key=0;
while (1) {
int n_read=read(fd, &key, 4);
printf("%d\n",key);
fflush(stdout);
if(key==1){
printf("in loop\n");
}
}
并将此代码在服务器端ATmega2560单片机上实现
while(1){
int key=1;
printf("%d", key);
}
服务器中的printf使用此代码
void usart_putchar(char data) {
// Wait for empty transmit buffer
while ( !(UCSR0A & (_BV(UDRE0))) );
// Start transmission
UDR0 = data;
}
// this function is called by printf as a stream handler
int usart_putchar_printf(char var, FILE *stream) {
// translate \n to \r for br@y++ terminal
if (var == '\n') usart_putchar('\r');
usart_putchar(var);
return 0;
}
我希望它打印“in loop”,但这从未发生过,当我在客户端打印循环中的键时,它的值为825307441,而不是1。
我想这可能是因为我从串行阅读它后,如何将字节一个接一个地放在整数变量中,或者我以不正确的方式使用读取函数,但我真的不知道
编辑:
在阅读了答案后,我像这样更改了服务器:
for(int j=0; j<4;j++){
while ( !(UCSR0A & (_BV(UDRE0))) );
UDR0=(key >> (8*j)) & 0xff;;
}
这给我带来了一些麻烦,我现在有这样的结果:
1
in loop
1
in loop
1
in loop
1
in loop
1
in loop
1
in loop
1
in loop
1
in loop
16777216
16777216
16777216
16777216
16777216
65536
65536
65536
65536
65536
256
256
256
1
in loop
1
in loop
1
in loop
1
in loop
1
in loop
1
这是endianness问题吗?有办法解决吗?
如果我不能解决这个问题,我将使用“忙碌者的建议”。
2条答案
按热度按时间pobjuy321#
你混合了文本和二进制的值表示。
服务器发送以字符表示的密钥,因为您使用
printf()
。实际上,由于值为1
,因此只发送一个字符:'1'
。客户端需要4个字节的二进制表示,因为您使用
read()
。让我们看看你收到了什么。从串行端口读取的4字节值为十进制825307441。快速抛出一个桌面计算器,并转换为十六进制显示,它是0x 31313131。
这4个字节是
'1'
的4个ASCII字符。如果你可以计算传输的次数,你会看到服务器需要通过它的循环运行4次,客户端才能收到1个密钥。如何解决?
你有两个选择,只使用二进制表示或只使用文本表示。
如果您想避免endianness问题,请选择文本表示。为此,将客户端代码更改为:
您需要用空格分隔数字,空格至少是空白,制表符或换行符之一。扩展服务器代码:
要使用二进制表示,您需要定义一个协议,指定传输的字节顺序、每个值的字节数以及分隔值的方式。这并不简单,通常过于广泛,无法在这里深入展示,并取决于您(我们不知道)的要求。
如果您选择只传输一个字节,这会给您一个0到255或-128到+127的值范围,您可以避免其他两个决定。每个值使用一个字节,就没有字节顺序(在字节级别上),并且由于每个字节都是一个完整的值,因此不需要额外的措施来分隔值。
以下是示例实现:
您在客户机中看到的输出来自
read()
的超时行为。串行传输需要时间,主要取决于波特率。显然,read()
返回的速度比传输单个字节所需的速度要快。由于您没有检查
read()
的返回值,因此即使没有收到字节,也可以继续使用key
中的任何内容。这就给出了你看到的多个输出。7cjasjjr2#
是的,您错误地使用了
read
。我不应该这么说,因为你可以这么做,但这与正在发送的数据不匹配。你根本没有发送int
。您正在发送组成int
的asspark字符。你这么想吧...如果我发送int
值44444
,那么我 * 应该 * 从read中得到的是'4'
的5个字符串。这实际上会使缓冲区溢出,因为int
的大小为4。通过printf
打印int
s是提供人类可读 * 文本 * 输出的方式。有两种方法可以做到这一点。你可以像现在这样做。当你读的时候,你需要发送一个字节缓冲区:
然后另一种方法是直接发送int的字节,如下所示:
然后,您需要在客户端解压缩这些字节。直接将它们阅读成整数可能会起作用,但前提是它们的大小相同,而我很确定它们的大小是 * 不 *。我建议使用大小为
int
的类型,如int16_t
或int32_t
,这样你就知道有多少字节会到达。