我曾经写过一个这样的帖子,这是老贴的地址:http://topic.csdn.net/u/20080716/10/21a2d6bd-8b55-4aa9-8eeb-3eef14a3315b.html
因为之后我又加入了很重要的信息,但是各位没有看到,而我又无法编辑老贴,所以只有重新开贴,我会整理如下
/////////////////////////////////
我属于第一天接触 socket的人,io多路复用一类的,完全不懂,努力学习ing ,我想在客户端用多线程 建立socket 模拟多个用户登录服务器 反复登录,对服务器做压力测试, 请问怎么做?服务器端用的WSA和overlap写的 我本来有个网络引擎,我把它对接到我在网上下载的一个 公开源码的stress测试软件上了,但是连接测试发现,不稳定,网络引擎,底层出现堆分配错误,我不知道为什么,可能是网络引擎的多线程和这个stress的多线程不能配合工作 引擎是用的WSA和overlapped写的和服务器是一样的,这个stress的多线程用的是mfc的多线程 所以我就想自己写一个简单的控制台程序,用了最基本的socket来做 conncet send while(1)
{ revc
}
但是发现,send给服务器的包,服务器收的不对, 客户端revc服务器的包,也不对,相互不能交流,而且我都核对过了,发出去的包是正确的,而原来的网络引擎虽然不稳定,但至少收发能保证都正确的 我不知道怎么回事,是不是普通的socket和相对应的WSA的socket不能协作? 而且在登录过程中,开始有个验证码,用户连接,服务器收到后,先发验证码,用户收到验证码,再发账户,密码,验证码,服务器收到以上3项,检查无误算是登录成功,可现在收验证码都不对,我又把验证码的过程屏蔽了,直接发账户,密码,也是不对,现在就卡在这里,因为首先我不太懂,我想知道,首先需要一个什么样的模式,需要开几个线程么?等等 我太菜了,所以问题太多,希望能找到方法,谢谢大家了/////////////////////////
包结构定义:
struct MSG_LOGIN:public TCP_MSG_BASE
{
char szSigniture[6]; //标志
DWORD dwVersion; //客户端版本
char szLoginUserID[zhansan::MAX_ID_LENGTH]; //ID
char szLoginPassWord[zhansan::MAX_PASSWORD_LENGTH]; //密码
char szValidationCode[zhansan::ValidationCodeCharCount]; //登陆验证码 MSG_LOGIN():TCP_MSG_BASE( CMD_LOGIN )
{
szSigniture[0] = 'A';
szSigniture[1] = 'b';
szSigniture[2] = 'c';
szSigniture[3] = 'd';
szSigniture[4] = 'e';
szSigniture[5] = 'f';
dwVersion = MAKELONG(PROTOCOL_VERSION_MINOR, PROTOCOL_VERSION_MAJOR);
szLoginUserID[0] = '\0';
szLoginPassWord[0] = '\0';
szValidationCode[0] = '\0';
} };
我发的数据包 MSG_CTLS::MSG_LOGIN sendpacket; memcpy(sendpacket.szLoginUserID, "abcdef001",20);//最长20位
memcpy(sendpacket.szLoginPassWord,"123456",9);//最长20位 memcpy(sendpacket.szValidationCode,"7419", ValidationCodeCharCount);//4位 可我收到的是 szLoginUserID为"cdef0010000000000012" 版本号是个很大的垃圾值,
密码是“34560.....000074” 验证码是 “19XX” , 看上去,好像好像被平行前移了2位/////////////////////////////
很辛苦找到底层代码
BOOL COverlappedSend::Push(char* pMsg,DWORD dwLen)
{
BOOL bResult = FALSE;
DWORD dwTail;
char* p; dwTail = m_dwExistPacketSize + m_dwEntryPosition;
if (dwTail + dwLen + 2 > m_dwMaxBufferSize)
{
if (ResetBuffer() < dwLen + 2)
goto lb_return;
}
p = m_pBuffer + m_dwEntryPosition + m_dwExistPacketSize;
*(WORD*)p = (WORD)dwLen;
memcpy(p + 2,pMsg,dwLen); m_dwExistPacketSize += (dwLen + 2);
bResult = TRUE; lb_return: // if( !bResult)
// printf("Push Operation Error\n");
return bResult;
}
BOOL COverlappedSend::SendBuffer()
{
BOOL bResult = TRUE;
WSABUF wsabuf;
wsabuf.buf = m_pBuffer + m_dwEntryPosition;
wsabuf.len = m_dwExistPacketSize;
m_dwIoType = IO_TYPE_WRITE; int result = WSASend(m_socket,&wsabuf,1,&m_dwTransferredBytes,NULL,&m_ovl,NULL);
if (result != SOCKET_ERROR)
goto lb_return; result = WSAGetLastError();
if (result == ERROR_IO_PENDING)
goto lb_return; // printf("Socket Error : %d\n", result); bResult = FALSE; lb_return:
return bResult; }
////
我知道了为何发送不对的地方,但是无能为力,本来我写出了一个版本,底层就是用的这个,但是在F5跑起来的时候,在每次连接服务器的时候后,底层会add connection,然后就会出现堆分配错误,如果直接运行程序就不会出错,可同事认为这不算,不能算合格,要我另外想办法,我使用了各种方法,发现收发不对,最后发现是上面那段代码的问题,但是因为底层是动态库,无法跟踪这个p = m_pBuffer + m_dwEntryPosition + m_dwExistPacketSize 是如何计算的,想办法我也想不出什么好方法去解决了,如果重写,那相当于重构这个底层引擎,我自认没这个能力,不重写也无法解决问题,我现在卡在这里,很难过,没人帮忙,没人可以问,同事都很冷漠,我只好来这里求助,我还在试用期,这是第一个case,搞不定只有失业了,可我绝对不能这样,各位帮帮忙
因为之后我又加入了很重要的信息,但是各位没有看到,而我又无法编辑老贴,所以只有重新开贴,我会整理如下
/////////////////////////////////
我属于第一天接触 socket的人,io多路复用一类的,完全不懂,努力学习ing ,我想在客户端用多线程 建立socket 模拟多个用户登录服务器 反复登录,对服务器做压力测试, 请问怎么做?服务器端用的WSA和overlap写的 我本来有个网络引擎,我把它对接到我在网上下载的一个 公开源码的stress测试软件上了,但是连接测试发现,不稳定,网络引擎,底层出现堆分配错误,我不知道为什么,可能是网络引擎的多线程和这个stress的多线程不能配合工作 引擎是用的WSA和overlapped写的和服务器是一样的,这个stress的多线程用的是mfc的多线程 所以我就想自己写一个简单的控制台程序,用了最基本的socket来做 conncet send while(1)
{ revc
}
但是发现,send给服务器的包,服务器收的不对, 客户端revc服务器的包,也不对,相互不能交流,而且我都核对过了,发出去的包是正确的,而原来的网络引擎虽然不稳定,但至少收发能保证都正确的 我不知道怎么回事,是不是普通的socket和相对应的WSA的socket不能协作? 而且在登录过程中,开始有个验证码,用户连接,服务器收到后,先发验证码,用户收到验证码,再发账户,密码,验证码,服务器收到以上3项,检查无误算是登录成功,可现在收验证码都不对,我又把验证码的过程屏蔽了,直接发账户,密码,也是不对,现在就卡在这里,因为首先我不太懂,我想知道,首先需要一个什么样的模式,需要开几个线程么?等等 我太菜了,所以问题太多,希望能找到方法,谢谢大家了/////////////////////////
包结构定义:
struct MSG_LOGIN:public TCP_MSG_BASE
{
char szSigniture[6]; //标志
DWORD dwVersion; //客户端版本
char szLoginUserID[zhansan::MAX_ID_LENGTH]; //ID
char szLoginPassWord[zhansan::MAX_PASSWORD_LENGTH]; //密码
char szValidationCode[zhansan::ValidationCodeCharCount]; //登陆验证码 MSG_LOGIN():TCP_MSG_BASE( CMD_LOGIN )
{
szSigniture[0] = 'A';
szSigniture[1] = 'b';
szSigniture[2] = 'c';
szSigniture[3] = 'd';
szSigniture[4] = 'e';
szSigniture[5] = 'f';
dwVersion = MAKELONG(PROTOCOL_VERSION_MINOR, PROTOCOL_VERSION_MAJOR);
szLoginUserID[0] = '\0';
szLoginPassWord[0] = '\0';
szValidationCode[0] = '\0';
} };
我发的数据包 MSG_CTLS::MSG_LOGIN sendpacket; memcpy(sendpacket.szLoginUserID, "abcdef001",20);//最长20位
memcpy(sendpacket.szLoginPassWord,"123456",9);//最长20位 memcpy(sendpacket.szValidationCode,"7419", ValidationCodeCharCount);//4位 可我收到的是 szLoginUserID为"cdef0010000000000012" 版本号是个很大的垃圾值,
密码是“34560.....000074” 验证码是 “19XX” , 看上去,好像好像被平行前移了2位/////////////////////////////
很辛苦找到底层代码
BOOL COverlappedSend::Push(char* pMsg,DWORD dwLen)
{
BOOL bResult = FALSE;
DWORD dwTail;
char* p; dwTail = m_dwExistPacketSize + m_dwEntryPosition;
if (dwTail + dwLen + 2 > m_dwMaxBufferSize)
{
if (ResetBuffer() < dwLen + 2)
goto lb_return;
}
p = m_pBuffer + m_dwEntryPosition + m_dwExistPacketSize;
*(WORD*)p = (WORD)dwLen;
memcpy(p + 2,pMsg,dwLen); m_dwExistPacketSize += (dwLen + 2);
bResult = TRUE; lb_return: // if( !bResult)
// printf("Push Operation Error\n");
return bResult;
}
BOOL COverlappedSend::SendBuffer()
{
BOOL bResult = TRUE;
WSABUF wsabuf;
wsabuf.buf = m_pBuffer + m_dwEntryPosition;
wsabuf.len = m_dwExistPacketSize;
m_dwIoType = IO_TYPE_WRITE; int result = WSASend(m_socket,&wsabuf,1,&m_dwTransferredBytes,NULL,&m_ovl,NULL);
if (result != SOCKET_ERROR)
goto lb_return; result = WSAGetLastError();
if (result == ERROR_IO_PENDING)
goto lb_return; // printf("Socket Error : %d\n", result); bResult = FALSE; lb_return:
return bResult; }
////
我知道了为何发送不对的地方,但是无能为力,本来我写出了一个版本,底层就是用的这个,但是在F5跑起来的时候,在每次连接服务器的时候后,底层会add connection,然后就会出现堆分配错误,如果直接运行程序就不会出错,可同事认为这不算,不能算合格,要我另外想办法,我使用了各种方法,发现收发不对,最后发现是上面那段代码的问题,但是因为底层是动态库,无法跟踪这个p = m_pBuffer + m_dwEntryPosition + m_dwExistPacketSize 是如何计算的,想办法我也想不出什么好方法去解决了,如果重写,那相当于重构这个底层引擎,我自认没这个能力,不重写也无法解决问题,我现在卡在这里,很难过,没人帮忙,没人可以问,同事都很冷漠,我只好来这里求助,我还在试用期,这是第一个case,搞不定只有失业了,可我绝对不能这样,各位帮帮忙
解决方案 »
- MFC中如何用双缓冲实现页面无闪烁问题
- 请教如何撤消数据库操作,即Rollback;
- ~~~~控件太多,怎么办?~~~~~
- 紧急求助!
- 请问如何把一个对话框固定在一个位置,使之不能拖动?
- 给推荐几本关于硬件编程的书
- ActiveX的对外接口个数有限制吗?
- 前台显示一个模态对话框,后台滚动条继续滚动,如何实现?
- 请问'GetWindowLongPtr'要怎样用
- 关于API的一个问题!
- vc20008 新建CButton*变量.运行结束时提示:Run-Time Check Failure #2 - Stack around the variable 'dlg' was corrupted.错误
- 使用SetClassLong修改explorer.exe程序的WinProc,程序一点反应都没有!!!!
使用抓包工具,查看你本来的网络引擎与你自己写的发出去的包是否是一样的。
你的代码:
memcpy(sendpacket.szLoginUserID, "abcdef001",20);//最长20位
memcpy(sendpacket.szLoginPassWord,"123456",9);//最长20位 memcpy(sendpacket.szValidationCode,"7419", ValidationCodeCharCount);//4位 可我收到的是 szLoginUserID为"cdef0010000000000012" 你用的是memcpy,将20位的数据拷贝到了sendpacket.szLoginUserID,所以你服务器端收到的应该是20位。这是没错的。
你得看服务器端是怎样处理的,是接收整个结构后进行处理的,还是单独接收用户名密码。建议看看服务器端的程序接收数据的要求,调整一下你客户端的发送应该就可以。
发送前使用ZeroMeory或memeset清空一下缓冲区。仔细点估计很快就能解决。
我记得memcpy的第三参数是说要COPY多少个字节,是不是这个问题了?你的src没有20字节,所以,copy了一些乱七八糟的东西过去,这样引起的?
这部分发送方法我可以拿出来用,但是它涉及到很多类,和发送机制,
我属于网络,多线程这方面的菜鸟。如果我用这部分,相当于把这个底层引擎都重写了,如果要我另辟路径再写一个,我自认没有写引擎的能力,然后我在调试中发现了个新问题,帖子写在这里,http://topic.csdn.net/u/20080723/16/cb6a10e5-d0bf-444e-b17d-b825376dbf99.html同事不满意这个,所以我才被上述问题极度的困扰,现在问题集中在:重写 我没有能力写,用我自己搞出来的这个,同事又不满意,用简单的soecket,又由于它这个发送机制,和服务器根本沟通不了,左也不行,右也不行,所以卡在这里动弹不得, 客户端可以完全端口写么?还有什么其他的办法么?
找到问题的根源所在是关键~~~~
{
unsigned int nflag;
char username[20]; // 用户名
char password[20]; // 密码
}Head,*PHead;// 使用的时候这样,
// 打包
char pBuf[64] = {0};
PHead * pack = pBuf;
pack->nflag = 0x45AD00BA;
strcpy(pack->username, "username");
strcpy(pack-password, "password");// 发送
send(pBuf, sizeof(PHead)+1);
//接收端
char pBuf[512] = {0}; 这里稍大一点
int n = recv(pBuf);
//判断包,(查找包头)
int pos = -1; // 包头位置
for ( int i = 0; i < n; ++i )
{
if ( *((unsigned int*)(pBuf+i)) == 0x45AD00BA )
{
pos = i;
break;
}
}
if ( pos >= 0 ) // 包找到
{
PHead * pack = (PHead*)pBuf;
}else
{
// 不是你的包
}
另:可以来我们公司,呵呵,起码有高手耐心给你讲解
利用多线程 跑简单socket 跑童。利用iocp 跑逻辑。 一步步来。
你直接走第三部, 自己又不太懂, 问题全在一起,能做出来就特nb了。