我曾经写过一个这样的帖子,这是老贴的地址: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,搞不定只有失业了,可我绝对不能这样,各位帮帮忙

解决方案 »

  1.   

    可能的情况是你的结构前面还有SOCKET包的自定义标识位,你无妨先在发出数据的前面多加两个空字节,发出试试,如果正常再找问题。
      

  2.   

    首先:
    使用抓包工具,查看你本来的网络引擎与你自己写的发出去的包是否是一样的。
    你的代码:
    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清空一下缓冲区。仔细点估计很快就能解决。
      

  3.   

    你用基本的socket写一个简单的服务端,然后和你现在的客户端进行通讯,看数据是否正确,如果正确说明你的客户端没有问题。那问题就是原来的服务器端可能有问题。
      

  4.   

    你发送的时候是先调用Push然后再SendBuffer,是这样吗?可否设置断点调试这两个函数?
      

  5.   

    如果楼主想先弄出东西来先应付,那么可以考虑再在网上找个比较符合你需求的代码,以后再慢慢学习SOCKET和多线程的技术
      

  6.   

    >>memcpy(sendpacket.szLoginUserID, "abcdef001",20);//最长20位 
    我记得memcpy的第三参数是说要COPY多少个字节,是不是这个问题了?你的src没有20字节,所以,copy了一些乱七八糟的东西过去,这样引起的?
      

  7.   

    memcpy(sendpacket.szLoginUserID, "abcdef001",sizeof("abcdef001"));//应该是这样才对的
      

  8.   

    王老师,的确是您说的这样,我想和你具体聊聊这部分,
    这部分发送方法我可以拿出来用,但是它涉及到很多类,和发送机制,
    我属于网络,多线程这方面的菜鸟。如果我用这部分,相当于把这个底层引擎都重写了,如果要我另辟路径再写一个,我自认没有写引擎的能力,然后我在调试中发现了个新问题,帖子写在这里,http://topic.csdn.net/u/20080723/16/cb6a10e5-d0bf-444e-b17d-b825376dbf99.html同事不满意这个,所以我才被上述问题极度的困扰,现在问题集中在:重写 我没有能力写,用我自己搞出来的这个,同事又不满意,用简单的soecket,又由于它这个发送机制,和服务器根本沟通不了,左也不行,右也不行,所以卡在这里动弹不得, 客户端可以完全端口写么?还有什么其他的办法么?
      

  9.   

    可以去下载个NetMonitor抓下你的收发报文
    找到问题的根源所在是关键~~~~
      

  10.   

    在结构中定义一个标识,比如:typedef struct _HEAD
    {
        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
    {
        // 不是你的包
    }
      

  11.   

    简单说吧!标准socket函数和WSA socket函数是可以相互通信的不同的是WSA socket支持ms制定的各种通信模型如iocp至于为什么send的数据包WSARecv不对,首先你先要确定客户端send的原始数据以及send后的数据长度然后查看是否发生了错误之后再服务端查看响应的WSARecv到的数据对不对有时候由于网络延迟接收到数据会小于发送的数据如果你做软件要求实时性比较高那么就需要你写个算法来修正延迟。如果你不知道怎么在源码中查看send数据以及WSARecv数据那么就的靠Ethereal工具来抓网卡数据包分析数据是否正确
      

  12.   

    建议用wireshark抓包比较下,多加点调试信息
    另:可以来我们公司,呵呵,起码有高手耐心给你讲解
      

  13.   

    这个问题其实不难, 我认为你的做法方向上是错误的。你应该做的不是找引擎, 而是首先用最简单的socket 完成,让逻辑流同,
    利用多线程 跑简单socket  跑童。利用iocp 跑逻辑。 一步步来。
    你直接走第三部, 自己又不太懂, 问题全在一起,能做出来就特nb了。
      

  14.   

    这么多天了,我已经找到了正确的方法,完成了压力测试,程序有些许不稳定,但是功能要求都达到了不过没办法,还是有人不满意,今天已经签了协议了,一切over但还是感觉各位的帮助,非常感谢,我向所有的人致敬