大家好,我现在要做一台服务器,用于接收客户端传来的图像。现在有一台客户机,上面有2个客户端程序,每个客户端以10M/s的速度发送图像到服务器。我在服务器上开了2个端口用于监听这2个客户端。由于图像比较大(大约1M/张),客户端在发送每张图像前先发送一个信息结构体,然后紧跟着发送图像数据。每次发送4096个数据。服务器上收到图像信息结构体后,然后根据结构体中描述的图像大小收数据,直到收完为止。
现在的问题是,我收到1个客户端传来的数据时,没问题,能正常显示。但是,要是两个客户端同时传图像的时候,就出现了错乱,接收到的信息结构体描述的信息都是错的。这是什么问题?难道这两个端口共享了一块内存???请指教!!
现在的问题是,我收到1个客户端传来的数据时,没问题,能正常显示。但是,要是两个客户端同时传图像的时候,就出现了错乱,接收到的信息结构体描述的信息都是错的。这是什么问题?难道这两个端口共享了一块内存???请指教!!
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;
}
}
}
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);
}
恩,我知道,我就是要让他保存现在已经读的数据!因为IRoutine为回调函数,我不可能一次把1M的数据读完,需要多次读取,读完后我才dwHaveAccept = 0;
static DWORD dwPackSize = 0;如果有两个客户端,那么你这个回调函数会被两个线程并发调用。但是由于静态变量的存在,你这个回调函数显然不具有并发性。比如,你理想的情况是一个客户端连上来第一次调用IRoutine时上面两个变量都是零,但是只有第一个客户端能保证得到这个待遇。