插座写入循环混合弦缓冲器
我使用这样的循环多次调用函数:
for ( int con=0; con < this->controller_info.size(); con++ ) {
try {
this->pi.home_axis( this->controller_info.at(con).addr );
}
catch( std::out_of_range &e ) { ... }
}
其中home_axis()
函数定义为:
long ServoInterface::home_axis( int addr ) {
std::stringstream cmd;
if ( addr > 0 ) cmd << addr << " ";
cmd << "FRF";
cmd << "\n";
int bytes=this->controller.Write( cmd.str() );
return NO_ERROR;
}
controller.write.write()
函数只是一个包装器标准写(2)
将字符串中的字符写入套接字文件描述符。
您可以看到,每次home_axis()
被称为其新鲜,std :: stringstream cmd
buffer。但是发生的事情是, for循环执行,即接收由home_axis编写的字节的主机正在接收一个字符串,
1 FRF2 FRF
但是如果我打印了写的字节,则它打印6,两次。因此,作者编写正确,6个字节两个不同的时间,但是主机显然是作为一个缓冲区接收的。
如果我再次执行该循环,则主机将(正确)接收,
1 FRF
然后
2 FRF
在它们进来时处理两个接收的缓冲区
。 ?
这里不涉及线程。
为了将其分开一点,如果我仅将其延迟1秒插入以进行循环,即usleep(1);
,则可以正常工作。另外,如果我调用home_axis()
手动函数,但同样快速的继承,而无需使用这样的循环,
this->pi.home_axis( this->controller_info.at(0).addr );
this->pi.home_axis( this->controller_info.at(1).addr );
则也可以使用。
因此,我想知道是否有可能进行编译器优化?
I call a function multiple times using a for loop like this:
for ( int con=0; con < this->controller_info.size(); con++ ) {
try {
this->pi.home_axis( this->controller_info.at(con).addr );
}
catch( std::out_of_range &e ) { ... }
}
where the home_axis()
function is defined as:
long ServoInterface::home_axis( int addr ) {
std::stringstream cmd;
if ( addr > 0 ) cmd << addr << " ";
cmd << "FRF";
cmd << "\n";
int bytes=this->controller.Write( cmd.str() );
return NO_ERROR;
}
and the controller.Write()
function is just a wrapper for the standard write(2)
which writes the characters in the string to a socket file descriptor.
You can see that each time home_axis()
is called it should have its own, fresh, std::stringstream cmd
buffer. But what is happening is that, for the first time the for loop executes, the host that is receiving the bytes written by home_axis, is receiving a single string, once:
1 FRF2 FRF
but if I print the bytes written then it prints 6, twice. So the writer is writing correctly, 6 bytes two different times, but the host is receiving it apparently as a single buffer.
If I execute that for loop again, then the host receives (properly),
1 FRF
and then
2 FRF
handling the two received buffers each as they come in.
How can the std::stringstream cmd
buffers be getting mixed like this?
There are no threads involved here.
In an effort to pick this apart a bit, if I insert just 1µsec of delay in that for loop, i.e. usleep(1);
then it works properly. Also, if I call the home_axis()
function manually, but equally rapid succession, without using a for loop like this,
this->pi.home_axis( this->controller_info.at(0).addr );
this->pi.home_axis( this->controller_info.at(1).addr );
then that also works.
So I'm wondering if it's possible there is a compiler optimization going on?
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(1)
这与编译器完全无关。
TCP是一个字节流。它没有消息边界的概念。写作和读物之间没有1:1的关系。您可以编写每个6个字节的2个消息,并且接收器一次可以一次接收所有12个字节,或1个字节,然后接收11个字节,然后在两者之间接收11个字节。这就是TCP的工作方式。默认情况下,它可以分解数据包,因为它认为适合优化传输。
重要的是,TCP保证将交付字节(除非丢失连接),并且它将以与书写相同的顺序传递字节。
因此,发件人必须在每个消息开始和结束的数据本身中指示。通过在其内容之前发送消息的长度,或者将每个消息与唯一的定界符分开(如您所在)。
在接收方中,单个读取可能会收到部分消息或多个消息等。完成它们。
当您使用尾随
\ n
划定消息时,接收器应缓冲所有字节,并仅提取已收到其\ n
的消息,在末尾留下任何不完整的消息缓冲区的后续读取要完成。这样,保留并正确处理消息边界。
This has nothing to do with the compiler at all.
TCP is a byte stream. It has no concept of message boundaries. There is no 1:1 relationship between writes and reads. You can write 2 messages of 6 bytes each, and the receiver may receive all 12 bytes at a time, or 1 byte and then 11 bytes, or any combination in between. That is just the way TCP works. By default, it breaks up data packets as it sees fit to optimize transmissions.
What is important is that TCP guarantees the bytes will be delivered (unless the connection is lost), and it will deliver the bytes in the same order that they are written.
As such, the sender must indicate in the data itself where each message begins and ends. Either by sending a message's length before its content, or by separating each message with a unique delimiter (as you are).
On the receiving side, a single read may receive a partial message, or pieces of multiple messages, etc. It is the receiver's responsibility to buffer incoming bytes and extract only complete messages from that buffer as needed, regardless of however many reads it takes to complete them.
As you are delimiting your messages with a trailing
\n
, the receiver should buffer all bytes and extract only messages that have received their\n
, leaving any incomplete message at the end of the buffer for subsequent reads to finish.This way, message boundaries are preserved and handled correctly.