Boost.Asio同步通讯

发布于 2024-08-02 01:31:25 字数 2311 浏览 2 评论 0原文

我在使用 asio 时遇到问题。 我的客户端/服务器应用程序仅需要同步通信。 因此,使用 boost 主页中的同步示例,我设置了两个程序来发送和接收数据。 他们的代码如下:

void vReceive(tcp::socket & socket, std::string & szDest){
    char szTmp_Buf [BUF_LEN + 1];
    szDest = "";
    std::cout << "Entering vReceive . . ." << std::endl;

    for (;;){
      char szBuf [BUF_LEN];
      boost::system::error_code error;
      uInt uiBytes_Recv = socket.read_some(boost::asio::buffer(szBuf), error);
      std::cout << " Read " << uiBytes_Recv << " bytes" << std::endl;
      if (error == boost::asio::error::eof)
         break; // Connection closed cleanly by peer.
      else if (error)
         throw boost::system::system_error(error); // Some other error.

      memcpy((void*) szTmp_Buf, (void*) szBuf, uiBytes_Recv );
      szTmp_Buf[ uiBytes_Recv ] = '\0';
      szDest += szTmp_Buf;
      };
      std::cout << "Received" << szDest << std::endl;
      std::cout << "Leaving vReceive . . ." << std::endl << std::endl;
   };

void vSend(tcp::socket & socket, std::string & szSrc){
    std::cout << "Entering vSend . . . " << std::endl;
    std::cout << "Sending " << szSrc << std::endl;
    boost::system::error_code ignored_error;
    boost::asio::write(socket, boost::asio::buffer(szSrc), boost::asio::transfer_all(), ignored_error);
    std::cout << "Leaving vSend . . . " << std::endl << std::endl;
    };

这些过程只是从 boost 示例中提取的代码行的包装。

在我的测试应用程序中,客户端调用

std::string szDate;
vReceive(socket, szDate);
vSend(socket, std::string("Chop Suey!") );
vReceive(socket, szDate);
vSend(socket, std::string("Halo"));

和服务器调用

std::string message = make_daytime_string();
std::string szReceived;
vSend(socket, message);
vReceive(socket, szReceived);
vSend(socket, message);
vReceive(socket, szReceived);

只是为了测试功能。 问题是两个应用程序在第一次信息交换后都会冻结,正如我在下面的图片。 客户端的 vReceive() 过程似乎没有完成,而 vSend() 在服务器端完成。 那么,有人知道可能出了什么问题吗?

以防万一有人想要复制该问题,我将完整的源代码上传到同一服务器,其中图片位于 asio_problem.rar 文件中(作为新成员,我可以为每个帖子添加一个超链接)。

谢谢大家, 丹尼尔.

I have a problem using asio. My client/server application requires only synchronous communication. So, using the examples for synchro from the boost homepage, I have set up two procedures to send and receive data. Their code is as follows:

void vReceive(tcp::socket & socket, std::string & szDest){
    char szTmp_Buf [BUF_LEN + 1];
    szDest = "";
    std::cout << "Entering vReceive . . ." << std::endl;

    for (;;){
      char szBuf [BUF_LEN];
      boost::system::error_code error;
      uInt uiBytes_Recv = socket.read_some(boost::asio::buffer(szBuf), error);
      std::cout << " Read " << uiBytes_Recv << " bytes" << std::endl;
      if (error == boost::asio::error::eof)
         break; // Connection closed cleanly by peer.
      else if (error)
         throw boost::system::system_error(error); // Some other error.

      memcpy((void*) szTmp_Buf, (void*) szBuf, uiBytes_Recv );
      szTmp_Buf[ uiBytes_Recv ] = '\0';
      szDest += szTmp_Buf;
      };
      std::cout << "Received" << szDest << std::endl;
      std::cout << "Leaving vReceive . . ." << std::endl << std::endl;
   };

void vSend(tcp::socket & socket, std::string & szSrc){
    std::cout << "Entering vSend . . . " << std::endl;
    std::cout << "Sending " << szSrc << std::endl;
    boost::system::error_code ignored_error;
    boost::asio::write(socket, boost::asio::buffer(szSrc), boost::asio::transfer_all(), ignored_error);
    std::cout << "Leaving vSend . . . " << std::endl << std::endl;
    };

These procedures are just wrappers for the lines of code extracted from the boost examples.

In my test applications, the client calls

std::string szDate;
vReceive(socket, szDate);
vSend(socket, std::string("Chop Suey!") );
vReceive(socket, szDate);
vSend(socket, std::string("Halo"));

and the server calls

std::string message = make_daytime_string();
std::string szReceived;
vSend(socket, message);
vReceive(socket, szReceived);
vSend(socket, message);
vReceive(socket, szReceived);

just to test the functionality. The problem is that both applications freeze after the first information exchange, as I have depicted on the following picture. It seems that vReceive() procedure on the client side doesn´t finish while vSend() finishes on the server side. So, does anybody have any idea, what might be wrong?

Just in case someone wanted to replicate the problem, I uploaded the sources complete sources to to same server, where the picture is in the asio_problem.rar file (I can have one hyperlink per post as a new member).

Thank you all in advance,
Daniel.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(1

原谅我要高飞 2024-08-09 01:31:25

我认为你的问题出在这里:

for (;;){
  /* snipped */

  if (error == boost::asio::error::eof)
     break; // Connection closed cleanly by peer.
  else if (error)
     throw boost::system::system_error(error); // Some other error.

  /* snipped */
}

你无限循环直到连接关闭(打破循环的唯一方法是如果你从套接字收到 EOF 错误),但 vSend 永远不会关闭套接字。 这意味着客户端中的 vReceive 将永远等待,始终期待更多数据。 将 socket.close() 放入 vSend 应该可以很好地实现这一目的。

当然,这意味着您的客户端和服务器在每次调用 vReceivevSend 后都需要重新打开套接字。 如果这不合需要,那么我建议发送方使用其他一些方法来通知接收方不再发送数据。

我不确定您对通过线路发送的数据是否有任何限制,但是可以在消息开头发送“数据长度”值,或者在消息末尾发送某种“数据结束”哨兵值会给你一个漂亮、清晰的指示,告诉你何时停止监听更多数据。

这种方法还有一个额外的好处,那就是让您有理由使用 ASIO 的 read_until (或类似)功能来处理等待数据结束的逻辑。

I think your problem lies here:

for (;;){
  /* snipped */

  if (error == boost::asio::error::eof)
     break; // Connection closed cleanly by peer.
  else if (error)
     throw boost::system::system_error(error); // Some other error.

  /* snipped */
}

You are looping infinitely until the connection closes (the only way to break out of the loop is if you receive an EOF error from the socket), but vSend never closes the socket. This means that vReceive in your client will be waiting forever, always expecting more data. Putting a socket.close() in vSend should do the trick nicely.

Of course, this means that your client and server will need to re-open the socket after each respective call to vReceive and vSend. If that's not desirable, then I recommend using some other means of the sender notifying the receiver that no more data will be sent.

I'm not sure if you have any constraints on the data being sent over the wire, but either sending a "data length" value at the beginning of your message or some sort of "end-of-data" sentinel value at the end would give you a nice, clean indicator of when to stop listening for more data.

This approach has the additional upside of giving you reason to use ASIO's read_until (or similar) functionality to handle the logic of waiting for the end of the data for you.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文