您的位置:首页 > 理论基础 > 计算机网络

使用boost::asio开发网络服务器

2016-01-29 00:12 555 查看
作为简单的示例,说明, 此服务器只是作为简单的数据收发示例,没有加入reactor模式的事件分法机制如select/epoll, 有待进一步完善。

因代码并非完全独自编写,所以注明是转载。

服务器端

#include <boost/asio.hpp>
#include <boost/bind.hpp>
#include <boost/shared_ptr.hpp>
#include <boost/enable_shared_from_this.hpp>
#include <iostream>

using boost::asio::ip::tcp;

#define max_len 1024

class clientSession
:public boost::enable_shared_from_this<clientSession>
{
public:
clientSession(boost::asio::io_service& ioservice)
:m_socket(ioservice)
{
memset(data_, '\0', sizeof(data_));
}
~clientSession()
{}
tcp::socket& socket()
{
return m_socket;
}
void start()
{
boost::asio::async_write(m_socket,
boost::asio::buffer("link successed!"),
boost::bind(&clientSession::handle_write, shared_from_this(),
boost::asio::placeholders::error));

/*async_read跟客户端一样,还是不能进入handle_read函数,如果你能找到问题所在,请告诉我,谢谢*/

// --已经解决,boost::asio::async_read(...)读取的字节长度不能大于数据流的长度,否则就会进入
// ioservice.run()线程等待,read后面的就不执行了。
//boost::asio::async_read(m_socket,boost::asio::buffer(data_,max_len),

//         boost::bind(&clientSession::handle_read,shared_from_this(),

//         boost::asio::placeholders::error));
//max_len可以换成较小的数字,就会发现async_read_some可以连续接收未收完的数据

m_socket.async_read_some(boost::asio::buffer(data_, max_len),
boost::bind(&clientSession::handle_read, shared_from_this(),
boost::asio::placeholders::error));
}
private:
void handle_write(const boost::system::error_code& error)
{

if (error)
{
m_socket.close();
}

}
void handle_read(const boost::system::error_code& error)
{

if (!error)
{
std::cout << data_ << std::endl;
//boost::asio::async_read(m_socket,boost::asio::buffer(data_,max_len),

//     boost::bind(&clientSession::handle_read,shared_from_this(),

//     boost::asio::placeholders::error));

m_socket.async_read_some(boost::asio::buffer(data_, max_len),
boost::bind(&clientSession::handle_read, shared_from_this(),
boost::asio::placeholders::error));
}
else
{
m_socket.close();
}

}
private:
tcp::socket m_socket;
char data_[max_len];
};

class serverApp
{
typedef boost::shared_ptr<clientSession> session_ptr;
public:
serverApp(boost::asio::io_service& ioservice, tcp::endpoint& endpoint)
:m_ioservice(ioservice),
acceptor_(ioservice, endpoint)
{
session_ptr new_session(new clientSession(ioservice));
acceptor_.async_accept(new_session->socket(),
boost::bind(&serverApp::handle_accept, this, boost::asio::placeholders::error,
new_session));
}
~serverApp()
{
}
private:
void handle_accept(const boost::system::error_code& error, session_ptr& session)
{
if (!error)
{
std::cout << "get a new client!" << std::endl;
//实现对每个客户端的数据处理

session->start();
//在这就应该看出为什么要封session类了吧,每一个session就是一个客户端

session_ptr new_session(new clientSession(m_ioservice));
acceptor_.async_accept(new_session->socket(),
boost::bind(&serverApp::handle_accept, this, boost::asio::placeholders::error,
new_session));
}
}
private:
boost::asio::io_service& m_ioservice;
tcp::acceptor acceptor_;
};

int main(int argc, char* argv[])
{
boost::asio::io_service myIoService;
short port = 8100/*argv[1]*/;
//我们用的是inet4

tcp::endpoint endPoint(tcp::v4(), port);
//终端(可以看作sockaddr_in)完成后,就要accept了

serverApp sa(myIoService, endPoint);
//数据收发逻辑

myIoService.run();
return 0;
}


客户端

#include <boost/asio.hpp>
#include <boost/bind.hpp>
#include <boost/shared_ptr.hpp>

#include <iostream>

using boost::asio::ip::tcp;

class client
{
public:
client(boost::asio::io_service& io_service, tcp::endpoint& endpoint)
: socket(io_service)//这里就把socket实例化了
{
//连接服务端 connect
socket.async_connect(endpoint,
boost::bind(&client::handle_connect, this, boost::asio::placeholders::error)
);
memset(getBuffer, '\0', 1024);
}
~client()
{}
private:
void handle_connect(const boost::system::error_code& error)
{
if (!error)
{
//一连上,就向服务端发送信息
boost::asio::async_write(socket, boost::asio::buffer("hello, server!"),
boost::bind(&client::handle_write, this, boost::asio::placeholders::error));

/**读取服务端发下来的信息
*这里很奇怪,用async_read根本就不能进入handle_read函数
**/

// --已经解决,boost::asio::async_read(...)读取的字节长度不能大于数据流的长度,否则就会进入
// ioservice.run()线程等待,read后面的就不执行了。
//boost::asio::async_read(socket,
//     boost::asio::buffer(getBuffer,1024),
//     boost::bind(&client::handle_read,this,boost::asio::placeholders::error)
//    );
socket.async_read_some(boost::asio::buffer(getBuffer, 1024),
boost::bind(&client::handle_read, this, boost::asio::placeholders::error)
);
}
else
{
socket.close();
}
}
void handle_read(const boost::system::error_code& error)
{
if (!error)
{
std::cout <<"getBuffer"<< std::endl;
//boost::asio::async_read(socket,
//         boost::asio::buffer(getBuffer,1024),
//         boost::bind(&client::handle_read,this,boost::asio::placeholders::error)
//        );

//这样就可以实现循环读取了,相当于while(1)
//当然,到了这里,做过网络的朋友就应该相当熟悉了,一些逻辑就可以自行扩展了
//想做聊天室的朋友可以用多线程来实现
socket.async_read_some(
boost::asio::buffer(getBuffer, 1024),
boost::bind(&client::handle_read, this, boost::asio::placeholders::error)
);
}
else
{
socket.close();
}
}
void handle_write(const boost::system::error_code& error)
{
}

private:
tcp::socket socket;
char getBuffer[1024];
};

int main(int argc, char* argv[])
{
//if(argc != 3)
//{
// std::cerr << “Usage: chat_client <host> <port>\n”;
//    return 1;
//}

//我觉IO_SERVICE是一个基本性的接口,基本上通常用到的类实例都需要通过它来构造
//功能我们可以看似socket
boost::asio::io_service io_service;
//这个终端就是服务器
//它的定义就可以看作时sockaddr_in,我们用它来定义IP和PORT
tcp::endpoint endpoint(boost::asio::ip::address_v4::from_string("127.0.0.1"/*argv[1]*/), 8100/*argv[2]*/);
//既然socket和sockaddr_in已经定义好了,那么,就可以CONNECT了
//之所以为了要把连接和数据处理封成一个类,就是为了方便管理数据,这点在服务端就会有明显的感觉了
boost::shared_ptr<client> client_ptr(new client(io_service, endpoint));
//执行收发数据的函数
io_service.run();
return 0;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: