初学BOOST库,基于Tcp/Ip简易的问题回答

3 篇文章 0 订阅
2 篇文章 0 订阅

简述:

初学BOOST库之Asio网络库,写一个基于TCP/IP网络协议的问题回答。一端是服务端(包含应答监听以及数据存储);
另一端为客户端运行起来之后服务器会响应,然后回答问题。(数据库是用ODBC API进行操作的)

1、服务端代码:

#include<iostream>
#include<boost/asio.hpp>
#include<vector>
#include <cstdlib>
#include<string>
#include <sql.h>
#include <sqlext.h>
#include <odbcss.h>
#include<boost/thread.hpp>
#include<boost/bind.hpp>
#include<boost/array.hpp>
#include<boost/noncopyable.hpp>
#include<boost/shared_ptr.hpp>
#include<boost/asio/ip/tcp.hpp>
#include<boost/enable_shared_from_this.hpp>
#include<boost/algorithm/string.hpp>
#include <boost/aligned_storage.hpp>

using boost::asio::ip::tcp;
using namespace std;
#define MAXBUFLEN   255 
#define MaxNameLen  20
#define SQLBINDCOL
SQLHENV  henv = SQL_NULL_HENV;//定义环境句柄
SQLHDBC  hdbc1 = SQL_NULL_HDBC;//定义数据库连接句柄     
SQLHSTMT  hstmt1 = SQL_NULL_HSTMT;//定义语句句柄

class handle_alloc
	:private boost::noncopyable	    //禁止拷贝
{
private:
	boost::aligned_storage<1024> st;
	bool in;
public:
	handle_alloc()
		: in(false)
	{}
	void* allocate(std::size_t size)
	{
		if (!in&&st.size > size)
		{
			in = true;
			return st.address();
		}
		else
		{
			return ::operator new(size);	 //实现不同的内存分配,应重载operator new,而不是new;若类中没有重载operator new,就调用的全局的::operator new堆分配
		}
	}
	void* delallocate(void* p)
	{
		if (p == st.address())
		{
			in = false;
		}
		else
			::operator delete(p);
	}
};


template<class Thandle>
class usage_alloc_handle
{
private:
	handle_alloc& alloc_;
	Thandle handle_;
public:
	usage_alloc_handle(handle_alloc& a, Thandle h)
		:alloc_(a), handle_(h)
	{
	}
	template<class A1>
	void operator()(A1 a1)
	{
		handle_(a1);
	}
	template<class A1, class A2>
	void operator()(A1 a1, A2 a2)
	{
		handle_(a1, a2);
	}
	friend void* asio_handle_alloc(std::size_t size, usage_alloc_handle<Thandle>* t_handle)
	{
		return t_handle->alloc_.allocate(size);
	}
	friend void asio_handle_delallocate(void*p, std::size_t size, usage_alloc_handle<Thandle>* t_handle)
	{
		t_handle->alloc_.delallocate(p);
	}
};


template<class Thandle>
inline usage_alloc_handle<Thandle> mk_usage_alloc_handle(handle_alloc& a, Thandle h)
{
	return usage_alloc_handle<Thandle>(a, h);
}


class io_service_pool
	:private boost::noncopyable
{
public:
	explicit io_service_pool(std::size_t p_size)							   //显式构造,不使用默认的隐式构造
		:sio_service(0)
	{
		if (p_size == 0)
		{
			throw std::runtime_error("size is 0");			    //抛出异常
		}
		for (std::size_t i = 0; i < p_size; ++i)
		{
			io_service_ptr io_service(new boost::asio::io_service);
			work_ptr work(new boost::asio::io_service::work(*io_service));

			vio_service.push_back(io_service);
			vwork.push_back(work);
		}
	}
	void run()
	{
		//std::vector<boost::shared_ptr<boost::thread>> threads_;
		boost::thread_group  tg;
		for (std::size_t j = 0; j < vio_service.size(); ++j)
		{
			tg.create_thread([j, this]() {
				for (;;) {
					try {
						this->vio_service[j]->run();
					}
					catch (...) {
						cerr << "io_service throw exception" << endl;
					}
				}
			});
			//boost::shared_ptr<boost::thread>thread(new boost::thread(

			//线程绑定io
		//	threads_.push_back(thread);
		}
		tg.join_all();
		// 		for (std::size_t i = 0; i < threads_.size(); ++i)
		// 		{
		// 			threads_[i]->join();
		// 		}
	}
	void stop()
	{
		for (std::size_t i = 0; i < vio_service.size(); ++i)
		{
			vio_service[i]->stop();    //停止事件循环(即停止run)
		}
	}
	boost::asio::io_service& get_io_service()
	{
		boost::asio::io_service& io_service = *vio_service[sio_service];
		++sio_service;
		if (sio_service == vio_service.size())
		{
			sio_service = 0;
		}
		return io_service;
	}

private:
	typedef boost::shared_ptr<boost::asio::io_service> io_service_ptr;
	typedef boost::shared_ptr<boost::asio::io_service::work> work_ptr;  //用智能指针管理work,不用的时候可以用reset析构掉
	std::size_t sio_service;
	std::vector<io_service_ptr> vio_service;
	std::vector<work_ptr> vwork;
};


class session				 //会话
	:public boost::enable_shared_from_this<session>	   //weak_ptr获得this指针的shared_ptr,对象自己生产shared_ptr管理自己
	 //一个需要shared_ptr自我管理的类  普通的就这种格式
{
private:
	tcp::socket _socket;
	boost::asio::io_service& wio_service;
	boost::array<char, 1024> _data;
	handle_alloc _alloc;
public:
	session(boost::asio::io_service& work_service, boost::asio::io_service& io_service)
		:_socket(io_service), wio_service(work_service)
	{}
	tcp::socket& socket()
	{
		return _socket;
	}
	void start()
	{
		boost::system::error_code error;	//系统错误码
		handle_write(error);
		_socket.async_read_some(boost::asio::buffer(_data), mk_usage_alloc_handle(_alloc, boost::bind(&session::handle_read,
			shared_from_this(), boost::asio::placeholders::error, boost::asio::placeholders::bytes_transferred)));//异步错误处理
	}
	void handle_read(const boost::system::error_code& error, size_t bytes_transferred)
	{
		if (!error)
		{
			boost::shared_ptr<std::vector<char>>buf(new std::vector<char>);
			buf->resize(bytes_transferred);
			std::copy(_data.begin(), _data.begin() + bytes_transferred, buf->begin());

			wio_service.post(boost::bind(&session::receive, shared_from_this(), buf, bytes_transferred));

			_socket.async_read_some(boost::asio::buffer(_data), mk_usage_alloc_handle(_alloc, boost::bind(&session::receive,
				shared_from_this(), buf, boost::asio::placeholders::bytes_transferred)));
		}
	}
	void handle_write(const boost::system::error_code& error)
	{
		int i = 0;
		if (!error)
		{
			string N[6] = { "\n\t\t\t\t\t\t\t简易问卷\t\n","please answer the questions\n", "\nyour name?\n","your age?\n","your school?\n","your address?\n" };
			size_t m;
			try
			{
				for (i = 0; i < 6; i++)
				{
					m = _socket.send(boost::asio::buffer(N[i]));
				}
			}
			catch (std::exception& e)
			{
				std::cout << "exception:" << e.what() << std::endl;
			}
			if (m >= 0)
			{
				std::cout << "send:" << "  " << N << std::endl;
			}
		}
	}
	int receive(boost::shared_ptr<std::vector<char>>buffers, size_t bytes_transferred)
	{
		SQLRETURN retcode;//错误返回码			
		retcode = SQLAllocHandle(SQL_HANDLE_ENV, NULL, &henv);
		if (retcode < 0)//错误处理
		{
			cout << "allocate ODBC Environment handle errors." << endl;
			return -1;
		}
		retcode = SQLSetEnvAttr(henv, SQL_ATTR_ODBC_VERSION, (SQLPOINTER)SQL_OV_ODBC3, SQL_IS_INTEGER);
		if (retcode < 0) //错误处理
		{
			cout << "the  ODBC is not version3.0 " << endl;
			return -1;
		}

		retcode = SQLAllocHandle(SQL_HANDLE_DBC, henv, &hdbc1);
		if (retcode < 0) //错误处理
		{
			cout << "allocate ODBC connection handle errors." << endl;
			return -1;
		}

		char* szDSN = "mysql5.5";
		char* szUID = "root";//log name
		char* szAuthStr = "123";//passward
		SQLSetConnectAttr(hdbc1, SQL_LOGIN_TIMEOUT, (SQLPOINTER *)5, 0);
		retcode = SQLConnect(hdbc1, (SQLCHAR*)szDSN, (SWORD)strlen(szDSN), (SQLCHAR*)szUID, (SWORD)strlen(szUID), (SQLCHAR*)szAuthStr, (SWORD)strlen(szAuthStr));
		if (retcode < 0) //错误处理
		{
			cout << "connect to  ODBC errors." << endl;
			return -1;
		}

		retcode = SQLAllocHandle(SQL_HANDLE_STMT, hdbc1, &hstmt1);
		if (retcode < 0) //错误处理
		{
			cout << "allocate ODBC statement handle errors." << endl;
			return -1;
		}

		std::vector<string> v;
		int j = 0;
		char sttrr[10][10] = { 0 };
		char* data_str = &(*buffers->begin());
		boost::split(v, data_str, boost::is_any_of("#"), boost::token_compress_on);

		for (int q = 0; q < v.size(), j < v.size(); q++, j++)
		{
			cout << v[q].c_str() << endl;
			strcpy(sttrr[j], v[q].c_str());
		}
		retcode = SQLAllocHandle(SQL_HANDLE_STMT, hdbc1, &hstmt1);//申请SQL语句句柄  
		SQLCHAR sql[] = "insert into asio_test values (?,?,?,?);";
		SQLINTEGER P = SQL_NTS;

		retcode = SQLPrepare(hstmt1, sql, SQL_NTS);
		retcode = SQLBindParameter(hstmt1, 1, SQL_PARAM_INPUT, SQL_C_CHAR, SQL_CHAR, 20, 0, sttrr[0], 20, &P);//绑定参数  
		retcode = SQLBindParameter(hstmt1, 2, SQL_PARAM_INPUT, SQL_C_CHAR, SQL_CHAR, 10, 0, sttrr[1], 10, &P);//绑定参数 
		retcode = SQLBindParameter(hstmt1, 3, SQL_PARAM_INPUT, SQL_C_CHAR, SQL_CHAR, 10, 0, sttrr[2], 10, &P);//绑定参数
		retcode = SQLBindParameter(hstmt1, 4, SQL_PARAM_INPUT, SQL_C_CHAR, SQL_CHAR, 20, 0, sttrr[3], 20, &P);//绑定参数  
		retcode = SQLExecute(hstmt1);//直接执行SQL语句
				//SQLPOINTER
		retcode = SQLExecDirect(hstmt1, (SQLCHAR*)"SElECT name,age,school,addr  FROM asio_test", SQL_NTS);
		if (retcode < 0)
		{																			   
			cout << "Executing statement  throught ODBC  errors." << endl;
			return -1;
		}
		SQLCHAR      age[MaxNameLen + 1];
		SQLCHAR   name[MaxNameLen + 1];
		SQLCHAR   school[MaxNameLen + 1];
		SQLCHAR   addr[MaxNameLen + 1];
		SQLINTEGER   columnLen = 0;                                                                                                  //数据库定义中该属性列的长度
#ifdef SQLBINDCOL
		retcode = SQLBindCol(hstmt1, 1, SQL_C_CHAR, name, MaxNameLen, &columnLen);
		retcode = SQLBindCol(hstmt1, 2, SQL_C_CHAR, age, MaxNameLen, &columnLen);
		retcode = SQLBindCol(hstmt1, 3, SQL_C_CHAR, school, MaxNameLen, &columnLen);
		retcode = SQLBindCol(hstmt1, 4, SQL_C_CHAR, addr, MaxNameLen, &columnLen);
		while ((retcode = SQLFetch(hstmt1)) != SQL_NO_DATA)
		{
			if (columnLen > 0)
				printf("name = %s  age = %s  school=%s  addr=%s\n", name, age, school, addr);
			else
				printf("name = %s  age = NULL  school=NULL  addr=NULL\n", name, age, school, addr);
		}
#else
		while (1)
		{
			retcode = SQLFetch(hstmt1);
			if (retcode == SQL_NO_DATA)
				break;

			retcode = SQLGetData(hstmt1, 1, SQL_C_CHAR, name, MaxNameLen, &columnLen);
			retcode = SQLGetData(hstmt1, 2, SQL_C_CHAR, city, MaxNameLen, &columnLen);
			retcode = SQLBindCol(hstmt1, 3, SQL_C_CHAR, school, MaxNameLen, &columnLen);
			retcode = SQLBindCol(hstmt1, 4, SQL_C_CHAR, addr, MaxNameLen, &columnLen);
			if (columnLen > 0)
				printf("name = %s  age = %s  school=%s  addr=%s\n", name, age, school, addr);
			else
				printf("name = %s  age = NULL  school=NULL  addr=NULL\n", name, age, school, addr);

		}
#endif

		SQLFreeHandle(SQL_HANDLE_STMT, hstmt1);
		SQLDisconnect(hdbc1);
		SQLFreeHandle(SQL_HANDLE_DBC, hdbc1);
		SQLFreeHandle(SQL_HANDLE_ENV, henv);
		return (0);
	}
};

typedef boost::shared_ptr<session> s_ptr;

class server
{
private:
	boost::shared_ptr<boost::thread> io_thread;
	boost::shared_ptr<boost::thread> work_thread;
	io_service_pool io_service_pool_;
	io_service_pool io_service_work_pool;
	tcp::acceptor _accept;
public:
	server(short port, std::size_t io_service_pool_size)
		:io_service_pool_(io_service_pool_size), io_service_work_pool(io_service_pool_size)
		, _accept(io_service_pool_.get_io_service(), tcp::endpoint(tcp::v4(), 8080))
	{
		s_ptr new_session(new session(io_service_work_pool.get_io_service(), io_service_pool_.get_io_service()));
		_accept.async_accept(new_session->socket(), boost::bind(&server::handle_accept, this, new_session, boost::asio::placeholders::error));
	}

	void handle_accept(s_ptr new_session, const boost::system::error_code& error)
	{
		if (!error)
		{
			new_session->start();
			new_session.reset(new session(io_service_work_pool.get_io_service(), io_service_pool_.get_io_service()));
			_accept.async_accept(new_session->socket(), boost::bind(&server::handle_accept, this, new_session, boost::asio::placeholders::error));
		}
	}
	void run()
	{
		io_thread.reset(new boost::thread(boost::bind(&io_service_pool::run, &io_service_pool_)));
		work_thread.reset(new boost::thread(boost::bind(&io_service_pool::run, &io_service_pool_)));
	}
	void stop()
	{
		io_service_pool_.stop();
		io_service_work_pool.stop();
		io_thread->join();
		work_thread->join();
	}
};

int main(int argc, char* argv[])
{
	boost::asio::io_service ioservice;
	boost::asio::ip::tcp::socket sock(ioservice);
	try
	{
		std::cout << "server start." << std::endl;
		server s(8080, 100);
		s.run();
		getchar();
		s.stop();
	}
	catch (std::exception& e)
	{
		std::cout << e.what() << std::endl;
	}
	return 0;
}

2、客户端代码:

#include<iostream>
#include<boost/asio.hpp>
#include<vector>
using namespace boost::asio;

int main()
{
	io_service ioservice;
	ip::tcp::socket sock(ioservice);
	ip::tcp::endpoint ep(ip::address::from_string("127.0.0.1"), 8080);
	ioservice.run();
	try
	{
		sock.connect(ep);
		int i = 1;
		while (i)
		{
			std::cout << "client start." << std::endl;
			std::vector<char> str(1024, 0);
			std::cout << "Recv from: " << sock.remote_endpoint().address() << std::endl;
			int nSize = sock.read_some(buffer(str));
			std::cout<< &str[0] << std::endl;
			std::string sz ;
			std::cout << "answer:(请用#键隔开每个答案)" << std::endl;
			std::cin >> sz;
			sock.send(buffer(sz));
			i--;
		}
		sock.close();
	}
	catch (std::exception& e)
	{
		std::cout << e.what() << std::endl;
	}
}


  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值