紧急求助 accept 崩溃

爬山的人2008 2008-11-08 01:21:09
自己做了个服务器,平均在线也就500人,莫名其妙的会在Socket accept函数处崩溃,有时候一两个昨期才崩溃,有时候一天就崩溃好几次,自己做压力测试时又不会崩溃。accept崩溃让我非常无法理解,始终没有找到原因,希望大家能帮忙,必有重谢!!

一、崩溃时的堆栈信息
Unhandled exception: 09/18/2008 17:41:43
Exception code: C0000005 ACCESS_VIOLATION
Fault address: 7C95A6CE 01:000296CE C:\WINDOWS\system32\ntdll.dll

Registers:
EAX:00000000
EBX:0000008A
ECX:05570000
EDX:05570000
ESI:00000000
EDI:05572BB0
CS:EIP:001B:7C95A6CE
SS:ESP:0023:056AF890 EBP:056AFAAC
DS:0023 ES:0023 FS:003B GS:0000
Flags:00010287
Call stack:
Address Frame
7C95A6CE 056AFAACwcslen + 150
0001:000296CE C:\WINDOWS\system32\ntdll.dll
71A84740 056AFBBC0001:00003740 C:\WINDOWS\system32\mswsock.dll
71A9AD20 056AFDFCStopWsdpService + 4F92
0001:00019D20 C:\WINDOWS\system32\mswsock.dll
71B71024 056AFE30WSAAccept + 85
0001:00010024 C:\WINDOWS\system32\WS2_32.dll
71B712C2 056AFE4Caccept + 17
0001:000102C2 C:\WINDOWS\system32\WS2_32.dll
00398397 056AFFB8CGCSIoCP::AcceptThread + 77
0002:0000E397 D:\server\allserver\GCSRTNet.dll
e:\99develope\program\net\gcsrtnet\gcsiocp.cpp line 216
e:\99develope\program\net\gcsrtnet\gcsiocp.cpp line 216
7C824829 056AFFECGetModuleHandleA + DF
0001:00023829 C:\WINDOWS\system32\kernel32.dll
mswsock.dll, file version: 5.2.3790.3959 (srv03_sp2_rtm.070216-1710); product version: 5.2.3790.3959
module name: mswsock.dll, base adress:71A80000
32 percent of memory is in use.
There are 2097151 total Kbytes of physical memory.
There are 2097151 free Kbytes of physical memory.
There are 4194303 total Kbytes of paging file.
There are 4194303 free Kbytes of paging file.
There are 1fff80 total Kbytes of virtual memory.
There are 1e34e0 free Kbytes of virtual memory.

二、代码摘要
//接受连接的SOCKET创建过程
BOOL CGCSIoCP::InitNet(WORD wPort)
{
WORD wVersionRequested;
WSADATA wsaData;

wVersionRequested = MAKEWORD(1, 1);

if(WSAStartup( wVersionRequested, &wsaData ) !=0 )
{
return FALSE;
}

//监听端口
m_sListen = WSASocket(AF_INET, SOCK_STREAM, 0, NULL, 0, WSA_FLAG_OVERLAPPED);

if(m_sListen == INVALID_SOCKET)
{
return FALSE;
}

SOCKADDR_IN addr;
ZeroMemory(&addr, sizeof(addr));

addr.sin_family = AF_INET;
addr.sin_addr.s_addr = htonl(INADDR_ANY);
addr.sin_port = htons(wPort);

if(bind(m_sListen, (SOCKADDR*)&addr, sizeof(addr)) == SOCKET_ERROR)
{
closesocket(m_sListen);
return FALSE;
}

if(listen(m_sListen, 100) == SOCKET_ERROR)
{
closesocket(m_sListen);
return FALSE;
}

return TRUE;
}

//接收链接的线程
DWORD WINAPI CGCSIoCP::AcceptThread(void* pVoid)
{
SOCKADDR_IN addrAccept;
int addrlen = sizeof(SOCKADDR_IN);
ZeroMemory(&addrAccept, addrlen);

SOCKET sockAccept= INVALID_SOCKET;

while(TRUE)
{
//这个地方会崩溃,,有时候一两个昨期才崩溃,有时候一天就崩溃好几次,自己做压力测试时没有问题
//addrlen的值我检查了,始终是16

if((sockAccept=accept(m_sListen, (SOCKADDR*)&addrAccept, &addrlen))==INVALID_SOCKET)
{
continue;
}
...
}

return 0;
}
...全文
351 18 打赏 收藏 转发到动态 举报
AI 作业
写回复
用AI写文章
18 条回复
切换为时间正序
请发表友善的回复…
发表回复
Wenxy1 2008-12-10
  • 打赏
  • 举报
回复
[Quote=引用 1 楼 cnzdgs 的回复:]
进入循环前,先将m_sListen、&addrAccept、&addrlen这三个值输出到日志文件,再用try捕获异常,发生异常时,再将这三个值输出,对比看看。
[/Quote]

支持这个用法,建议把一些调试信息写入日志文件中,这样便于分析。
redhat7890 2008-12-10
  • 打赏
  • 举报
回复
你的思路错了,不是循环accept,而是必须循环listen!
止到监听到有socket来时,你再accept,这时会返回你一个连接上的acceptSocket,
你再创建新线程,新线程里的socket就是这个acceptSocket;
这样你有500个用户,那么你就需要创建500个工作线程,每一个工作线程都有自己的acceptSocket,互补干扰!
思路为:

创建socket();
bind();
while(TURE)
{
listen();
SOCKET accptSock = accept();//这里是阻塞的,当连接成功了才进入新线程;
CreateThread((LPVOID)&acceptSock);//新线程就是你的工作线程,在这里你和客户通信,
//通信的socket就是accptSock ,作为参数你传进新线程的线程函数里就可以了;
}
DWORD ThreadProc( LPVOID lParameter)
{
//和客户进行数据传输;
}
littlepboy 2008-12-02
  • 打赏
  • 举报
回复
h还是我分析的不错,lz加分吧,呵呵。

[Quote=引用 11 楼 climber1977 的回复:]
谢谢大家,我把应用层的一些功能屏蔽了,这个错误就没了.看来是我的应用层,哪里没处理好.导致了这个问题.
[/Quote]
jink 2008-12-01
  • 打赏
  • 举报
回复
看看你的m_sListen是不是被动过了
cmchao 2008-12-01
  • 打赏
  • 举报
回复
[Quote=引用 13 楼 sigh02 的回复:]
不是同一个socket吧
每次accept会自己创建一个socket返回给sockAccept啊,sockAccept相当于一个指针,内容是由每次accept更新的啊
引用 12 楼 Greg_han 的回复:
accept回返回一个socket,然后由这个socket去处理相关的事情,但是你每次返回都用同一个socket去处理,也就是说有肯能事情还没有处理完,它就要处理新来的事情,肯定会崩溃的,所以我建议你每accept一次就用一个新的socket去处理它,处理完后就自动释放socket
[/Quote]
[Quote=引用 1 楼 ]
不是同一个socket吧
每次accept会自己创建一个socket返回给sockAccept啊,sockAccept相当于一个指针,内容是由每次accept更新的啊
引用 12 楼 Greg_han 的回复:
accept回返回一个socket,然后由这个socket去处理相关的事情,但是你每次返回都用同一个socket去处理,也就是说有肯能事情还没有处理完,它就要处理新来的事情,肯定会崩溃的,所以我建议你每accept一次就用一个新的socket去处理它,处理完后就自动释放socket
[/Quote]
SOCKET sockAccept= INVALID_SOCKET;

while(TRUE)
{
//这个地方会崩溃,,有时候一两个昨期才崩溃,有时候一天就崩溃好几次,自己做压力测试时没有问题
//addrlen的值我检查了,始终是16
if((sockAccept=accept(m_sListen, (SOCKADDR*)&addrAccept, &addrlen))==INVALID_SOCKET)
{
continue;
}
...
}
从这个while循环就知道,每次的accept返回的socket都是由同一个sockAccept去处理的
sigh02 2008-12-01
  • 打赏
  • 举报
回复
不是同一个socket吧
每次accept会自己创建一个socket返回给sockAccept啊,sockAccept相当于一个指针,内容是由每次accept更新的啊
[Quote=引用 12 楼 Greg_han 的回复:]
accept回返回一个socket,然后由这个socket去处理相关的事情,但是你每次返回都用同一个socket去处理,也就是说有肯能事情还没有处理完,它就要处理新来的事情,肯定会崩溃的,所以我建议你每accept一次就用一个新的socket去处理它,处理完后就自动释放socket
[/Quote]
Greg_han 2008-11-25
  • 打赏
  • 举报
回复
accept回返回一个socket,然后由这个socket去处理相关的事情,但是你每次返回都用同一个socket去处理,也就是说有肯能事情还没有处理完,它就要处理新来的事情,肯定会崩溃的,所以我建议你每accept一次就用一个新的socket去处理它,处理完后就自动释放socket
爬山的人2008 2008-11-25
  • 打赏
  • 举报
回复
谢谢大家,我把应用层的一些功能屏蔽了,这个错误就没了.看来是我的应用层,哪里没处理好.导致了这个问题.
caitian6 2008-11-25
  • 打赏
  • 举报
回复
学习
dch4890164 2008-11-24
  • 打赏
  • 举报
回复
[Quote=引用 6 楼 littlepboy 的回复:]
C0000005一般是越界访问或使用了非法指针,从你的代码来看看不出什么问题。
我怀疑不是accept出的问题,而是别的地方出现了内存错误,lz带着代码跑吧,看是不是其他的问题。
[/Quote]非常同意
类似的问题,我遇到过几次,尤其是数组越界访问,出问题的地方就不是数组越界那里,而是其它地方,并且这种bug不总出现,数据输入条件相同有些时候也不能重现,有些时候重起一下机器就可以。把数组越界代码修正之后,bug就不会重复出现了
这种bug最难调,个人比较同意六楼的看法
homesos 2008-11-24
  • 打赏
  • 举报
回复
抓一下dmp包吧
用windbg或Dbgview看一下现场情况(主要看一下内存情况),或许是有可能是别的地方窜改了内存,导致此处出错。
sun007700 2008-11-24
  • 打赏
  • 举报
回复
while(TRUE)
{
fd_set fdRead;
timeval tmvTimeOut;
tmvTimeOut.tv_sec = 10; //根据情况自己设,但不要太小
tmvTimeOut.tv_usec = 0;
FD_ZERO(&fdRead);
FD_SET(m_sListen, &fdRead);
nResult = select(0, &fdRead, NULL, NULL, &tmvTimeOut);

if(nResult == SOCKET_ERROR)
{
nResult = WSAGetLastError();
return FALSE;
}
else if((nResult <= 0) || (FD_ISSET(m_sListen, &fdRead) == 0))
continue;
//这个地方会崩溃,,有时候一两个昨期才崩溃,有时候一天就崩溃好几次,自己做压力测试时没有问题
//addrlen的值我检查了,始终是16
if((sockAccept=accept(m_sListen, (SOCKADDR*)&addrAccept, &addrlen))==INVALID_SOCKET)
{
continue;
}
}

思路就是accept之前先select,这样更保险一点。
littlepboy 2008-11-22
  • 打赏
  • 举报
回复
C0000005一般是越界访问或使用了非法指针,从你的代码来看看不出什么问题。
我怀疑不是accept出的问题,而是别的地方出现了内存错误,lz带着代码跑吧,看是不是其他的问题。
爬山的人2008 2008-11-18
  • 打赏
  • 举报
回复
[Quote=引用 1 楼 cnzdgs 的回复:]
进入循环前,先将m_sListen、&addrAccept、&addrlen这三个值输出到日志文件,再用try捕获异常,发生异常时,再将这三个值输出,对比看看。
[/Quote]
m_sListen、&addrAccept、&addrlen三个值我检查过,没有发生过变化,addrlen始终是16.
谢谢

[Quote=引用 2 楼 superdiablo 的回复:]
一个可能的原因是m_sListen被close了而你还用它来accept。做一下日志看有没有这种情况。
[/Quote]
如果socket被close了,accept只是会失败。而不会崩溃

[Quote=引用 4 楼 cmchao 的回复:]
引用 3 楼 cmchao 的回复:
你总要一个人处理几百个人的事情,肯定要崩溃咯,accept回返回一个socket,然后由这个socket去处理相关的事情,但是你每次返回都用同一个socket去处理,也就是说有肯能事情还没有处理完,它就要处理新来的事情,肯定会崩溃的,所以我建议你每accept一次就用一个新的socket去处理它,处理完后就自动释放socket ,还有就是while里面一定要Sleep一下,否则你的电脑就像死机的状态

while(TRUE)
{

[/Quote]

AcceptThread只是一个接收线程,接收到的socket确实放到一个队列里面了,并且有还接数收数线程,数据处理线程,程序和你说的架构基上是一新的我再补充一下,我的程序是用完成端口实现的。只是为了简,才用了accept,但发送数据用的是ReadFile, WriteFile函数,不知道有没有影响
cmchao 2008-11-17
  • 打赏
  • 举报
回复
[Quote=引用 3 楼 cmchao 的回复:]
你总要一个人处理几百个人的事情,肯定要崩溃咯,accept回返回一个socket,然后由这个socket去处理相关的事情,但是你每次返回都用同一个socket去处理,也就是说有肯能事情还没有处理完,它就要处理新来的事情,肯定会崩溃的,所以我建议你每accept一次就用一个新的socket去处理它,处理完后就自动释放socket ,还有就是while里面一定要Sleep一下,否则你的电脑就像死机的状态

while(TRUE)
{
SOCKET *pSockAccept= new SOCKET;
//用一个队列保存pSockAccept地址,开一个线程维护这些…
[/Quote]
补充一点,如果发现socket队列的数目大于上限,就等待直到不做任何处理:

list<socket socket&> sctList;//全局
while(TRUE)
{
if(sctList.GetCount()<=500)
{
SOCKET *pSockAccept= new SOCKET;
sctList.addHead(pSockAccept);

if((sockAccept=accept(m_sListen, (SOCKADDR*)&addrAccept, &addrlen))==INVALID_SOCKET)
{
Sleep(10);
continue;
}
}
else
{
Sleep(100);
}


...
}

return 0;
}
同时要开线程负责处理和维护队列中的这些socket,如果发现socket闲置就释放socket和空间
....
cmchao 2008-11-17
  • 打赏
  • 举报
回复
你总要一个人处理几百个人的事情,肯定要崩溃咯,accept回返回一个socket,然后由这个socket去处理相关的事情,但是你每次返回都用同一个socket去处理,也就是说有肯能事情还没有处理完,它就要处理新来的事情,肯定会崩溃的,所以我建议你每accept一次就用一个新的socket去处理它,处理完后就自动释放socket


while(TRUE)
{
SOCKET *pSockAccept= new SOCKET;
//用一个队列保存pSockAccept地址,开一个线程维护这些socket,如果发现socket闲置就释放socket和空间
....

if((sockAccept=accept(m_sListen, (SOCKADDR*)&addrAccept, &addrlen))==INVALID_SOCKET)
{
continue;
}
...
}

return 0;
}
cnzdgs 2008-11-16
  • 打赏
  • 举报
回复
进入循环前,先将m_sListen、&addrAccept、&addrlen这三个值输出到日志文件,再用try捕获异常,发生异常时,再将这三个值输出,对比看看。
superdiablo 2008-11-16
  • 打赏
  • 举报
回复
一个可能的原因是m_sListen被close了而你还用它来accept。做一下日志看有没有这种情况。

18,363

社区成员

发帖
与我相关
我的任务
社区描述
VC/MFC 网络编程
c++c语言开发语言 技术论坛(原bbs)
社区管理员
  • 网络编程
加入社区
  • 近7日
  • 近30日
  • 至今
社区公告
暂无公告

试试用AI创作助手写篇文章吧