前面创建的UDP服务器和客户端,都是同步的方式,也就是说当接收数据时,不能参与别的事情执行的。如果在一个只有界面线程的程序里,又不想创建多线程,导致复杂程度的增加,在这种情况之下,我们还有一个方案可以选择,就是创建一个异步的UDP服务器或客户端,这样既有单线程的简单性,也可以让客户随便操作界面的快速响应的特性。在boost库里使用io_service对象来实现异步是轻而易举的事情,因为封装的接口简单、明了。具体的代码如下:
// boost_028.cpp : Defines the entry point for the console application. // #include "stdafx.h" #include <ctime> #include <boost/asio/ip/tcp.hpp> #include <boost/asio.hpp> #include <boost/bind.hpp> #include <boost/enable_shared_from_this.hpp> #include <boost/shared_ptr.hpp> #include <boost/array.hpp> #include <iostream> #include <string> //使用UDP命名空间 using boost::asio::ip::udp; //把当前时间转换为字符串。 std::string make_daytime_string() { using namespace std; //为了使用time_t, time 和 ctime; time_t now = time(0); return ctime(&now); } // //创建一个异步UDP的时间服务器。 //软件开发人员: 蔡军生 2013-08-25 //QQ: 9073204 // class UdpTimeServer { public: //传入IO服务,然后创建一个UDP的SOCKET,IPV4版本,端号为13 UdpTimeServer(boost::asio::io_service& ioService) :m_sockUdp(ioService, udp::endpoint(udp::v4(), 13)) { //进入接收服务中。 RecvTime(); } private: //接收收客户端的请求。 void RecvTime(void) { //异步接收数据 m_sockUdp.async_receive_from( boost::asio::buffer(m_recvBuf), m_endpointRemote, boost::bind(&UdpTimeServer::handleRecvTime, this, boost::asio::placeholders::error, boost::asio::placeholders::bytes_transferred)); } //当收到客户端数据时,就进入本函数响应处理 void handleRecvTime(const boost::system::error_code& error, std::size_t /*bytes_transferred*/) { //如果没有出错,就把时间字符串发送给客户端。 if (!error || error == boost::asio::error::message_size) { boost::shared_ptr<std::string> strMessage( new std::string(make_daytime_string())); m_sockUdp.async_send_to(boost::asio::buffer(*strMessage), m_endpointRemote, boost::bind(&UdpTimeServer::handleSendTime, this, strMessage, boost::asio::placeholders::error, boost::asio::placeholders::bytes_transferred)); //接收下一次的信息。 RecvTime(); } } //当发送时间字符串给客户端成功之后响应。 void handleSendTime(boost::shared_ptr<std::string> /*strMessage*/, const boost::system::error_code& /*error*/, std::size_t /*bytes_transferred*/) { } private: udp::socket m_sockUdp; //服务器的SOCKET。 udp::endpoint m_endpointRemote; //收到数据时的端点信息。 boost::array<char, 1> m_recvBuf; //接收数据缓冲区。 }; void TestUdp(void) { boost::asio::io_service ioService; UdpTimeServer udpTimeServer(ioService); ioService.run(); } int _tmain(int argc, _TCHAR* argv[]) { // TestUdp(); return 0; }
在这个例子里,主要封装了一个服务器UdpTimeServer,它是采用io_service对象和socket对象的异步特性来构造,有事件响应之后才去执行相应的操作,不过这样比前面的同步方式,还是复杂了一些,但带来了避免多线程之间的同步问题。