我使用boost:asio創建了一個服務器。當客戶端連接時,它發送一個file_size,file_name和file_data。服務器將其存儲在磁盤上的文件中。這完美的作品!雖然現在我在其應用程序的主線程中運行客戶端應用程序和服務器應用程序(所以我有一個服務器和客戶端應用程序),它阻止應用程序的其餘部分執行。如何:Boost :: asio的客戶端連接管理器?
所以在抽象我想創造這樣的事情:
服務器應用
- 有一個線程來接收和處理所有傳入的文件傳輸
- 有另一個線程在休息的應用程序可以做它想要的東西
cl ient應用
-
當我按下空格鍵,或者只要我想,我想從主要的一個文件發送到服務器在一個單獨的線程,所以我的應用程序可以繼續做它需要做其他的東西
- 。
我的問題:如何爲我的客戶端文件傳輸創建管理器?
文件傳輸服務器接受新的文件傳輸客戶端連接
#include "ofxFileTransferServer.h"
ofxFileTransferServer::ofxFileTransferServer(unsigned short nPort)
:acceptor(
io_service
,boost::asio::ip::tcp::endpoint(
boost::asio::ip::tcp::v4()
,nPort
)
,true
)
,port(nPort)
{
}
// test
void ofxFileTransferServer::startThread() {
boost::thread t(boost::bind(
&ofxFileTransferServer::accept
,this
));
}
void ofxFileTransferServer::accept() {
ofxFileTransferConnection::pointer new_connection(new ofxFileTransferConnection(io_service));
acceptor.async_accept(
new_connection->socket()
,boost::bind(
&ofxFileTransferServer::handleAccept
,this
,new_connection
,boost::asio::placeholders::error
)
);
std::cout << __FUNCTION__ << " start accepting " << std::endl;
io_service.run();
}
void ofxFileTransferServer::handleAccept(
ofxFileTransferConnection::pointer pConnection
,const boost::system::error_code& rErr
)
{
std::cout << __FUNCTION__ << " " << rErr << ", " << rErr.message() << std::endl;
if(!rErr) {
pConnection->start();
ofxFileTransferConnection::pointer new_connection(new ofxFileTransferConnection(io_service));
acceptor.async_accept(
new_connection->socket()
,boost::bind(
&ofxFileTransferServer::handleAccept
,this
,new_connection
,boost::asio::placeholders::error
)
);
}
}
文件傳輸客戶端
#include "ofxFileTransferClient.h"
#include "ofMain.h"
using boost::asio::ip::tcp;
ofxFileTransferClient::ofxFileTransferClient(
boost::asio::io_service &rIOService
,const std::string sServer
,const std::string nPort
,const std::string sFilePath
):resolver_(rIOService)
,socket_(rIOService)
,file_path_(sFilePath)
,server_(sServer)
,port_(nPort)
{
}
ofxFileTransferClient::~ofxFileTransferClient() {
std::cout << "~~~~ ofxFileTransferClient" << std::endl;
}
void ofxFileTransferClient::start() {
// open file/get size
source_file_stream_.open(
ofToDataPath(file_path_).c_str()
,std::ios_base::binary | std::ios_base::ate
);
if(!source_file_stream_) {
std::cout << ">> failed to open:" << file_path_ << std::endl;
return;
}
size_t file_size = source_file_stream_.tellg();
source_file_stream_.seekg(0);
// send file size and name to server.
std::ostream request_stream(&request_);
request_stream << file_path_ << "\n"
<< file_size << "\n\n";
std::cout << ">> request_size:" << request_.size()
<< " file_path: " << file_path_
<< " file_size: "<< file_size
<< std::endl;
// resolve ofxFileTransferServer
tcp::resolver::query query(server_, port_);
resolver_.async_resolve(
query
,boost::bind(
&ofxFileTransferClient::handleResolve
,shared_from_this()
,boost::asio::placeholders::error
,boost::asio::placeholders::iterator
)
);
}
void ofxFileTransferClient::handleResolve(
const boost::system::error_code& rErr
,tcp::resolver::iterator oEndPointIt
)
{
if(!rErr) {
tcp::endpoint endpoint = *oEndPointIt;
socket_.async_connect(
endpoint
,boost::bind(
&ofxFileTransferClient::handleConnect
,shared_from_this()
,boost::asio::placeholders::error
,++oEndPointIt
)
);
}
else {
std::cout << ">> error: " << rErr.message() << std::endl;
}
}
void ofxFileTransferClient::handleConnect(
const boost::system::error_code& rErr
,tcp::resolver::iterator oEndPointIt
)
{
if(!rErr) {
cout << ">> connected!" << std::endl;
boost::asio::async_write(
socket_
,request_
,boost::bind(
&ofxFileTransferClient::handleFileWrite
,shared_from_this()
,boost::asio::placeholders::error
)
);
}
else if (oEndPointIt != tcp::resolver::iterator()) {
// connection failed, try next endpoint in list
socket_.close();
tcp::endpoint endpoint = *oEndPointIt;
socket_.async_connect(
endpoint
,boost::bind(
&ofxFileTransferClient::handleConnect
,shared_from_this()
,boost::asio::placeholders::error
,++oEndPointIt
)
);
}
else {
std::cout << ">> error: " << rErr.message() << std::endl;
}
}
void ofxFileTransferClient::handleFileWrite(
const boost::system::error_code& rErr
)
{
if(!rErr) {
if(source_file_stream_.eof() == false) {
source_file_stream_.read(buf_.c_array(), buf_.size());
if(source_file_stream_.gcount() <= 0) {
std::cout << ">> read file error." << std::endl;
return;
}
std::cout << ">> send: " << source_file_stream_.gcount() << " bytes, total: " << source_file_stream_.tellg() << " bytes\n";
boost::asio::async_write(
socket_
,boost::asio::buffer(buf_.c_array(), source_file_stream_.gcount())
,boost::bind(
&ofxFileTransferClient::handleFileWrite
,this
,boost::asio::placeholders::error
)
);
if(rErr) {
std::cout <<">> send error: " << rErr << std::endl; // not sure bout this one..
}
}
else {
return; // eof()
}
}
else {
std::cout << ">> error:" << rErr.message() << std::endl;
}
}
和一個小經理管理客戶端傳輸(這是在使用客戶端應用程序) 線程代碼僅用於tes目的並不被使用。
#include "ofxFileTransferManager.h"
ofxFileTransferManager::ofxFileTransferManager() {
}
void ofxFileTransferManager::transferFile(
const std::string sServer
,const std::string nPort
,const std::string sFile
)
{
ofxFileTransferClient::pointer client(new ofxFileTransferClient(
io_service_
,sServer
,nPort
,sFile
));
client->start();
io_service_.run();
}
void ofxFileTransferManager::startThread() {
boost::thread t(boost::bind(
&ofxFileTransferManager::run
,this
));
}
void ofxFileTransferManager::run() {
cout << "starting filemanager" << std::endl;
while(true) {
io_service_.run();
boost::this_thread::sleep(boost::posix_time::milliseconds(250));
cout << ".";
}
cout << "ready filemanager" << std::endl;
}
如果有人能幫助我在這裏,這將是太棒了。 boost的例子都使用「一次性」客戶端連接,這對我來說並沒有什麼幫助。
roxlu
喜詹尼,爲沒關係的服務器,但我想用管理器文件「送」到這臺服務器類。問題是我不能把io_service.run()放入一個線程中,因爲它可能沒有文件需要傳輸。 – pollux 2010-08-13 14:43:59