Простой клиент / сервер теряет линии при передаче (boost / Windows)

Первые данные среды: Windows 7, c: \ boost (1.55.0), Microsoft Visual C ++ 2010 Express (SP1)

Вот самая простая функциональная версия клиента / сервера, о которой вы можете подумать, используя новые линии с окончанием строки в качестве способа транспортировки (не обращайте внимания на отсутствие ограничений и время ожидания, пожалуйста!)

Сервер ждет, пока клиент не отправит "f\n", а затем отправляет обратно обрезанные строки из локального текстового файла обратно клиенту. Самая последняя строка содержит только точку (.), Которая указывает на конец передачи (не считая того факта, что в файле может быть точка).

Вывод на сервер показывает, что все строки отправляются обратно клиенту. Клиент, однако, показывает, что отсутствуют некоторые строки.

Я не вижу, где есть возможность для передачи пропустить данные.

Вот полнофункциональный код сервера. Постройте его и запустите на сервере без аргументов.

#define _CRT_SECURE_NO_WARNINGS

#include "stdafx.h"#include <iostream>
#include <boost/asio.hpp>

void writeln( boost::asio::ip::tcp::socket& socket, const std::string& text )
{
std::cout << "writeln " << text << "\n" ;
boost::system::error_code error ;
boost::asio::write( socket, boost::asio::buffer( text + "\n", text.length() + 1 ), boost::asio::transfer_all(), error );
}

bool readln( boost::asio::ip::tcp::socket& socket, std::string& text )
{
try
{
boost::asio::streambuf response ;
boost::asio::read_until( socket, response, "\n" ) ;

std::istream response_stream( &response ) ;
std::getline( response_stream, text ) ;

if ( text != "." )
return true ;
}
catch( const std::exception& e )
{
std::cerr << e.what() << "\n" ;
}

return false ;
}

static char* trim( char* line )
{
size_t len = strlen( line ) ;

while ( len > 0 && ( line[ len - 1 ] == ' ' || line[ len - 1 ] == '\t' || line[ len - 1 ] == '\n' || line[ len - 1 ] == '\r' ))
len-- ;

line[ len ] = 0 ;

return line ;
}

static void f( boost::asio::ip::tcp::socket& socket )
{
std::string fname = "c:\\f.txt" ;
FILE* f = fopen( fname.c_str(), "r" ) ;
if ( f != NULL )
{
char line[ 1024 ] ;

while ( fgets( line, sizeof( line ), f ) != NULL )
writeln( socket, trim( line )) ;

fclose( f ) ;
}
}

int main( int argc, char* argv[])
{
try
{
boost::asio::io_service        io_service ;
boost::asio::ip::tcp::acceptor acceptor( io_service, boost::asio::ip::tcp::endpoint(boost::asio::ip::tcp::v4(), 8080 )) ;

for (;;)
{
boost::asio::ip::tcp::socket socket( io_service ) ;
std::string                  cmd ;

acceptor.accept( socket ) ;
while ( readln( socket, cmd ))
{
std::cout << cmd << "\n" ;
if ( cmd == "f" )
f( socket ) ;

writeln( socket, "." ) ;
}
}
}
catch( const std::exception& e )
{
std::cerr << e.what() << "\n" ;
}

return 0 ;
}

И вот идет код клиента. Вызов prog 127.0.0.1 f чтобы увидеть результат.

#include "stdafx.h"#include <boost/asio.hpp>
#include <iostream>

void writeln( boost::asio::ip::tcp::socket& socket, const std::string& text )
{
boost::system::error_code error ;
boost::asio::write( socket, boost::asio::buffer( text + "\n", text.length() + 1 ), boost::asio::transfer_all(), error );
}

bool readln( boost::asio::ip::tcp::socket& socket, std::string& text )
{
try
{
boost::asio::streambuf response ;
boost::asio::read_until( socket, response, "\n" ) ;
std::istream response_stream( &response ) ;
std::getline( response_stream, text ) ;
std::cout << "readln " << text << "\n" ;
if ( text != "." )
return true ;
}
catch( const std::exception& e )
{
std::cerr << e.what() << "\n" ;
}

return false ;
}

int main( int argc, char* argv[])
{
if ( argc > 2 )
try
{
boost::asio::io_service      io_service ;
boost::asio::ip::tcp::socket socket( io_service ) ;
std::string                  text ;

socket.connect( boost::asio::ip::tcp::endpoint( boost::asio::ip::address::from_string( argv[ 1 ]), 8080 )) ;

writeln( socket, argv[ 2 ]) ;

while ( readln( socket, text ))
std::cout << text << "\n" ;

return 0 ;
}
catch( const std::exception& e )
{
std::cerr << e.what() << "\n" ;
return 1 ;
}
}

0

Решение

bool readln( boost::asio::ip::tcp::socket& socket, std::string& text ) Функция в версии клиента неверна. Использует буферизованный ввод, который ест больше, чем должен.

Это не лучшая версия, но вместо текущего кода клиента:

    while ( readln( socket, text ))
std::cout << text << "\n" ;

Это может сделать:

    boost::asio::streambuf response ;

for(;;)
{
boost::asio::read_until( socket, response, "\n" ) ;
std::istream response_stream( &response ) ;
std::getline( response_stream, text ) ;
if ( text == "." )
break ;
std::cout << text << "\n" ;
}
1

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


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