TCP / IP-клиент, использующий Boost :: asio

Я пытаюсь сделать клиент TCP / IP используя библиотеку boost. Вот как я разработал свою программу

-> читать ветку для чтения с сервера

-> написать ветку для отправки команд

-> функция, которая анализирует прочитанные данные с сервера

int main()
{

TCP_IP_Connection router;
router.Create_Socket();
boost::thread_group t;
t.create_thread(boost::bind(&TCP_IP_Connection::get_status,&router,'i'));
t.create_thread(boost::bind(&TCP_IP_Connection::readTCP,&router));
std::string reply="\nend of main()";
std::cout<<reply;
t.join_all();
return 0;
}
void TCP_IP_Connection::Create_Socket()
{

tcp::resolver resolver(_io);//resolve into TCP endpoint
tcp::resolver::query query(routerip,rport);

tcp::resolver::iterator endpoint_iterator = resolver.resolve(query);
//list of endpoints
tcp::resolver::iterator end;
boost::asio::streambuf b;
_socket = new tcp::socket(_io); //create socket
boost::system::error_code error= boost::asio::error::host_not_found;

try
{
while (error && endpoint_iterator != end) //if error go to next endpoint
{
_socket->close();
_socket->connect(*endpoint_iterator++, error);
}

if(error)
throw boost::system::system_error(error);

//else the router is connected
}

catch (std::exception& e)
{
std::cerr << e.what() << std::endl;
}
}void TCP_IP_Connection::get_status(char p){
try
{
if(p=='i')
_socket->send(boost::asio::buffer("llist\n\n"));
//sending command for input command
else
_socket->send(boost::asio::buffer(" sspo l1\n\n"));
//sending signal presence for output command
}
catch (std::exception& e)
{
std::cerr << e.what() << std::endl;
}

}void TCP_IP_Connection::readTCP()

{

this->len=0;
boost::system::error_code error= boost::asio::error::host_not_found;
try
{    //loop reading all values from router
while(1)
{

//wait for reply??

_socket->async_read_some(boost::asio::buffer(this-
>reply,sizeof(this>reply)),boost::bind(&TCP_IP_Connection::dataProcess,this,
boost::asio::placeholders::error,boost::asio::placeholders::bytes_transferred));

_io.run();

if(error==boost::asio::error::eof) //connection closed by router
std::cout<<"connection closed by router";
}

}

catch (std::exception& e)
{
std::cerr << e.what() << std::endl;
}

}void TCP_IP_Connection::dataProcess(const boost::system::error_code &er,size_t l)
{
if(!er)
{
if(l>0)
{
for(int i=0;i<l;i++)
{
this->data[i]=this->reply[i];
//if(data[i]="\n")
std::cout<<this->data[i];
}
}
}
}

Когда я запускаю код, все, что я получаю, это ответ от сервера, который говорит, что клиент подключен, а не ответ от команды, которую я посылаю. Но когда я пытаюсь отладить, я получаю полный вывод, как мне нужно. Я делаю что-то не так в потоке или в буфере чтения TCP.

1

Решение

Ваш код создает 2 потока. Первый созданный поток имеет функцию потока с именем get_status. В get_status зацикливание отсутствует, поэтому код выполняется только один раз. Похоже, что он отправляет на сервер строку «llist \ n \ n», и это делается синхронно. После этого больше ничего не отправляет. Итак, вы ожидаете, что сервер отправит другие данные после отправки первой команды? Код в первом потоке может выполняться или не выполняться полностью до выполнения кода во втором потоке.

Второй поток создан, и этот поток, по-видимому, отвечает за обработку информации, поступающей из сокета. Существует бесконечный цикл while (1), но нет логики для выхода из цикла, поэтому он будет работать вечно, пока не будет сгенерировано исключение. Я считаю, что метод async_read_some не приведет к передаче каких-либо данных, пока буфер не будет заполнен. Размер буфера определяется размером ответа. Это может быть вашей проблемой, так как метод dataProcess не будет вызываться до тех пор, пока не будут получены все данные, указанные длиной ответа. Во многих протоколах первые 4 байта указывают длину сообщения. Итак, если вы имеете дело с сообщениями переменной длины, то ваш код должен будет это учитывать.

Еще один момент, о котором стоит упомянуть, это то, что код цикла в readTCP для вызова _io.Run на самом деле не нужен. Вы можете добавить рабочий объект в ваш объект io_service, чтобы он работал непрерывно. Например:

void SSLSocket::InitAsynchIO()
{
// This method is responsible for initiating asynch i/o.
boost::system::error_code Err;
string s;
stringstream ss;
//
try
{
ss << "SSLSocket::InitAsynchIO: Worker thread - " << Logger::NumberToString(boost::this_thread::get_id()) << " started.\n";
Log.LogString(ss.str(), LogInfo);
// Enable the handlers for asynch i/o.  The thread will hang here until the stop method has been called or an error occurs.
// Add a work object so the thread will be dedicated to handling asynch i/o.
boost::asio::io_service::work work(*IOService);
IOService->run();
Log.LogString("SSLSocket::InitAsynchIO: receive worker thread done.\n", LogInfo);
}
catch (std::exception& e)
{
stringstream ss;
ss << "SSLSocket::InitAsynchIO: threw an error - " << e.what() << ".\n";
Log.LogString(ss.str(), LogError);
Stop();
}
}

Вполне нормально, чтобы ваш первый поток сделал ваше первое асинхронное чтение. Ваш обработчик чтения может быть настроен на вызов самого себя для обработки следующего сообщения. Например:

void SSLSocket::HandleRead(const boost::system::error_code& error, size_t bytesTransferred)
{
// This method is called to process an incomming message.
//
std::stringstream ss;
int ByteCount;
try
{
ss << "SSLSocket::HandleRead: From worker thread " << boost::this_thread::get_id() << ".\n";
Log.LogString(ss.str(), LogInfo);
// Set to exit this thread if the user is done.
if (!ReqAlive)
{
// IOService->stop();
return;
}
if (!error)
{
// Get the number of bytes in the message.
if (bytesTransferred == 4)
{
ByteCount = BytesToInt(pDataBuf);
}
else
{
// Call the C# callback method that will handle the message.
ss << "SSLSocket::HandleRead: From worker thread " << boost::this_thread::get_id() << "; # bytes transferred = " << bytesTransferred << ".\n";
Log.LogString(ss.str(), LogDebug2);
Log.LogBuf(pDataBuf, (int)bytesTransferred, true, LogDebug3);
Log.LogString("SSLSocket::HandleRead: sending msg to the C# client.\n\n", LogDebug2);
CallbackFunction(this, bytesTransferred, (void*)pDataBuf);
// Prepare to read in the next message length.
ByteCount = MsgLenBytes;
}
pDataBuf = BufMang.GetPtr(ByteCount);
boost::system::error_code Err;
// boost::asio::async_read(pSocket, boost::asio::buffer(pDataBuf, ByteCount), boost::bind(&SSLSocket::HandleRead,
//  this, boost::asio::placeholders::error, boost::asio::placeholders::bytes_transferred));
Locking CodeLock(SocketLock); // Single thread the code.
boost::asio::async_read(*pSocket, boost::asio::buffer(pDataBuf, ByteCount), boost::bind(&SSLSocket::HandleRead,
this, boost::asio::placeholders::error, boost::asio::placeholders::bytes_transferred));
// boost::asio::read(pSocket, boost::asio::buffer(reply_), boost::asio::transfer_exactly(ByteCount), Err);
}
else
{
Log.LogString("SSLSocket::HandleRead failed: " + error.message() + "\n", LogError);
Stop();
}
}
catch (std::exception& e)
{
stringstream ss;
ss << "SSLSocket::HandleRead: threw an error - " << e.what() << ".\n";
Log.LogString(ss.str(), LogError);
Stop();
}
}

Если ничего из вышеперечисленного не поможет, вставьте некоторый код отладки, который регистрирует все вызовы в файле журнала, чтобы вы могли видеть, что происходит. Вы также можете рассмотреть возможность загрузки Wire Shark, чтобы увидеть, какие данные выходят и поступают.

1

Другие решения

Других решений пока нет …

По вопросам рекламы [email protected]