BOOST库介绍(三)——网络编程相关的库

Cain ·
更新时间:2024-11-10
· 652 次阅读

1. 同步和异步

网络编程分为同步模式和异步模式:
同步模式是有一个数据块客户端发送过来,服务端就必须处理完才能处理下一个数据块;
异步模式是客户端发送的数据块放入缓存队列;
异步处理不阻塞,同步模式是阻塞式的。

2. 编程实例 2.1 同步模式

同步模式介绍
大家好!我是同步方式!

我的主要特点就是执着!所有的操作都要完成或出错才会返回,不过偶的执着被大家称之为阻塞,实在是郁闷~~(场下一片嘘声),其实这样也是有好处的,比如逻辑清晰,编程比较容易。

在服务器端,我会做个socket交给acceptor对象,让它一直等客户端连进来,连上以后再通过这个socket与客户端通信, 而所有的通信都是以阻塞方式进行的,读完或写完才会返回。

在客户端也一样,这时我会拿着socket去连接服务器,当然也是连上或出错了才返回,最后也是以阻塞的方式和服务器通信。

有人认为同步方式没有异步方式高效,其实这是片面的理解。在单线程的情况下可能确实如此,我不能利用耗时的网络操作这段时间做别的事情,不是好的统筹方法。不过这个问题可以通过多线程来避免,比如在服务器端让其中一个线程负责等待客户端连接,连接进来后把socket交给另外的线程去和客户端通信,这样与一个客户端通信的同时也能接受其它客户端的连接,主线程也完全被解放了出来。

同步模式编程
服务器端

#include "stdafx.h" #include #include #include #include using namespace std; //流程: //① 创建io_service对象 //② 打包IP和端口 //③ 利用ios和ep创建连接器 //④ 利用io_service对象创建socket //⑤ 利用连接器连接 //⑥ 读写信息 int _tmain(int argc, _TCHAR* argv[]) { boost::asio::io_service ios;//asio网络编程必须io_service对象 boost::asio::ip::tcp::endpoint ep(boost::asio::ip::tcp::v4(),12248);//打包IP和端口 boost::asio::ip::tcp::acceptor ac(ios,ep);//利用ios和ep创建连接器 while (true)//监听客户端 { boost::asio::ip::tcp::socket sock(ios);//利用io_service对象创建socket ac.accept(sock);//连接客户端的socket //接收客户端消息,如果没有接收到,就一直卡在这里 cout << sock.remote_endpoint().address() << endl;//显示连接进来的客户端信息 boost::system::error_code ec; if (ec) { cout << boost::system::system_error(ec).what() << endl; break; } else { sock.write_some(boost::asio::buffer("hello world!"), ec); } } return 0; }

补充说明:
服务器端,做个socket交给acceptor对象,让它一直等客户端连进来,连上以后再通过这个socket与客户端通信。如果一直连不上,就卡在这里。

客户端

#include "stdafx.h" #include #include #include using namespace std; int _tmain(int argc, _TCHAR* argv[]) { try { boost::asio::io_service ios;//asio网络编程必须io_service对象 boost::asio::ip::tcp::endpoint ep(boost::asio::ip::address::from_string("127.0.0.1"),12248);//打包IP和端口 boost::asio::ip::tcp::socket sock(ios);//创建socket sock.connect(ep);//利用IP和端口连接服务器 while (true) { boost::array buf; boost::system::error_code ec; size_t len = sock.read_some(boost::asio::buffer(buf),ec); if (ec == boost::asio::error::eof) break; else if (ec) throw boost::system::system_error(ec); cout.write(buf.data(),len); } } catch (exception &e) { cout << e.what() << endl; } return 0; }

此外,在同步模式下,可以通过多线程来避免阻塞。在服务器端让其中一个线程负责等待客户端连接,连接进来后把socket交给另外的线程去和客户端通信,这样与一个客户端通信的同时也能接受其它客户端的连接,主线程也完全被解放了出来。示例如下:

//服务器端 boost::asio::io_service ios; //asio编程必须io_service对象,服务端和客户端创建socket和服务端创建acceptor对象要用 boost::asio::ip::tcp::endpoint ep(boost::asio::ip::tcp::v4(),9800); //TCP协议的服务器所在的IP和网络编程开放的端口,客户端连接的IP和端口 boost::asio::ip::tcp::acceptor acceptor(ios,ep); //监听连接 while(1) { boost::asio::ip::tcp::socket sock(ios);//创建socket连接对象 acceptor.accept(sock); cont<<sock.remote_endpoint().address()<<endl; boost::thread(boost::bind(svr_handle,sock)).detach(); } //交互处理 void svr_handle(boost::asio::ip::tcp::socket sock) { string msg; sock.write_some(boost::asio::buffer("hello world")); char msg[1024]; sock.read_some(boost::asio::buffer(msg)); cout<<"client send msg:"<<msg<<endl; } 2.2 异步模式

和同步方式不同,异步方式从来不花时间去等那些龟速的IO操作,我只是向系统说一声要做什么,然后就可以做其它事去了。如果系统完成了操作, 系统就会通过我之前给它的回调对象来通知我。
在ASIO库中,异步方式的函数或方法名称前面都有“async_ ” 前缀,函数参数里会要求放一个回调函数。异步操作执行后不管有没有完成都会立即返回,这时可以做一些其它事,直到回调函数被调用,说明异步操作已经完成。
在ASIO中很多回调函数都只接受一个boost::system::error_code参数,在实际使用时肯定是不够的,所以一般使用仿函数携带一堆相关数据作为回调,或者使用boost::bind来绑定一堆数据。
另外要注意的是,只有io_service类的run()方法运行之后回调对象才会被调用,否则即使系统已经完成了异步操作也不会有任 务动作。

服务端

#include "stdafx.h" #include #include #include #include using namespace std; class AsyncServer { public: //构造函数 AsyncServer(boost::asio::io_service &io, boost::asio::ip::tcp::endpoint &ep) :ios(io), ac(io,ep) { this->start(); } private: boost::asio::io_service &ios; boost::asio::ip::tcp::acceptor ac; typedef boost::shared_ptr sock_ptr; //启动异步连接,接受客户端的连接请求 void start() { sock_ptr sock(new boost::asio::ip::tcp::socket(ios)); ac.async_accept(*sock, boost::bind(&AsyncServer::accept_handler, this, boost::asio::placeholders::error, sock)); } void accept_handler(const boost::system::error_code &ec, sock_ptr &sock) { if (ec) return; cout << "客户端地址" <remote_endpoint().address() << endl; cout << "客户端端口" <remote_endpoint().port() <async_write_some(boost::asio::buffer("Hello World"), boost::bind(&AsyncServer::write_handler,this,boost::asio::placeholders::error)); //再次启动异步接受连接 start(); } void write_handler(const boost::system::error_code &) { cout << "服务端发送消息完成" << endl; } }; int _tmain(int argc, _TCHAR* argv[]) { try { boost::asio::io_service ios; boost::asio::ip::tcp::endpoint ep(boost::asio::ip::tcp::v4(),12248); AsyncServer server(ios,ep);//启动异步服务 ios.run(); } catch (exception &e) { cout << e.what() << endl; } return 0; }

客户端

#include "stdafx.h" #include #include #include #include #include using namespace std; class AsyncClient { public: AsyncClient(boost::asio::io_service &io, boost::asio::ip::tcp::endpoint ep):ios(io),ep(ep) { this->start(); } private: boost::asio::io_service &ios; typedef boost::shared_ptr sock_ptr; boost::asio::ip::tcp::endpoint ep; char m_RcvStr[1024]; void start() { sock_ptr sock(new boost::asio::ip::tcp::socket(ios)); sock->async_connect(ep, boost::bind(&AsyncClient::connect_handler, this, boost::asio::placeholders::error, sock)); } void connect_handler(const boost::system::error_code &ec, sock_ptr &sock) { if (ec) return; cout << "服务端地址" <remote_endpoint().address() << endl; cout << "服务端端口" <remote_endpoint().port() <async_read_some(boost::asio::buffer(m_RcvStr), boost::bind(&AsyncClient::read_handler, this, boost::asio::placeholders::error, boost::asio::placeholders::bytes_transferred)); } void read_handler(const boost::system::error_code &ec,size_t i) { if (ec) return; cout << "读数据成功" << endl; cout << m_RcvStr << endl; cout << i<<endl; } }; int _tmain(int argc, _TCHAR* argv[]) { try { boost::asio::io_service ios; boost::asio::ip::tcp::endpoint ep(boost::asio::ip::address::from_string("127.0.0.1"), 12248); AsyncClient client(ios,ep); ios.run(); } catch (exception &e) { cout << e.what() << endl; } return 0; } 3. 补充说明 3.1 io_serveice类不支持拷贝构造

如下程序:

class A { private: io_service io; public: A(io_service io_): io(io_) { } };

程序执行时,会报错;原因在于没有使用引用,而是使用了拷贝。
应该修改成:

io_service &io;
作者:无名无奈



网络编程 boost库

需要 登录 后方可回复, 如果你还没有账号请 注册新账号