求教一个C++(boost asio)服务器开发方面的问题

170 views
Skip to first unread message

nebuladream

unread,
Oct 24, 2009, 5:52:04 AM10/24/09
to TopLanguage
在今天的开发当中,我们再次遇到了一个几乎无法解决的诡异问题。其问题描述如下,希望群里的大牛给予指点:
程序已经在我的机器上运行成功了,现在要移植到基于centos的64位服务器上。
我们将源代码成功编译后,运行时发生了Segmentation fault的错误提示。使用GDB进行跟踪发现错误出现在类构造的初始化列表当中。
其中 boost::asio::ip::tcp::socket m_socket; m_socket 在进行初始化时的代码为 m_socket
(*pio),参数pio 为io_service对象的指针,我们可以保证其指针的有效性(在该语句的上一条语句中已经进行了初始化的操作)。
在跟踪进入 m_socket对象的构造函数之后,我们发现在程序运行到/root/boost_1_39_0/boost/asio/detail/
service_registry.hpp:208 地方发生了Segmentation fault的错误提示。
我们怀疑是boost库本身的问题,于是运行了其官方提供的例子。
例子当中包括对于 boost::asio::ip::tcp::socket对象的初始化操作,但例子程序可以正常运行。

nebuladream

unread,
Oct 24, 2009, 5:53:59 AM10/24/09
to TopLanguage

下面是我们使用GDB调试的代码:
Breakpoint 1, CProxy (this=0x7fffa648b4e0, filename=0x7fffa648bbe5
"config.txt") at proxy.cpp:51
51 pIConnect pcconnect(new CCconnect(&ioOwn, ip.c_str(), port.c_str
(), this, regist,response));
(gdb) s
CCconnect (this=0x149f8060, pio=0x7fffa648b4ec, host=
{static npos = 18446744073709551615, _M_dataplus =
{<std::allocator<char>> = {<__gnu_cxx::new_allocator<char>> = {<No
data fields>}, <No data fields>}, _M_p = 0x7fffa648b440
"\030\200\237\024"}}, port=
{static npos = 18446744073709551615, _M_dataplus =
{<std::allocator<char>> = {<__gnu_cxx::new_allocator<char>> = {<No
data fields>}, <No data fields>}, _M_p = 0x7fffa648b450 "H
\200\237\024"}}, ph=0x7fffa648b4e0,
msg_register={len = 0, cmd = 32, res = 0}, msg_response={len = 0,
cmd = 33, res = 0}) at cconnect.cpp:17
17 ,m_is_informed(-1)
(gdb) s
CInterfaceConnect (this=0x149f8060) at interfaceconnect.h:35
35 CInterfaceConnect(){}
(gdb) s
enable_shared_from_this (this=0x149f806c) at /root/boost_1_39_0/boost/
smart_ptr/enable_shared_from_this.hpp:29
29 {
(gdb) s
weak_ptr (this=0x149f806c) at /root/boost_1_39_0/boost/smart_ptr/
weak_ptr.hpp:39
39 weak_ptr(): px(0), pn() // never throws in 1.30+
(gdb) s
weak_count (this=0x149f8074) at /root/boost_1_39_0/boost/smart_ptr/
detail/shared_count.hpp:313
313 weak_count(): pi_(0) // nothrow
(gdb) s
318 }
(gdb) s
weak_ptr (this=0x149f806c) at /root/boost_1_39_0/boost/smart_ptr/
weak_ptr.hpp:40
40 {
(gdb) s
basic_stream_socket (this=0x149f807c, io_service=@0x7fffa648b4ec)
at /root/boost_1_39_0/boost/asio/basic_stream_socket.hpp:70
70 : basic_socket<Protocol, StreamSocketService>(io_service)
(gdb) s
basic_socket (this=0x149f807c, io_service=@0x7fffa648b4ec)
at /root/boost_1_39_0/boost/asio/basic_socket.hpp:67
67 : basic_io_object<SocketService>(io_service)
(gdb) s
basic_io_object (this=0x149f807c, io_service=@0x7fffa648b4ec)
at /root/boost_1_39_0/boost/asio/basic_io_object.hpp:72
72 : service(boost::asio::use_service<IoObjectService>
(io_service))
(gdb) s
noncopyable (this=0x149f807c) at /root/boost_1_39_0/boost/
noncopyable.hpp:24
24 noncopyable() {}
(gdb) s
boost::asio::use_service<boost::asio::stream_socket_service<boost::asio::ip::tcp>
> (ios=@0x7fffa648b4ec)
at /root/boost_1_39_0/boost/asio/impl/io_service.ipp:195
195 return ios.service_registry_->template use_service<Service>();
(gdb) s
boost::asio::detail::service_registry::use_service<boost::asio::stream_socket_service<boost::asio::ip::tcp>
>
(this=0x149f3010) at /root/boost_1_39_0/boost/asio/detail/
service_registry.hpp:94
94 boost::asio::detail::mutex::scoped_lock lock(mutex_);
(gdb) s
scoped_lock (this=0x7fffa648b000, m=@0x149f3014) at /root/boost_1_39_0/
boost/asio/detail/scoped_lock.hpp:34
34 : mutex_(m)
(gdb) s
noncopyable (this=0x7fffa648b000) at /root/boost_1_39_0/boost/
noncopyable.hpp:24
24 noncopyable() {}
(gdb) s
scoped_lock (this=0x7fffa648b000, m=@0x149f3014) at /root/boost_1_39_0/
boost/asio/detail/scoped_lock.hpp:36
36 mutex_.lock();
(gdb) s
boost::asio::detail::posix_mutex::lock (this=0x149f3014)
at /root/boost_1_39_0/boost/asio/detail/posix_mutex.hpp:71
71 int error = ::pthread_mutex_lock(&mutex_);
(gdb) s
72 if (error != 0)
(gdb) s
80 }
(gdb) s
scoped_lock (this=0x7fffa648b000, m=@0x149f3014) at /root/boost_1_39_0/
boost/asio/detail/scoped_lock.hpp:37
37 locked_ = true;
(gdb) s
boost::asio::detail::service_registry::use_service<boost::asio::stream_socket_service<boost::asio::ip::tcp>
>
(this=0x149f3010) at /root/boost_1_39_0/boost/asio/detail/
service_registry.hpp:97
97 boost::asio::io_service::service* service = first_service_;
(gdb) s
98 while (service)
(gdb) s
100 if (service_id_matches(*service, Service::id))
(gdb) s
boost::asio::detail::service_registry::service_id_matches<boost::asio::stream_socket_service<boost::asio::ip::tcp>
> (service=@0x149f306000007fff) at /root/boost_1_39_0/boost/asio/
detail/service_registry.hpp:208
208 && *service.type_info_ == typeid(typeid_wrapper<Service>);
(gdb) s

Program received signal SIGSEGV, Segmentation fault.
0x000000000044c97a in
boost::asio::detail::service_registry::service_id_matches<boost::asio::stream_socket_service<boost::asio::ip::tcp>
> (service=@0x149f306000007fff)
at /root/boost_1_39_0/boost/asio/detail/service_registry.hpp:208
208 && *service.type_info_ == typeid(typeid_wrapper<Service>);

Shuo Chen

unread,
Oct 24, 2009, 6:22:47 AM10/24/09
to TopLanguage
贴最小的能独立编译的复现错误的代码。并说明编译器的版本和参数。
没有代码,光有gdb会话,无法分析。

nebuladream

unread,
Oct 24, 2009, 6:37:18 AM10/24/09
to pon...@googlegroups.com

gcc 4.1, 下面是代码内容:

// 这是main函数当中的调用语句

CProxy proxy(argv[1]);

// 这里是proxy的构造函数

CProxy::CProxy(const char*filename)

{

ifstream input;

string ip;

string port;

inu32 destid;

input.open(filename, ios::in);

input >> proxyid;

while (true)

{

input >> ip;

if (input.eof() || ip == "END_OF_CONNECTION")

{

break;

}

input >> port;

S_MsgHead regist;

S_MsgHead response;

regist.cmd = msg_proxy_gamelogic_register;

response.cmd = msg_gamelogic_proxy_response;

input >> destid;

response.res = destid;

// 程序执行到这条语句发生了段错误,其中ioOwn是该类的成员变量。

new CCconnect(&ioOwn, ip, port, this, regist,response));

}

}


// 这里是CCconnect的构造函数。

// 我们跟踪进入 m_socket之后发生了段错误,如问题描述当中所示。

CCconnect::CCconnect

( boost::asio::io_service* pio , std::string host , std::string port , CInterfaceHandler* ph ,S_MsgHead msg_register ,S_MsgHead msg_response)

:m_socket(*pio) ,m_pio_service_own(pio),m_lRecv( 0 ),m_pHandler(ph)

,m_inum_reconnect(0)

,m_flag_connect (-1)

,m_timer_connect( *pio )

,m_is_informed(-1)

cout << “cconnect construct” << endl;// 这条语句没有被打印

memset( &m_oMsgHead, 0, sizeof( m_oMsgHead ) );

memset( m_szRecv, 0, sizeof( m_szRecv ) );

m_strRecv = "";


m_strhost = host ;

m_strport = port ;

m_oMsg_register = msg_register;

m_oMsg_response = msg_response;


}


makefile文件内容:

# compiler

c++ := c++

# options

c++flags := -I/home/nebuladream/boost_1_39_0 -g -c

# source code path

src_path := ./

#lib_path := /usr/local/lib/

lib_path := /home/nebuladream/boost_1_39_0/stage/lib/

# run

run := $(c++) $(c++flags)

#$(cc) $(cflags) $^ -o $@

proxy : main.o accept.o proxy.o cconnect.o sconnect.o \

$(lib_path)libboost_system-gcc41-mt-d-1_39.a $(lib_path)libboost_thread-gcc41-mt-d-1_39.a \

$(lib_path)libboost_python-gcc41-mt-d-1_39.a

$(c++) -g -o $@ $^ -lpthread

main.o : main.cpp

$(run) $^

accept.o : $(src_path)accept.cpp

$(run) $^

proxy.o : $(src_path)proxy.cpp

$(run) $^

sconnect.o : $(src_path)sconnect.cpp

$(run) $^

cconnect.o : $(src_path)cconnect.cpp

$(run) $^

clean :

rm main.o accept.o proxy.o cconnect.o sconnect.o proxy

cleantemp :

rm main.o accept.o proxy.o cconnect.o sconnect.o


Shuo Chen

unread,
Oct 24, 2009, 6:49:39 AM10/24/09
to TopLanguage
ioOwn 的类型是什么?在哪儿初始化的?
m_socket 的类型是什么?

在列成员函数的时候,好歹给个头文件嘛。

另外,用系统自带的boost库有没有问题?

Fei Yan

unread,
Oct 24, 2009, 6:55:46 AM10/24/09
to pon...@googlegroups.com
根据你的gdb输出至少可以发现一个基本的问题,即你的成员初始化列表的顺序起码是有问题的,否则怎么会在后边的先初始化
强烈怀疑你的ioOwn是否是个完全初始化的io_service

如果是自己定义并初始化,是否调用了use_service

2009/10/24 nebuladream <nebul...@gmail.com>

Wenbo Yang

unread,
Oct 24, 2009, 6:57:06 AM10/24/09
to pon...@googlegroups.com
看不懂这段代码。不过将 32 位的程序移植到 64 位机器上的时候,首先要考虑的就是字长的问题。尤其是指针,如果在 64 位下使用 32 位的指针,那肯定会有段错误的。有时候指针会被自动扩展,所以没那么明显发觉。你可以 dump 一下汇编代码,看看对应的地方指针有没有被自动地使用 cltq/cdqe 转换。

文博
2009/10/24 nebuladream <nebul...@gmail.com>

--
Wenbo YANG

Homepage ---> http://solrex.cn
Blog | Solrex Shuffling ---> http://blog.solrex.cn

Shuo Chen

unread,
Oct 24, 2009, 7:03:07 AM10/24/09
to TopLanguage
编译参数加上 -Wall, 看看有什么警告。另外你的参数和编译boost是一样的吗?

nebuladream

unread,
Oct 24, 2009, 7:05:04 AM10/24/09
to pon...@googlegroups.com
ioOwn的类型是一个io_service,其为CProxy的成员,我们也试过在这条语句前面加上
boost::asio::io_service iotemp;
然后使用&iotemp替换ioOwn,但是同样的问题还是会发生。
---
IT民工一个


2009/10/24 Shuo Chen <gian...@gmail.com>

nebuladream

unread,
Oct 24, 2009, 7:06:57 AM10/24/09
to pon...@googlegroups.com
恩,是一样的,我用了同样的makefile,仅仅修改了部分模块的名称,而编译参数是不变的。
---
IT民工一个


2009/10/24 Shuo Chen <gian...@gmail.com>

Fei Yan

unread,
Oct 24, 2009, 7:21:05 AM10/24/09
to pon...@googlegroups.com
不妨先验证下这两个方面是否都是正确的:
1>对于64位应用程序代码,可能需要手工加 -m64(貌似老版本的GCC是不会自动完成的)
2> boost的64位编译也需要格外注意,你编译的代码是否config.hpp是正确的
参考boost.bjam关于GNU Compiler的说明
http://www.boost.org/boost-build2/doc/html/bbv2/reference/tools.html

In order to compile 64-bit applications, you have to specify address-model=64, and the instruction-set feature should refer to a 64 bit processor. Currently, those include nocona, opteron, athlon64 and athlon-fx.

Shuo Chen

unread,
Oct 24, 2009, 7:32:42 AM10/24/09
to TopLanguage
直接在main里调用 new CConnect(xxx), 会发生什么?
CProxy 有没有基类?有哪些成员?类型是什么?
CConnect 有没有基类?有哪些成员?类型是什么?

一点一点挤牙膏....

Fei Yan

unread,
Oct 24, 2009, 7:33:33 AM10/24/09
to pon...@googlegroups.com
查了一下1.40的代码,发现这个地方的代码已经有所改动,主要是加了指针检查:
200 #if !defined(BOOST_ASIO_NO_TYPEID)
201   // Check if a service matches the given id.
202   template <typename Service>
203   static bool service_id_matches(
204       const boost::asio::io_service::service& service,
205       const boost::asio::detail::service_id<Service>& /*id*/)
206   {
207     return service.type_info_ != 0

208       && *service.type_info_ == typeid(typeid_wrapper<Service>);

209   }
你不妨参照新版本的检查,在你最后一个地方加一个breakpoint,然后查看service.type_info_对应的地址是否是合法的64位地址;你的segment fault应该是由于指针解引用引起的,而这个地址的初始化是在这里(会在service构造的时候调用):
183   template <typename Service>
184   void init_service_id(boost::asio::io_service::service& service,
185       const boost::asio::detail::service_id<Service>& /*id*/)
186   {
187     service.type_info_ = &typeid(typeid_wrapper<Service>);
188     service.id_ = 0;
189   }

那个wrapper类则是个很简单的空模板类,用于RTTI标示ID的(不同的模板参数会生成不同的类,从而对应的typeid也不一样):
 46 template <typename T>
 47 class typeid_wrapper {};

我手头没有1.39的代码,不过对应部分应该差不多,你不妨在前两个标记的地方设置breakpoints查查看


Fei Yan

unread,
Oct 24, 2009, 7:36:58 AM10/24/09
to pon...@googlegroups.com
2009/10/24 Shuo Chen <gian...@gmail.com>

直接在main里调用 new CConnect(xxx), 会发生什么?
CProxy 有没有基类?有哪些成员?类型是什么?
CConnect 有没有基类?有哪些成员?类型是什么?

一点一点挤牙膏....


说的很不错,一语道破调试排错的玄机,就是 猜测+挤牙膏式的排除,能否一下猜到电子上,主要还是靠积累

 

Shuo Chen

unread,
Oct 24, 2009, 8:28:49 AM10/24/09
to TopLanguage
下面这段程序在你的环境下有段错误吗?

class Connect
{
public:
Connect(boost::asio::io_service* pio)
: m_socket(*pio)
{
cout << "OK" << endl;
}
boost::asio::ip::tcp::socket m_socket;
};

class Proxy
{
public:
Proxy()
{
new Connect(&ioOwn);
}
boost::asio::io_service ioOwn;
};

int main()
{
Proxy p;
}


On Oct 24, 7:05 pm, nebuladream <nebuladr...@gmail.com> wrote:
> ioOwn的类型是一个io_service,其为CProxy的成员,我们也试过在这条语句前面加上
> boost::asio::io_service iotemp;
> 然后使用&iotemp替换ioOwn,但是同样的问题还是会发生。
> ---
> IT民工一个
>
> 2009/10/24 Shuo Chen <giantc...@gmail.com>

Shuo Chen

unread,
Oct 24, 2009, 8:37:19 AM10/24/09
to TopLanguage
我估计 1.39 也是有的,你看前面 gdb 的log:

detail/service_registry.hpp:208
208 && *service.type_info_ == typeid
(typeid_wrapper<Service>);
(gdb) s

第 208 行以 && 开头,并不完整,前面估计就有 service.type_info_ != 0。
LZ 给的上下文太少了。

On Oct 24, 7:33 pm, Fei Yan <skyscribe...@gmail.com> wrote:
> 查了一下1.40的代码,发现这个地方的代码已经有所改动,主要是加了指针检查:
> 200 #if !defined(BOOST_ASIO_NO_TYPEID)
> 201 // Check if a service matches the given id.
> 202 template <typename Service>
> 203 static bool service_id_matches(
> 204 const boost::asio::io_service::service& service,
> 205 const boost::asio::detail::service_id<Service>& /*id*/)
> 206 {

> *207 return service.type_info_ != 0
> 208 && *service.type_info_ == typeid(typeid_wrapper<Service>);*


> 209 }
> 你不妨参照新版本的检查,在你最后一个地方加一个breakpoint,然后查看service.type_info_对应的地址是否是合法的64位地址;你的segment
> fault应该是由于指针解引用引起的,而这个地址的初始化是在这里(会在service构造的时候调用):
> 183 template <typename Service>
> 184 void init_service_id(boost::asio::io_service::service& service,
> 185 const boost::asio::detail::service_id<Service>& /*id*/)
> 186 {

> *187 service.type_info_ = &typeid(typeid_wrapper<Service>);*


> 188 service.id_ = 0;
> 189 }
>
> 那个wrapper类则是个很简单的空模板类,用于RTTI标示ID的(不同的模板参数会生成不同的类,从而对应的typeid也不一样):
> 46 template <typename T>

> * 47 class typeid_wrapper {};
>
> *我手头没有1.39的代码,不过对应部分应该差不多,你不妨在前两个标记的地方设置breakpoints查查看*
> *

jrckkyy

unread,
Oct 29, 2009, 12:01:07 PM10/29/09
to pon...@googlegroups.com
段错误,多半是由于越界访问,CCconnect 堆上建立对象构造时传入的参数可能有问题,为什么不把指针改为引用呢,最好是能用引用就用引用。

2009/10/24 nebuladream <nebul...@gmail.com>



--

http://hi.baidu.com/jrckkyy

选择百度博客的原因只为更快的CRUD思维上的碎片

Fuzhou Chen

unread,
Oct 29, 2009, 2:14:15 PM10/29/09
to pon...@googlegroups.com
上下文确实太少,不过多少还能有点内容。试试看能不能抛砖引玉。
 
 
因为公司的限制我不能看boost的代码。所以只能从这个trace考虑:
 
a) 首先从地址上看,service指针指向的地址有点突兀,别的地址要么是高位栈地址的0x7fffxxxxxxxx,要么是低位的堆0x149fxxxx,只有它孤零零地处在中间的0x149fxxxxxxxxxxx,不符合地址分配的常识,值得怀疑。
 
io_service=@0x7fffa648b4ec
this=0x149f3014
service=@0x149f306000007fff
this=0x7fffa648b000
 
 
b) gdb已经肯定crash发生在/root/boost_1_39_0/boost/asio/detail/service_registry.hpp:208
 
208           && *service.type_info_ == typeid(typeid_wrapper<Service>);
 
c) 我看到service_registry.hpp:97有这一句:
 
97          boost::asio::io_service::service* service = first_service_;

 
结合后面98行的while,以及执行路径从100行直接跳到208行的行为,我认为这里的 *service指针应该是一个迭代器。而迭代器越界的行为是可能发生的。
 
现在假设这个可能性成立,从楼主贴出来的trace来看,这段代码在第一次进入循环的时候已经crash了,所以我会认为first_service_的初始化情况非常值得怀疑。所以我首先会用gdb的x命令查阅段错误发生时的service的内容。如果确实像是个非法值,那么我会从头开始调试,用display命令设定检查 boost::asio::io_service::service* service的值,然后一步一步地跟踪,看看到哪一步出问题。
 
至于是不是boost本身的bug,我认为得等到能确定是first_service_的问题后才能开始看代码验证,现在做结论为时尚早。
 
 
 
注意:这里的考虑中有一个漏洞:有谁能把service_registry.hpp:208行之前的完整语句贴出来?我已经很久没用gdb了,不记得gdb是否能够把crash精确确定到分句。如果crash发生在208行的前半句,那么上面的分析就得推翻。
 
最后,呼唤boost高手帮忙。
 
 
(gdb) s
boost::asio::detail::service_registry::use_service<boost::asio::stream_socket_service<boost::asio::ip::tcp> >
   (this=0x149f3010) at /root/boost_1_39_0/boost/asio/detail/service_registry.hpp:97

97          boost::asio::io_service::service* service = first_service_;
(gdb) s
98          while (service)
(gdb) s
100           if (service_id_matches(*service, Service::id))
(gdb) s
boost::asio::detail::service_registry::service_id_matches<boost::asio::stream_socket_service<boost::asio::ip::tcp> > (service=@0x149f306000007fff) at /root/boost_1_39_0/boost/asio/detail/service_registry.hpp:208
208           && *service.type_info_ == typeid(typeid_wrapper<Service>);
(gdb) s

Program received signal SIGSEGV, Segmentation fault.
0x000000000044c97a in
boost::asio::detail::service_registry::service_id_matches<boost::asio::stream_socket_service<boost::asio::ip::tcp> > (service=@0x149f306000007fff)
   at /root/boost_1_39_0/boost/asio/detail/service_registry.hpp:208

208           && *service.type_info_ == typeid(typeid_wrapper<Service>);
 

 
2009/10/24 Shuo Chen <gian...@gmail.com>



--
《采莲》·江南

为卿采莲兮涉水,为卿夺旗兮长战。为卿遥望兮辞宫阙,为卿白发兮缓缓歌。

另抄自蒜头的评论:http://www.douban.com/review/1573456/

  且祭一束紫琳秋,为一段落花流水的传说
  且饮一杯青花酒,为一场几多擦肩的错过
  且焚一卷旖旎念,为一腔抛付虚无的惜怜
  且歌一曲罢箜篌,为一刻良辰春宵的寂寞

Fuzhou Chen

unread,
Oct 29, 2009, 2:42:43 PM10/29/09
to pon...@googlegroups.com
纠正一下:service的地址不是在当中,而是在更高位的地址区,不像在栈空间之内,但是推论不变:这个变量的地址仍然值得怀疑。

2009/10/29 Fuzhou Chen <cppo...@gmail.com>

nebuladream

unread,
Oct 29, 2009, 10:23:05 PM10/29/09
to pon...@googlegroups.com

感谢大家的留言,我也在一直在着手解决上述的问题。这几天我写了一些相关的代码来验证我的想法,又发现了如下诡异的问题。我在四楼贴出的那段段代码,如果在CProxy类的声明当作加入一个socket对象的声明,我发现上述代码将不会在CConnect类初始化列表当中发生段错误,但是程序会在接下来的主动连接代码中发生问题。

boost::asio::ip::tcp::resolver resolver( *m_pio_service_own );

boost::asio::ip::tcp::resolver::query query( m_strhost, m_strport );

boost::asio::ip::tcp::resolver::iterator endpoint_iterator= resolver.resolve(query);

// 非常奇怪,在iterator初始化过程当中将会产生段错误。

boost::asio::ip::tcp::resolver::iterator end;

boost::system::error_code error = boost::asio::error::host_not_found;

while (error && endpoint_iterator != end)

{

m_socket.close();

m_socket.connect(*endpoint_iterator++, error);

}


我又尝试着写出如下代码,试图发现产生段错误原因,但是奇怪的是下面这段代码却可以正常的运行通过!可以说下面程序的基本结构已经与我的程序及其相似了。只是网络层并没有我的程序那么复杂(而出问题的那段代码与下面这段代码唯一的不同就是初始化列表当作多加入了几个初始化成员变量)。之后,我将test换成调用问题代码的CConnect,就会在前面所说的

// 非常奇怪,在iterator初始化过程当中将会产生段错误。

boost::asio::ip::tcp::resolver::iterator end;

地方发生段错误!!!


如果本周这个问题还是不能解决,我已经开始考虑重写代码了……这件事告诉我以后开发时候还是使用64位系统比较稳妥,发现问题可以及时找到。


//main.cpp

#include "test.h"

int main()

{

test t;

t.run();

return 0;

}


//test.h

#ifndef TEST_H

#define TEST_H

#endif

#include "cconnect.h"

#include "interfacehandler.h"

#include <boost/thread.hpp>

#include <string>

#include <iostream>

#include <vector>

using namespace std;

// CInterfaceConnect是网络层抽象的接口。

typedef boost::shared_ptr<CInterfaceConnect> pIConnect;

// CinterfaceHandler是数据包处理层的抽象接口。

class test : public CInterfaceHandler

{

private:

boost::asio::io_service ioOwn;

vector< boost::shared_ptr< boost::thread > > m_vt_Thread;

public:

~test(){}

test();

void run();

boost::asio::io_service* get_pio( void ){return &ioOwn;}

void handle( std::string sdata ,pIConnect pcon );

};

// test.cpp

#include "test.h"

#include "timer.h"

test::test()

{

pIConnect pconnect(new CCconnect( &ioOwn , "192.168.1.77" , "80" , this ) );

pconnect->run();

}

void test::run()

{

new CTimer( ioOwn );

for( size_t x = 0 ; x < 5 ; ++ x )

{

boost::shared_ptr< boost::thread > pnewown( new boost::thread( boost::bind( &boost::asio::io_service::run, &ioOwn ) ) );

m_vt_Thread.push_back( pnewown );

}

std::cout << "process run ... " << std::endl;

for( size_t y = 0 ; y < m_vt_Thread.size() ; ++ y )

m_vt_Thread[ y ]->join();

}

void test::handle( std::string sdata ,pIConnect pcon )

{

cout << "handle function." << endl;

}


// CConnect.cpp代码

#include "cconnect.h"

// 这个构造函数仅仅比出问题的构造函数少了几个初始化变量,而这几个初始化变量全部都是int类型

CCconnect::CCconnect(boost::asio::io_service* pio , std::string h , std::string p , CInterfaceHandler* ph ):pioOwn(pio), m_pHandler(ph),m_socket(*pio)

{

host = h ;

port = p ;

}


void CCconnect::run( void )

{

Connect();

}

// 这一段是主动连接服务器的程序。boost库的example中就是这么写的。

void CCconnect::Connect( void )

{

cout << "connect." << endl;

boost::asio::ip::tcp::resolver resolver( *pioOwn );

boost::asio::ip::tcp::resolver::query query( host, port );

boost::asio::ip::tcp::resolver::iterator endpoint_iterator= resolver.resolve(query);

boost::asio::ip::tcp::resolver::iterator end;

boost::system::error_code error = boost::asio::error::host_not_found;

while (error && endpoint_iterator != end)

{

m_socket.close();

m_socket.connect(*endpoint_iterator++, error);

}

if (error)

{

#ifdef _DEBUG_DISPLAY_

std::cout << "------CConnect:error" << std::endl;

#endif

Connect() ;

}

else

{

#ifdef _DEBUG_DISPLAY_

std::cout << "------Cconnect:start to send register package" << std::endl;

#endif

Send_RegisterMsg() ;

}

}

void CCconnect:: Send_RegisterMsg()

{

try

{

#ifdef _DEBUG_DISPLAY_

std::cout << "------CCconnect:: Send_RegisterMsg() " << std::endl;

#endif

boost::asio::async_write( m_socket, boost::asio::buffer( buffer , sizeof(1024) ),

boost::bind( &CCconnect::Receive, shared_from_this(), boost::asio::placeholders::error ) );

}

catch (exception& e)

{

std::cerr<< "CCconnect:: Send_RegisterMsg() :"<< e.what() ;

}

catch (...)

{

std::cerr << "CCconnect:: Send_RegisterMsg : oh no \n" ;

}

}

void CCconnect::Receive(const boost::system::error_code& error)

{

Recv_MsgHead();

}

void CCconnect::Recv_MsgHead( void )

{

#ifdef _DEBUG_DISPLAY_

std::cout << "------CCconnect:: Recv_MsgHead" << std::endl;

#endif

boost::asio::async_read( m_socket, boost::asio::buffer( buffer, 1000 ),

boost::asio::transfer_at_least( 1 ),

boost::bind( &CCconnect::Recv_MsgHead_End, shared_from_this(),boost::asio::placeholders::error, boost::asio::placeholders::bytes_transferred ) );

}

void CCconnect::Recv_MsgHead_End( const boost::system::error_code& error, std::size_t bytes_transferred )

{

string data = buffer;

( m_pHandler->get_pio() )->post( boost::bind ( &CInterfaceHandler::handle, m_pHandler, data, shared_from_this() ) ) ;

Recv_MsgHead();

}


---
IT民工一个


2009/10/30 Fuzhou Chen <cppo...@gmail.com>

Fuzhou Chen

unread,
Oct 29, 2009, 10:57:52 PM10/29/09
to pon...@googlegroups.com
我最担心的是问题根源还没有真的找到。重写代码或许可以绕开之前的问题,但难保不会再后来遇到别的。如果时间允许的话,我比较倾向于继续追下去。如果不允许,或许我们可以考虑把一段最小能重现的代码留在这里作为讨论。毕竟这里boost有经验的人还要多一些,实在不行还可以继续往别的mail thread上发。
 
另外作为重现时常常需要考虑的情况,这些配置也要考虑的:
 
a) 别的版本的64位Linux是否也能稳定重现?
b) 所有这些诡异问题在32位Linux上是否都无法重现?
 
就我个人经验,我推荐测试系统中应该至少包含一个Suse版本,因为我记得Suse的Glibc增加了边界保护的代码,有些别的系统上直接段错误的情况在Suse上可以从命令行上看到一些有用的信息。别的版本现状我不清楚,不过Fedora到4之前应该没有这个机制,希望现在的12能有改进。
2009/10/29 nebuladream <nebul...@gmail.com>

nebuladream

unread,
Oct 29, 2009, 11:05:57 PM10/29/09
to pon...@googlegroups.com
a) 别的版本的64位Linux是否也能稳定重现?

是的,不仅在服务器的centos 64位上,我刚刚在我开发的机器上面安装了ubuntu9.04 64位,该状况的确会稳定的发生。

b) 所有这些诡异问题在32位Linux上是否都无法重现?

从目前来看我们在ubuntu32(包括9.04和9.10版本)以及 Windows xp(32位)上面没有发现上述的问题。

pi1ot

unread,
Oct 29, 2009, 11:06:12 PM10/29/09
to TopLanguage
公司限制?boost的授权已经很宽松了吧

On 10月30日, 上午2时14分, Fuzhou Chen <cppof...@gmail.com> wrote:
> 因为公司的限制我不能看boost的代码。所以只能从这个trace考虑:

Fuzhou Chen

unread,
Oct 29, 2009, 11:15:49 PM10/29/09
to pon...@googlegroups.com
如果是这样的话,我的经验是这更可能是一个出在您的代码里的隐藏很深的bug,至于X86没有遇上问题可能是因为一些相关库的实现不同导致错误被掩盖了。
 
我曾经遇上过因为64位和32位LocalAlloc()实现不同导致一个网络攻击无法被发现的案例,推己及人吧。纯属推测。

2009/10/29 nebuladream <nebul...@gmail.com>

Fuzhou Chen

unread,
Oct 29, 2009, 11:16:38 PM10/29/09
to pon...@googlegroups.com
恰恰是因为授权松所以无法看。我和公司签的合同要求我不得看任何open source的代码,所以我也没法帮上太多。

pi1ot

unread,
Oct 30, 2009, 3:55:55 AM10/30/09
to TopLanguage
那岂不是小心翼翼防不胜防,不小心打开个网页都能看到open source的js代码。

On 10月30日, 上午11时16分, Fuzhou Chen <cppof...@gmail.com> wrote:
> 恰恰是因为授权松所以无法看。我和公司签的合同要求我不得看任何open source的代码,所以我也没法帮上太多。
>

> 2009/10/29 pi1ot <pilot...@gmail.com>

up duan

unread,
Oct 30, 2009, 4:27:40 AM10/30/09
to pon...@googlegroups.com
2009/10/30 pi1ot <pilot.cn@gmail.com>
那岂不是小心翼翼防不胜防,不小心打开个网页都能看到open source的js代码。

On 10月30日, 上午11时16分, Fuzhou Chen <cppof...@gmail.com> wrote:
> 恰恰是因为授权松所以无法看。我和公司签的合同要求我不得看任何open source的代码,所以我也没法帮上太多。
>
是啊。就算在工作时间不能看,难道非工作时间也不能看?公司支付什么补偿金了?

Shuo Chen

unread,
Oct 30, 2009, 7:37:53 AM10/30/09
to TopLanguage
boost 是你自己编译的?还是系统安装的?

董诣

unread,
Oct 30, 2009, 9:41:23 AM10/30/09
to pon...@googlegroups.com

2009/10/30 Shuo Chen <gian...@gmail.com>
boost 是你自己编译的?还是系统安装的?


 

LZ的问题已经解决,因为某头文件某处加了个pragma....



--
豆瓣:http://www.douban.com/people/ilicis/

nebuladream

unread,
Oct 30, 2009, 10:49:39 AM10/30/09
to pon...@googlegroups.com
靠,真他NN的爽,今天下午,绝望的我在一堆*.h文件代码找到了一行4字节对齐的编译命令语句,注释掉之后,一切问题就都解决了……
---
IT民工一个


2009/10/30 董诣 <juv...@gmail.com>

nebuladream

unread,
Oct 30, 2009, 10:53:47 AM10/30/09
to pon...@googlegroups.com
这个再次印证了那句名言“再诡异的错误归根结底都是因为自己2逼引起的”。这行语句是我们在32位机器上花了一下午时间才意识到必须加上的,没想到一个月后的今天,我们却花了一周的时间意识到需要在64位机器上把它去掉!
---
IT民工一个


2009/10/30 nebuladream <nebul...@gmail.com>

Fuzhou Chen

unread,
Oct 30, 2009, 1:37:17 PM10/30/09
to pon...@googlegroups.com
严格地说的确是非工作时间也不能看,看了的话一旦被发现就被解雇了。补偿金不太可能,我们同事间的笑话是让您到这儿来干活已经是恩典了,这么牛的code都看不够,还看什么Open Source,总而言之,这是政治问题不是技术问题,呵呵。
 
所以自从被招安之后俺就再也没敢到kernel.org下内核了。
 
P.S.:跑题了……

2009/10/30 up duan <fix...@gmail.com>

Fuzhou Chen

unread,
Oct 30, 2009, 1:37:37 PM10/30/09
to pon...@googlegroups.com
呵呵看来问题解决了,恭喜恭喜。:)
 
话说字节对齐我还真的没想过,可否解释一下为什么32位机器上必须加这个标志?可是因为boost或者仁兄的代码中的一些特殊要求?

2009/10/30 nebuladream <nebul...@gmail.com>

Shuo Chen

unread,
Oct 30, 2009, 7:58:19 PM10/30/09
to TopLanguage
贵公司管得真宽,能透露是哪家吗?

On Oct 31, 1:37 am, Fuzhou Chen <cppof...@gmail.com> wrote:
> 严格地说的确是非工作时间也不能看,看了的话一旦被发现就被解雇了。补偿金不太可能,我们同事间的笑话是让您到这儿来干活已经是恩典了,这么牛的code都看不够,还看什么Open
> Source,总而言之,这是政治问题不是技术问题,呵呵。
>
> 所以自从被招安之后俺就再也没敢到kernel.org下内核了。
>

> P.S.:跑题了......
>
> 2009/10/30 up duan <fixo...@gmail.com>
>
>
>
> > 2009/10/30 pi1ot <pilot...@gmail.com>

nebuladream

unread,
Oct 30, 2009, 9:25:58 PM10/30/09
to pon...@googlegroups.com
这个是因为我们定义的结构体在32位机上会发生位对齐,导致sizeof与定时的大小不同。这一点会在网络传输的客户端与server端之间产生不一致的问题。于是我们想到了32位系统编译器会自动对齐的问题。关于这个问题为什么会在64位机器上暴露,我们的代码并无这种特殊要求,而是boost本身不允许。

---
IT民工一个


2009/10/31 Fuzhou Chen <cppo...@gmail.com>

chuang

unread,
Oct 30, 2009, 9:54:22 PM10/30/09
to pon...@googlegroups.com
前段时间也遇到类似的问题,我在blog做了描述:
http://www.cppblog.com/converse/archive/2009/10/15/98714.html


2009/10/31 nebuladream <nebul...@gmail.com>



--
好装B,求甚解.

豆瓣:http://www.douban.com/people/Lichuang/
blog:http://www.cppblog.com/converse/

Fuzhou Chen

unread,
Oct 30, 2009, 9:55:33 PM10/30/09
to pon...@googlegroups.com
还是别了吧,最近招聘紧张,说出去吓坏了花花草草的话HR姐姐们面前不好交待,而且这里同公司的人不少,随口乱说话将来回国要被报复的,呵呵。

2009/10/30 Shuo Chen <gian...@gmail.com>

Fuzhou Chen

unread,
Oct 30, 2009, 9:59:16 PM10/30/09
to pon...@googlegroups.com
要是楼主这么说的话,敢问楼主现在的实现是不是在传递数据时把整个结构体直接当一个buffer写给write()?
 
我有点担心x86 server <-> x64 client或者 x64 server <-> x86 client这样的场景了。可曾做过测试?

2009/10/30 nebuladream <nebul...@gmail.com>

chuang

unread,
Oct 30, 2009, 10:06:21 PM10/30/09
to pon...@googlegroups.com
搭车问一下,gcc里面可有指定对齐字节数的编译选项,这样就不用每个结构体逐个加对齐了,....

2009/10/31 Fuzhou Chen <cppo...@gmail.com>

Fuzhou Chen

unread,
Oct 30, 2009, 10:56:15 PM10/30/09
to pon...@googlegroups.com
GCC可以靠aligned和packed属性对单个变量指定对齐。http://tigcc.ticalc.org/doc/gnuexts.html#SEC91_aligned,印象里倒是没有命令行选项要求对齐变量的。虽然有-falign-functions之类的,但只针对语句块,主要用于代码段的优化。
 
我的观点是字节对齐这种东西太冒险,说不好什么时候就出问题。如果是代码必需,那至少也得保证这些数据的操作严格保证在同一台机器内进行。用命令行参数一次指定太冒险了。


 
2009/10/30 chuang <lichua...@gmail.com>

Fei Yan

unread,
Nov 1, 2009, 6:53:16 AM11/1/09
to pon...@googlegroups.com

2009/10/31 Fuzhou Chen <cppo...@gmail.com>

GCC可以靠aligned和packed属性对单个变量指定对齐。http://tigcc.ticalc.org/doc/gnuexts.html#SEC91_aligned,印象里倒是没有命令行选项要求对齐变量的。虽然有-falign-functions之类的,但只针对语句块,主要用于代码段的优化。
 
我的观点是字节对齐这种东西太冒险,说不好什么时候就出问题。

字节对齐的确是个非常凶险的东西,如果有可能则要尽可能避免。我以前的经验是,大部分字节对齐的需求都可以通过其它一些方式来绕过,譬如定义encode/decode的方法来封装之,除非你有确定的数据证明这里是性能瓶颈。

依目前的处理器能力来说,个人觉得采用二进制方式定义的命令控制协议其实往往是得不偿失的,因为这里基本上不会造成性能的瓶颈。

提供类似命令行参数来完成的方式,确实感觉有些凶险,而且只有依赖某个特殊的编译选项才能正常运行的状况,实在是个隐藏的“地雷”。
我倒是希望编译器可以提供一种警告机制(不知道是否有),将类似这种“地雷”默认给提示出来,并提供禁止该警告的选项。

 

Fuzhou Chen

unread,
Nov 2, 2009, 6:06:21 PM11/2/09
to pon...@googlegroups.com
这个怕是很难。C的原则一贯是相信程序员,所以很少会质疑程序员的警告。
 
有条件的同学们能不能帮忙用-Wall试试看?我最近用Linux的机会太少。

2009/11/1 Fei Yan <skyscr...@gmail.com>
Reply all
Reply to author
Forward
0 new messages