Onega's profileOnegaBlogListsNetwork Tools Help

Onega Zhang

Occupation

Onega

www.fruitfruit.com
November 30

why do I use alloca

alloca function allocates memory from stack, thus is much faster than heap and is released automatically when function exit. At first look it like like declare a char array, but the difference is that you can only declare array of fixed size on stack, but you can get variable size memory (although limited by available stack size) via alloca.

#include <windows.h>
#include <iostream>
#include <iomanip>
#include <exception>
void test_stackoverflow(int size)
{
    std::cout << __FUNCTION__ << "("<<size<<")\n";
    char* ptr = static_cast<char*>(alloca(size));
    ptr[0]='a';
    std::cout << __FUNCTION__ << "()\n";
}

void test_with_std_exception()
{
    try
    {
        for(int i=102; ;i++ )
            test_stackoverflow(i*10240);
    }
    catch (std::exception& e)
    {
        std::cout << e.what()<<std::endl;
    }

}
void main(int argc, char* argv[])
{
    __try{
        for(int i=102; ;i++ )
            test_stackoverflow(i*10240);

    }
    __except (EXCEPTION_EXECUTE_HANDLER)
    {
        std::cout<<"Exception code 0x"<<std::hex<< _exception_code()<<std::endl;
    }
    if (argc>1)
        test_with_std_exception();
}
// cl -EHa overflow.cpp
// D:\test\stl>overflow.exe
//test_stackoverflow(1044480)
//  Exception code 0xc00000fd

November 17

std::stack, std::queue and std::priority_queue

The interesting fact is that std::queue and std::priority_queue has different interface – std::queue has front(), but std::priority_queue has top().

#include <stack>
#include <list>
#include <iostream>
#include <string>
#include <queue>

template<typename ContainerType>
void fill_container(ContainerType& cnt)
{
    cnt.push('a');
    cnt.push('0');
    cnt.push('b');
    cnt.push('c');
}

void main()
{
    typedef std::stack< char, std::list<char> > char_list_stack;
    char_list_stack mystack; fill_container(mystack);
    std::cout << "\ncontent in stack:";
    while(mystack.size())
    {
        std::cout << mystack.top() << " ";
        mystack.pop();
    }

    std::queue<char, std::list<char> > myqueue;
    fill_container(myqueue);
    std::cout << "\ncontent in queue:";
    while(myqueue.size())
    {
        std::cout << myqueue.front() << " ";
        myqueue.pop();
    }

    //std::priority_queue<char, std::deque<char> > mypqueue;
    std::priority_queue<char, std::vector<char> > mypqueue;
    fill_container(mypqueue);
    std::cout << "\ncontent in priority_queue:";
    while(mypqueue.size())
    {
        std::cout << mypqueue.top() << " ";
        mypqueue.pop();
    }

}
// cl -EHsc stack.cpp -link -verbose:lib
// content in stack:c b 0 a
// content in queue:a 0 b c
// content in priority_queue:c b a 0

exception in ctor

operator new return NULL if ctor throw exception, this will leads to resource leak, and other possible problem like lock is not released.

// ctor.cpp : test throw exception in ctor.
// cl -EHsc -d1reportSingleClassLayoutCtorWithException ctor.cpp

#define _CRTDBG_MAP_ALLOC
#include <tchar.h>
#include <stdlib.h>
#include <crtdbg.h>
#include <iostream>
#include <iomanip>

class CtorWithException
{
public:
    CtorWithException(bool throw_exception):m_buf(new char[10240])
    {
        std::cout << __FUNCTION__ << " this=" << std::hex << (int)this <<std::endl;
        if (throw_exception)
        throw std::runtime_error("exception in ctor");
    }
    ~CtorWithException()
    {
        delete[] m_buf;
        std::cout << __FUNCTION__ << " this=" << std::hex << (int)this <<std::endl;
    }
private:
    char* m_buf;
};

class TestCtorWithException
{
public:
    TestCtorWithException():m_buf(new char[1024*1024]),m_no_exp(false),m_has_exp(true),m_uninitialized(false)
    {
        std::cout << __FUNCTION__ << " this=" << std::hex << (int)this <<std::endl;
    };
    ~TestCtorWithException()
    {
        delete[] m_buf;
        std::cout << __FUNCTION__ << " this=" << std::hex << (int)this <<std::endl;
    };
private:
    char *m_buf;
    CtorWithException m_no_exp;
    CtorWithException m_has_exp;
    CtorWithException m_uninitialized;
};

int _tmain(int argc, _TCHAR* argv[])
{
    _CrtSetReportMode(_CRT_WARN, _CRTDBG_MODE_FILE);
    _CrtSetReportFile(_CRT_WARN, _CRTDBG_FILE_STDOUT );
    TestCtorWithException* testobj=NULL;
    try
    {
        //TestCtorWithException test_obj;
        testobj=new TestCtorWithException;
    }
    catch (std::exception& e)
    {
        std::cout << e.what() << std::endl;
    }
    std::cout << "new return " << std::hex << testobj << std::endl;
    _CrtDumpMemoryLeaks();
    return 0;
}
// program output
//CtorWithException::CtorWithException this=38cf34
//CtorWithException::CtorWithException this=38cf38
//CtorWithException::~CtorWithException this=38cf34
//exception in ctor
//new return 00000000
//Detected memory leaks!
//Dumping objects ->
//{225} normal block at 0x00530068, 10240 bytes long.
//Data: <                > CD CD CD CD CD CD CD CD CD CD CD CD CD CD CD CD
//{203} normal block at 0x00420040, 1048576 bytes long.
//Data: <                > CD CD CD CD CD CD CD CD CD CD CD CD CD CD CD CD
//      Object dump complete.

boost.program_options crash

A program linking with libboost_program_options-vc90-mt-gd-1_35.lib crashed at desc.add_options(), but the release version worked. At last it turned out to be due to mixed usage of debug version CRT and release version CRT – the program in trouble linked to some release version library in its debug build. The interesting fact is that VC++ 2008 does not complain during compilation, but boost.program_options raised obscure run-time error.

October 27

Join sample on PostgreSQL

Here is a simple example that demonstrate usage of INNER, FULL, LEFT and RIGHT JOIN.

Create 2 tables
create table p1(pid integer, pname varchar(20));
create table p2(pid integer, ptype varchar(10));
insert some data into the tables.
insert into p1(pid, pname) values(1,'p1');
insert into p1(pid, pname) values(2, 'p2');
insert into p1(pid, pname) values(4, 'p4');
insert into p2(pid, ptype) values(1,'t1');
insert into p2(pid, ptype) values(2, 't2');
insert into p2(pid, ptype) values(3, 't3');

select * from p1;

  pid pname
1 1 p1
2 2 p2
3 4 p4


select * from p2;

  pid ptype
1 1 t1
2 2 t2
3 4 t4

inner join is implicit. The following two produce the same result.

select * from p1,p2 where p1.pid=p2.pid;
select * from p1 inner join p2 on p1.pid=p2.pid;

  pid pname pid ptype
1 1 p1 1 t1
2 2 p2 2 t2

select * from p1 left join p2 on p1.pid=p2.pid;

  pid pname pid ptype
1 1 p1 1 t1
2 2 p2 2 t2
3 4 p4    


 

1;"p1";1;"t1"
2;"p2";2;"t2"
4;"p4";;""
select * from p1 right join p2 on p1.pid=p2.pid;

  pid pname pid ptype
1 1 p1 1 t1
2 2 p2 2 t2
3     3 t3


select * from p1 full join p2 on p1.pid=p2.pid;

  pid pname pid ptype
1 1 p1 1 t1
2 2 p2 2 t2
3     3 t3
4 4 p4    

CORBA, COM and WebService

Compare aspects of CORBA and COM

  CORBA COM WebService
interface IDL IDL WSDL
  Interface Repository typelib WSDL
  POA ClassFactory  
  Active Object Map GIT, ROT  
Locate the server Implementation Repository;
IIOP
Interoperable Object Reference (IOR)
Registry UDDI
  CORBA::object to string    
  static invocation interface (SII)    
  dynamic invocation interface IDispatch  
  Dynamic Skeleton Interface (DSI)    
October 19

regex in eclipse

QuickREx provides a nice dialog to help user compose regex pattern, but it does not provide “replace” feature. Regex Util provides nice feature to displace “replaced” result, but it does not allow user to copy result into clipboard, just allows user to preview results. Another not so nice fact is that Regex Util uses “$1”, but boost.regex uses “\1” format.

October 13

custom deleter and shared_ptr

Custom deleter can be used to manage resource other than memory via shared_ptr. Here I elaborated some usage of custom deleter.

#include <iostream>
#include <boost/shared_ptr.hpp>
#include <boost/bind.hpp>
#include <list>
using namespace std;
class custom_deleter_demo
{
public:
    custom_deleter_demo(int data):m_data(data){    }
    void custom_deleter0()
    {
        std::cout << __FUNCTION__ << " data is " << m_data << std::endl;
        delete this;
    }
    void custom_deleter1(int extra_arg)
    {
        std::cout << __FUNCTION__ << " data is " << m_data <<
        ", extra argument is " << extra_arg << std::endl;
        delete this;
    }
    static void static_custom_deleter(custom_deleter_demo* ptr)
    {
        std::cout << __FUNCTION__ << " data is " << ptr->m_data << std::endl;
        delete ptr;
    }
private:
    ~custom_deleter_demo()
    {
        std::cout << __FUNCTION__ << " data is " << m_data << std::endl;
    }
    int m_data;
};

int main() {
    typedef boost::shared_ptr<custom_deleter_demo> ptr_custom_deleter;
    std::list<ptr_custom_deleter> my_list;
    my_list.push_back(ptr_custom_deleter(new custom_deleter_demo(__LINE__),
            custom_deleter_demo::static_custom_deleter));
    custom_deleter_demo* ptr_object=new custom_deleter_demo(__LINE__);
    my_list.push_back(ptr_custom_deleter(ptr_object,
            boost::bind(&custom_deleter_demo::custom_deleter0, ptr_object)) );
    ptr_object=new custom_deleter_demo(__LINE__);
    my_list.push_back(ptr_custom_deleter(ptr_object,
            boost::bind(&custom_deleter_demo::custom_deleter1, ptr_object,__LINE__)) );
    my_list.clear();
    cout << "Demo custom deleter with shared_ptr" << endl;
    return 0;
}

September 30

build boost_1_40_0.7z via Visual Studio 2008 Profession on Windows XP

At first I build it in usual way as I did with boost 1.39, but bjam (Boost.Jam 03.1.17) prints a lot of errors like the following.

cl : Command line error D8022 : cannot open 'bin.v2\libs\math\config\msvc-9.0\debug\link-static\threading-multi\has_long_double_support.obj.rsp'

The file does exist on my disk. At last I resort to the tool File Monitor in order to find out the root cause. File Monitor captured the following error:

1:53:37 PM    cl.exe:6324    OPEN    D:\bin.v2\libs\math\build\msvc-9.0\debug\threading-multi\pch.pch.rsp    PATH NOT FOUND    Options: Open  Access: Read   

It seems that bjam was passing incorrect path to cl.exe. The error is known, and the fix is simple. I created the following batch file and build it successfully. Before starting, I already have d:\boost_1_40_0\bjam.exe in place. size of d:\boost_1_40_0 is 5.56 GB after build completed.

subst x: D:\boost_1_40_0
call "%VS90COMNTOOLS%\..\..\vc\bin\vcvars32.bat"
SET PYTHON_ROOT=C:\Python26
SET PYTHON_VERSION=2.6
SET ICU_PATH=D:\opensource\ICU4C-4_2\icu
cd /d x:\
.\bjam.exe --without-mpi --toolset=msvc-9.0 stage --build-type=complete

 

Command line to build single library:

cd /d D:\opensource\boost\boost_1_40_0\libs\program_options\build
D:\opensource\boost\bjam.exe "-sTOOLS=msvc" link=static threading=multi
D:\opensource\boost\bjam.exe "-sTOOLS=msvc" link=static threading=multi variant=release
D:\opensource\boost\bjam.exe "-sTOOLS=msvc" threading=multi variant=release
D:\opensource\boost\bjam.exe "-sTOOLS=msvc" threading=multi variant=release

Command line from "Building Boost with Visual Studio"

.\bjam --toolset=msvc-9.0 --with-date_time --with-filesystem --with-iostreams -sBZIP2_INCLUDE=C:\bzip2-1.0.5 -sBZIP2_SOURCE=C:\bzip2-1.0.5 -sZLIB_INCLUDE=C:\zlib-1.2.3 -sZLIB_SOURCE=C:\zlib-1.2.3 --with-serialization --with-test --with-thread --build-type=complete stage

Command line from boost-users@lists.boost.org

bjam --layout=versioned --toolset=msvc-9.0 variant=debug threading=multi link=static runtime-link=static stage

September 29

self debugging on XP

It is nice to save some useful information at the point of application crash. The useful methods including call stack and minidump file. Call stack can be obtained by installing exception filter via  AddVectoredExceptionHandler Function, stack trace can be obtained via StackWalk64 Function, and minidump file can be created via MiniDumpWriteDump Function.

WinDbg can open the minidump file. Use .sympath+ <pdb path name> to let WinDBG search this folder before _NT_SYMBOL_PATH. Use .exepath+ command to inform windbg search for executable image file.

September 25

ATL, MFC and scoped_any

I am glad to found Achieve More Reliable Resource Management with Our Custom C++ Classes, but when using it in a unit test project, I got weird compile error. The error points to line 238 of scoped_any.h

DECLARE_SMART_ANY_TYPEDEFS(scoped) and according to other error message it claims “close_rpc_binding” is not valid. After struggling it turned out to be confliction between ATL and MFC. In an ATL project the source file compiled successfully, but in its corresponding unit test project I have to use MFC because CPPUNIT MFCTestRunner is used to produce GUI. At last the problem was solved by moving MFC related headers from stdafx.h to where they are actually required, and disable precompiled header.

There is also a post(Automate Resource Management with shared_ptr) demonstrating resource management via custom deleter and boost::shared_ptr.

September 22

file transfer over asynchronous TCP connection via boost.asio

// another sample that send file name and content to Tcp server, but using asynchronous mode Tcp connection

//
// send a file to a tcp server via boost.asio library
#include <iostream>
#include <boost/asio.hpp>
#include <boost/bind.hpp>
#include <fstream>
#include <sstream>
using boost::asio::ip::tcp;
class async_tcp_client
{
public:
    async_tcp_client(boost::asio::io_service& io_service,
        const std::string& server, const std::string& path)
        : resolver_(io_service),
        socket_(io_service)
    {
        size_t pos = server.find(':');
        if (pos==std::string::npos)
            return;
        std::string port_string = server.substr(pos+1);
        std::string server_ip_or_host = server.substr(0, pos);

        source_file.open(path.c_str(), std::ios_base::binary | std::ios_base::ate);
        if (!source_file)
        {
            std::cout << "failed to open " << path << std::endl;
            return ;
        }
        size_t file_size = source_file.tellg();
        source_file.seekg(0);
        // first send file name and file size to server
        std::ostream request_stream(&request_);
        request_stream << path << "\n"
            << file_size << "\n\n";
        std::cout << "request size:"<<request_.size()<<std::endl;
        // Start an asynchronous resolve to translate the server and service names
        // into a list of endpoints.
        tcp::resolver::query query(server_ip_or_host, port_string);
        resolver_.async_resolve(query,
            boost::bind(&async_tcp_client::handle_resolve, this,
            boost::asio::placeholders::error,
            boost::asio::placeholders::iterator));
    }

private:
    void handle_resolve(const boost::system::error_code& err,
        tcp::resolver::iterator endpoint_iterator)
    {
        if (!err)
        {
            // Attempt a connection to the first endpoint in the list. Each endpoint
            // will be tried until we successfully establish a connection.
            tcp::endpoint endpoint = *endpoint_iterator;
            socket_.async_connect(endpoint,
                boost::bind(&async_tcp_client::handle_connect, this,
                boost::asio::placeholders::error, ++endpoint_iterator));
        }
        else
        {
            std::cout << "Error: " << err.message() << "\n";
        }
    }

    void handle_connect(const boost::system::error_code& err,
        tcp::resolver::iterator endpoint_iterator)
    {
        if (!err)
        {
            // The connection was successful. Send the request.
            boost::asio::async_write(socket_, request_,
                boost::bind(&async_tcp_client::handle_write_file, this,
                boost::asio::placeholders::error));
        }
        else if (endpoint_iterator != tcp::resolver::iterator())
        {
            // The connection failed. Try the next endpoint in the list.
            socket_.close();
            tcp::endpoint endpoint = *endpoint_iterator;
            socket_.async_connect(endpoint,
                boost::bind(&async_tcp_client::handle_connect, this,
                boost::asio::placeholders::error, ++endpoint_iterator));
        }
        else
        {
            std::cout << "Error: " << err.message() << "\n";
        }
    }

    void handle_write_file(const boost::system::error_code& err)
    {
        if (!err)
        {
                if (source_file.eof()==false)
                {
                    source_file.read(buf.c_array(), (std::streamsize)buf.size());
                    if (source_file.gcount()<=0)
                    {
                        std::cout << "read file error " << std::endl;
                        return;
                    }
                    std::cout << "send " <<source_file.gcount()<<" bytes, total:" << source_file.tellg() << " bytes.\n";
                    boost::asio::async_write(socket_,
                        boost::asio::buffer(buf.c_array(), source_file.gcount()),
                        boost::bind(&async_tcp_client::handle_write_file, this,
                        boost::asio::placeholders::error));
                    if (err)
                    {
                        std::cout << "send error:" << err << std::endl;
                        return;
                    }
                }
                else
                    return;
        }
        else
        {
            std::cout << "Error: " << err.message() << "\n";
        }

    }
    tcp::resolver resolver_;
    tcp::socket socket_;
    boost::array<char, 1024> buf;
    boost::asio::streambuf request_;
    std::ifstream source_file;
};
int main(int argc, char* argv[])
{
    if (argc != 3)
    {
        std::cerr << "Usage: " << argv[0] << " <server-address> <file path>" << std::endl;
        std::cerr << "sample: " << argv[0] << " 127.0.0.1:1234 c:\\tmp\\a.txt" << std::endl;
        return __LINE__;
    }
    try
    {
        boost::asio::io_service io_service;
        async_tcp_client client(io_service, argv[1], argv[2]);
        io_service.run();

        std::cout << "send file " << argv[2] << " completed successfully.\n";
//         system("pause");
    }
    catch (std::exception& e)
    {
        std::cerr << e.what() << std::endl;
    }
    return 0;
}

// I also made an asynchronous Tcp server to accept work with above client.

//receive a file from socket client via boost.asio
#include <iostream>
#include <string>
#include <boost/asio.hpp>
#include <fstream>
#include <boost/bind.hpp>
#include <boost/function.hpp>
#include <boost/shared_ptr.hpp>
#include <boost/enable_shared_from_this.hpp>
unsigned short tcp_port = 1234;
class async_tcp_connection: public boost::enable_shared_from_this<async_tcp_connection>
{
public:
    async_tcp_connection(boost::asio::io_service& io_service)
        : socket_(io_service), file_size(0)
    {
    }
    void start()
    {
        std::cout << __FUNCTION__  << std::endl;
        async_read_until(socket_,
            request_buf, "\n\n",
            boost::bind(&async_tcp_connection::handle_read_request,
            shared_from_this(), boost::asio::placeholders::error, boost::asio::placeholders::bytes_transferred));
    }
    boost::asio::ip::tcp::socket& socket() { return socket_; }
private:
    boost::asio::streambuf request_buf;
    size_t file_size;
    std::ofstream output_file;
    boost::asio::ip::tcp::socket socket_;
    boost::array<char, 40960> buf;
    void handle_read_request(const boost::system::error_code& err, std::size_t bytes_transferred)
    {
        if (err)
        {
            return handle_error(__FUNCTION__, err);
        }
        std::cout << __FUNCTION__ << "(" << bytes_transferred << ")"
            << ", in_avail=" << request_buf.in_avail()
            << ", size=" << request_buf.size()
            << ", max_size=" << request_buf.max_size() <<".\n";
        std::istream request_stream(&request_buf);
        std::string file_path;           
        request_stream >> file_path;
        request_stream >> file_size;
        request_stream.read(buf.c_array(), 2); // eat the "\n\n"
        std::cout << file_path << " size is " << file_size << ", tellg=" << request_stream.tellg()<< std::endl;
        size_t pos = file_path.find_last_of('\\');
        if (pos!=std::string::npos)
            file_path = file_path.substr(pos+1);
        output_file.open(file_path.c_str(), std::ios_base::binary);
        if (!output_file)
        {
            std::cout << "failed to open " << file_path << std::endl;
            return;
        }
        // write extra bytes to file
        do
        {
            request_stream.read(buf.c_array(), (std::streamsize)buf.size());
            std::cout << __FUNCTION__ << " write " << request_stream.gcount() << " bytes.\n";
            output_file.write(buf.c_array(), request_stream.gcount());
        } while (request_stream.gcount()>0);
        async_read(socket_, boost::asio::buffer(buf.c_array(), buf.size()),
            boost::bind(&async_tcp_connection::handle_read_file_content,
            shared_from_this(), boost::asio::placeholders::error, boost::asio::placeholders::bytes_transferred));          
    }

    void handle_read_file_content(const boost::system::error_code& err, std::size_t bytes_transferred)
    {
        if (bytes_transferred>0)
        {
            output_file.write(buf.c_array(), (std::streamsize)bytes_transferred);
            std::cout << __FUNCTION__ << " recv " << output_file.tellp() << " bytes."<< std::endl;
            if (output_file.tellp()>=(std::streamsize)file_size)
            {
                return;
            }
        }
        if (err)
        {
            return handle_error(__FUNCTION__, err);
        }
        async_read(socket_, boost::asio::buffer(buf.c_array(), buf.size()),
            boost::bind(&async_tcp_connection::handle_read_file_content,
            shared_from_this(), boost::asio::placeholders::error, boost::asio::placeholders::bytes_transferred));
    }
    void handle_error(const std::string& function_name, const boost::system::error_code& err)
    {
        std::cout << __FUNCTION__ << " in " << function_name <<" due to " << err <<" " << err.message()<< std::endl;
    }
};

class async_tcp_server : private boost::noncopyable
{
public:
    typedef boost::shared_ptr<async_tcp_connection> ptr_async_tcp_connection;

    async_tcp_server(unsigned short port)
        : acceptor_(io_service_, boost::asio::ip::tcp::endpoint(boost::asio::ip::tcp::v4(), port), true)
    {
            ptr_async_tcp_connection new_connection_(new async_tcp_connection(io_service_));
            acceptor_.async_accept(new_connection_->socket(),
            boost::bind(&async_tcp_server::handle_accept, this,new_connection_,
            boost::asio::placeholders::error));
            io_service_.run();
   }   
    void handle_accept(ptr_async_tcp_connection current_connection, const boost::system::error_code& e)
    {
        std::cout << __FUNCTION__ << " " << e << ", " << e.message()<<std::endl;
        if (!e)
        {
            current_connection->start();
            //ptr_async_tcp_connection new_connection_(new async_tcp_connection(io_service_));
            //acceptor_.async_accept(new_connection_->socket(),
            //    boost::bind(&async_tcp_server::handle_accept, this,new_connection_,
            //    boost::asio::placeholders::error));
        }
    }
    ~async_tcp_server()
    {
        io_service_.stop();
    }
private:
    boost::asio::io_service io_service_;
    boost::asio::ip::tcp::acceptor acceptor_;
};

int main(int argc, char* argv[])
{
    try
    {
        if (argc==2)
        {
            tcp_port=atoi(argv[1]);
        }
        std::cout <<argv[0] << " listen on port " << tcp_port << std::endl;
        async_tcp_server *recv_file_tcp_server = new async_tcp_server(tcp_port);
        delete recv_file_tcp_server;
    }
    catch (std::exception& e)
    {
        std::cerr << e.what() << std::endl;
    }
    return 0;
}

file transfer over synchronousTCP connection via boost.asio

//First is a synchronous TCP client that send file name and file content to Tcp Server.

//
// send a file to a tcp server via boost.asio library
#include <iostream>
#include <boost/asio.hpp>
#include <fstream>
#include <sstream>
using boost::asio::ip::tcp;
int main(int argc, char* argv[])
{
    if (argc != 3)
    {
        std::cerr << "Usage: " << argv[0] << " <server-address> <file path>" << std::endl;
        std::cerr << "sample: " << argv[0] << " 127.0.0.1:1234 c:\\tmp\\a.txt" << std::endl;
        return __LINE__;
    }
    try
    {
        std::string server_ip_or_host = argv[1];
        size_t pos = server_ip_or_host.find(':');
        if (pos==std::string::npos)
            return __LINE__;
        std::string port_string = server_ip_or_host.substr(pos+1);
        server_ip_or_host = server_ip_or_host.substr(0, pos);
        boost::asio::io_service io_service;
        tcp::resolver resolver(io_service);
        tcp::resolver::query query(server_ip_or_host, port_string);
        tcp::resolver::iterator endpoint_iterator = resolver.resolve(query);
        tcp::resolver::iterator end;
        tcp::socket socket(io_service);
        boost::system::error_code error = boost::asio::error::host_not_found;
        while (error && endpoint_iterator != end)
        {
            socket.close();
            socket.connect(*endpoint_iterator++, error);
        }
        if (error)
            return __LINE__;
        std::cout << "connected to " << argv[1] << std::endl;
        boost::array<char, 1024> buf;
        std::ifstream source_file(argv[2], std::ios_base::binary | std::ios_base::ate);
        if (!source_file)
        {
            std::cout << "failed to open " << argv[2] << std::endl;
            return __LINE__;
        }
        size_t file_size = source_file.tellg();
        source_file.seekg(0);
        // first send file name and file size to server
        boost::asio::streambuf request;
        std::ostream request_stream(&request);
        request_stream << argv[2] << "\n"
            << file_size << "\n\n";
        boost::asio::write(socket, request);
        std::cout << "start sending file content.\n";
        for (;;)
        {

            if (source_file.eof()==false)
            {
                source_file.read(buf.c_array(), (std::streamsize)buf.size());
                if (source_file.gcount()<=0)
                {
                    std::cout << "read file error " << std::endl;
                    return __LINE__;
                }
                boost::asio::write(socket, boost::asio::buffer(buf.c_array(),
                    source_file.gcount()),
                    boost::asio::transfer_all(), error);
                if (error)
                {
                    std::cout << "send error:" << error << std::endl;
                    return __LINE__;
                }
            }
            else
                break;
        }
        std::cout << "send file " << argv[2] << " completed successfully.\n";
    }
    catch (std::exception& e)
    {
        std::cerr << e.what() << std::endl;
    }
    return 0;
}

 

// next is a Tcp server working in synchronous mode that accept file from above Tcp client. This sample also demonstrate usage of async_read_until(). The trick with async_read_until is that it will read more than I want and those extra bytes must be properly handled.

//receive a file from socket client via boost.asio
#include <ctime>
#include <iostream>
#include <string>
#include <boost/asio.hpp>
#include <fstream>
#include <sstream>
unsigned short tcp_port = 1234;

int main(int argc, char* argv[])
{
    boost::array<char, 1024> buf;
    size_t file_size = 0;
    try
    {
        if (argc==2)
        {
            tcp_port=atoi(argv[1]);
        }
        std::cout <<argv[0] << " listen on port " << tcp_port << std::endl;
        boost::asio::io_service io_service;
        boost::asio::ip::tcp::acceptor acceptor(io_service, boost::asio::ip::tcp::endpoint(boost::asio::ip::tcp::v4(), tcp_port));
        boost::system::error_code error;
        boost::asio::ip::tcp::socket socket(io_service);
        acceptor.accept(socket);
        std::cout << "get client connection." << std::endl;
        boost::asio::streambuf request_buf;
        boost::asio::read_until(socket, request_buf, "\n\n");
        std::cout<< "request size:" << request_buf.size() << "\n";
        std::istream request_stream(&request_buf);
        std::string file_path;           
        request_stream >> file_path;
        request_stream >> file_size;
        request_stream.read(buf.c_array(), 2); // eat the "\n\n"

        std::cout << file_path << " size is " << file_size << std::endl;
        size_t pos = file_path.find_last_of('\\');
        if (pos!=std::string::npos)
            file_path = file_path.substr(pos+1);
        std::ofstream output_file(file_path.c_str(), std::ios_base::binary);
        if (!output_file)
        {
            std::cout << "failed to open " << file_path << std::endl;
            return __LINE__;
        }

        // write extra bytes to file
        do
        {
            request_stream.read(buf.c_array(), (std::streamsize)buf.size());
            std::cout << __FUNCTION__ << " write " << request_stream.gcount() << " bytes.\n";
            output_file.write(buf.c_array(), request_stream.gcount());
        } while (request_stream.gcount()>0);

        for (;;)
        {
            size_t len = socket.read_some(boost::asio::buffer(buf), error);
            if (len>0)
                output_file.write(buf.c_array(), (std::streamsize)len);
            if (output_file.tellp()== (std::fstream::pos_type)(std::streamsize)file_size)
                break; // file was received
            if (error)
            {
                std::cout << error << std::endl;
                break;
            }
        }
        std::cout << "received " << output_file.tellp() << " bytes.\n";
    }
    catch (std::exception& e)
    {
        std::cerr << e.what() << std::endl;
    }
    return 0;
}

July 26

DevPartner 9.02 coverage analysis

DevPartner failed to instrument two projects with “Error and Coverage” type, the only common fact is that there is a medium size CPP file in thos projects, one is around 40k, another is around 64k. It seems to be bug because those two projects can be instrumented successfully with “Error detection” or “Coverage or performance” type, and the debug configuration is also working, at last a colleague found a workaround with release configuration – disable optimization.

July 04

usage of boost::program_options::parse_config_file

I just need to create options_description as usual, and prepare configuration file in the following format:

#include <boost/program_options.hpp>
namespace po = boost::program_options;

std::stringstream ss;
ss  << "CurrentX=1234"<<std::endl
    <<"CurrentY=456"<<std::endl;
    po::options_description desc("Allowed options");
    desc.add_options()
        ("help,h", "produce help message")
        ("CurrentX", po::value<int>(), "set CurrentX")
        ("CurrentY", po::value<int>(), "set CurrentY")
        ;

    po::variables_map vm;       
    po::store(po::parse_config_file(ss, desc, true), vm);