大家好,我现在要做一台服务器,用于接收客户端传来的图像。现在有一台客户机,上面有2个客户端程序,每个客户端以10M/s的速度发送图像到服务器。我在服务器上开了2个端口用于监听这2个客户端。由于图像比较大(大约1M/张),客户端在发送每张图像前先发送一个信息结构体,然后紧跟着发送图像数据。每次发送4096个数据。服务器上收到图像信息结构体后,然后根据结构体中描述的图像大小收数据,直到收完为止。
现在的问题是,我收到1个客户端传来的数据时,没问题,能正常显示。但是,要是两个客户端同时传图像的时候,就出现了错乱,接收到的信息结构体描述的信息都是错的。这是什么问题?难道这两个端口共享了一块内存???请指教!!

解决方案 »

  1.   

    对不起大家了,前两天出去了,没来得及回。回来想了想,我把缓冲区重新设大点(默认的好像是8K,我现在设置成64K),就好些,但是偶尔还是会出现信息结构出错的问题。我也是网络编程刚入门,用的是重叠IO完成例程 做的服务器进行的收发。由于是测试,我就把客户端用的阻塞式的发送方式,10 M/S 的速度发送图片。在服务器端,我给每个accept的客户SOCKET分配了足够的内存(2M)进行单独读,读完后再接收,并且都加了锁的,所以满天星大侠说的共享冲突,应该不是吧。由于代码比较多,我待会看看能不能捡重要的发上来!!
      

  2.   

    下面是部分代码服务器端:
    void CBottleSvrView::ListenLoop()
    {
    while (m_bLoop)
    {
    fd_set rfds;
    TIMEVAL tv;
    tv.tv_sec  = 0;
    tv.tv_usec = 100; //等待100ms
    FD_ZERO(&rfds);
    FD_SET(m_ListenSocket[0], &rfds); // 端口8000
    FD_SET(m_ListenSocket[1], &rfds); // 端口8001
    switch (select(m_ListenSocket[1] + 1, &rfds, NULL, NULL,&tv))

    case -1: //error handled by u;
    case 0:// timeout hanled by u; 
    break;
    default: 
    for (j = 0;j < 2;j++)
    {
    f (FD_ISSET(m_ListenSocket[j],&rfds))// now u read or recv something; 

    sAccept = accept(m_ListenSocket[j],(SOCKADDR*)&addr,&addrLen);
    if (sAccept != INVALID_SOCKET)
    {
    CWorkSocket* pWork = new CWorkSocket(this); //客户端处理类
    pWork->sClient = sAccept;
    pWork->Init(1024,1024); // 给每个客户端分配内存1024*1024
    pWork->readHead(); //读信息结构体
    //令SOCKET处于警示状态,启动重叠IO
    dwRet = WSAWaitForMultipleEvents(1,EventArray,FALSE,WSA_INFINITE,TRUE);
    if (dwRet == WAIT_IO_COMPLETION)
    {

    else
    {
    if(dwRet == WAIT_TIMEOUT) 
    {
    }
    else
    {
    pWork->socketShell.m_bDead = TRUE;
    }
    }
    m_clientList.AddTail(pWork); //加入客户端链表
    }
    }

    }
    }
    }BOOL CWorkSocket::ReadHead() // 接收信息头
    {
    DWORD dwNumberOfBytesRecvd;
    DWORD dwFlags = 0; ZeroMemory(&m_iIO,sizeof(m_iIO));
    m_iIO.hEvent = WSAEVENT(this); ZeroMemory(&m_hdrRecv,sizeof(m_hdrRecv));// m_hdrRecv自定义的信息结构体
    m_hdrRecv.nIndex = -1; WSABUF wsaRecv;
    wsaRecv.buf = (char*)&m_hdrRecv;
    wsaRecv.len = sizeof(MSG_HEAD);

    if (SOCKET_ERROR == WSARecv(*m_pClient,&wsaRecv,1,&dwNumberOfBytesRecvd,&dwFlags,&m_iIO,IRoutine))
    //这里的m_pClient是view传来的客户端,IRoutine是数据处理的回调函数,主要处理读入的数据
    {
    if (WSA_IO_PENDING != WSAGetLastError())
    {
    m_bDead = TRUE;
    return FALSE;
    }
    }
    return TRUE;
    }
    BOOL CWorkSocket::ReadData(char* pBuffer,DWORD dwToRead)
    {
    DWORD dwNumberOfBytesRecvd;
    DWORD dwFlags = 0;

    ZeroMemory(&m_iIO,sizeof(m_iIO));
    m_iIO.hEvent = WSAEVENT(this); WSABUF wsaRecv;
    wsaRecv.buf = pBuffer;
    wsaRecv.len = dwToRead;
    if (SOCKET_ERROR == WSARecv(*m_pClient,&wsaRecv,1,&dwNumberOfBytesRecvd,&dwFlags,&m_iIO,IRoutine))
      //同ReadHead
    {
    if (WSA_IO_PENDING != WSAGetLastError()) //异步调用
    {
    m_bDead = TRUE;
    return FALSE;
    }
    }
    return TRUE;
    }void CALLBACK CWorkSocket::IRoutine(IN  DWORD dwError, IN DWORD cbTransferred, 
    IN  LPWSAOVERLAPPED lpOverlapped,IN  DWORD dwFlags)
    {
    if (dwError != 0 || cbTransferred == 0 )
    {
    pClient->m_bDead = TRUE;
    return;
    } static DWORD dwHaveAccept = 0;
    static DWORD dwPackSize = 0;
        if(m_hdrRecv.nIndex != -1) //读的是信息结构体
    {
           dwPackSize = m_hdrRecv.nWidth * m_hdrRecv.nHeight; //图像的大小
           ReadData(m_pBuffer, dwPackSize); // 开始读图像数据, m_pBuffer是已经分配好的内存,为1M
       m_hdrRecv.nIndex = -1;
    }
    else
       {
          dwHaveAccept += cbTransferred;
    if(dwHaveAccept < dwPackSize )
    {
    ReadData(m_pBuffer + dwHaveAccept, dwPackSize - dwHaveAccept);
    }
    else // 读完了图像数据
    {
    dwHaveAccept = 0; if(m_pParent)
        m_pParent->DrawBuffer(m_pBuffer); //交给view处理 ReadHead(); //重新读取头信息 dwPackSize = 0;
    }
        }
    }
      

  3.   

    客户端
    while (m_bStart)
    {
    static int nStep = 0;
    int nNeedToSend = lSrcWidth * lSrcHeight;//图像的高和宽
    //////////////////////////
    MSG_HEAD msg_head;
    msg_head.nIndex = m_nCamera;
    msg_head.nHeight = lSrcHeight;
    msg_head.nWidth = lSrcWidth;
    msg_head.dwTimes = m_dwTimes; DWORD dwHaveSend = 0;
    dwHaveSend = send(m_Server,(char *)(&msg_head),sizeof(MSG_HEAD),0);
    while (dwHaveSend < sizeof(MSG_HEAD))
    {
    dwSend = send(m_Server,(char *)(&msg_head),sizeof(MSG_HEAD) - dwHaveSend,0);
    dwHaveSend += dwSend;
    }
    char *pSend = (char *)lpSrcData + nNeedToSend * nStep;
    dwHaveSend = 0;
    while (dwHaveSend < nNeedToSend)
    {
    dwTosend = nNeedToSend - dwHaveSend;
    if(dwTosend > 4096)
    dwTosend = 4096;
    dwSend = send(m_Server,(pSend + dwHaveSend),dwTosend,0);
    dwHaveSend += dwSend;
    }
    nStep ++;
    if(nStep >= 2)
    nStep = 0;
    m_dwTimes ++;
    Sleep(100);
    }
      

  4.   

    静态变量是在编译时初始化,在程序执行过程中其值是一直保留的,也就是说,程序第1次执行CWorkSocket::IRoutine时,dwHaveAccept和dwPackSize都是0,当程序修改了变量值之后,再执行到这个函数中的时候就不是0了。
      

  5.   


    恩,我知道,我就是要让他保存现在已经读的数据!因为IRoutine为回调函数,我不可能一次把1M的数据读完,需要多次读取,读完后我才dwHaveAccept = 0;
      

  6.   

    static DWORD    dwHaveAccept = 0;
    static DWORD    dwPackSize = 0;如果有两个客户端,那么你这个回调函数会被两个线程并发调用。但是由于静态变量的存在,你这个回调函数显然不具有并发性。比如,你理想的情况是一个客户端连上来第一次调用IRoutine时上面两个变量都是零,但是只有第一个客户端能保证得到这个待遇。
      

  7.   

    哦,谢谢上面两位。我似乎明白了,回调函数是静态的,也就是说和类实例无关,不管new多少个CWorkSocket,只要有客户端传来都会调用这个函数,从而导致数据错乱。我今天改用阻塞+多线程的方式,没有问题!!谢谢,现在给分!!