多线程 + CSocket 遇到的困惑
大侠们,偶遇到困难了,请拔刀啊!!!! 有点长,恳请看完,不吝赐教啊!!!本人用MFC 写的一个客户端程序,分别连接两个服务端程序。
共三台计算机协作,客户端计算机为Client,两个服务端计算机为 CMDServer和DATAServer。
Client连接DATAServer 上的两个端口,这两个端口分别接受命令和发送数据。
Client接到CMDServer 发送过来的数据后,经过处理将命令转发给DATAServer。DATAServer接受到命令处理,
再给Client发送数据。Client接收到数据后存盘。
客户端程序如下描述:
这是基于对话框的应用程序。
新建三个CSocket类,三个类分别声明了一个对象,它们都是主对话框的成员变量。
CReceCMDSocket m_ReceCmdSocket;
CSendCMDSocket m_SendCmdSocket;
CReceDATASocket m_ReceDataSocket;
三个SOCKET类都重载了OnReceive函数,形式都一样,为的就是收到网络传输过来的数据时想主对话
框发送消息,如下:
void CReceCMDSocket::OnReceive(int nErrorCode)
{
SendMessage(m_hWnd,WM_RECEIVE1(WM_RECEIVE2,WM_RECEIVE3),0,0);
CSocket::OnReceive(nErrorCode);
}
定义了全局变量:
//接收一次命令也就是CMDServer向Client发送一次命令 所要接收的命令的缓冲区,
//命令接收到这里后会被COPY 到ReceCMDBuf1或ReceCMDBuf1
//一次命令长度为64字节 接收一次命令的条数不一定,但不会超过1024字节
unsigned long TempReceCMDBuf[256] = {'0'};
//命令缓存区1,CMDServer向Client发送一次命令的间隔不一定,很有可能就是连续发送(中间没有间隔时间),
//来不及处理,所以要先缓存.两个缓存区轮流被处理命令的线程扫描处理,乒乓操作
unsigned long ReceCMDBuf1[1024] = {'0'};
unsigned long ReceCMDBuf2[1024] = {'0'}; // 命令缓存区2
//指向最近一次发送的命令的末尾
unsigned long *ptHasSendCMDPosition = ReceCMDBuf1;
//指向最近一次接受的命令的末尾
unsigned long *ptReceCMDBufEnd = ReceCMDBuf1;
// 当前命令缓存区还剩下多少地方
unsigned short ReceCMDBufRemainLen = 4096;
嘿嘿,啰嗦了这么多,快到重点了。请大侠们耐心往下看,设计如果有不合理的地方,请大侠们拍砖,
我不怕疼!!!!!!!
由于数据的交换非常频繁。故使用多线程。使用临界区锁定的办法实现线程同步。现在暂时只把Client接收处理命
令的部分写完,就遇到了问题。
在主对话框的"开始"按钮的响应函数里创建了处理命令的线程。这是个WORKER线程。
//线程函数 仅仅扫描缓存区,处理和发送命令 所以做了个死循环
UINT DealReceFromWK1(LPVOID lpParamater)
{
Csocket_senddata2Dlg* pDlg = (Csocket_senddata2Dlg*)lpParamater;
while (TRUE)
{
// ptHasSendCmdPosition 没追上 ptReceCMDBufEnd 即接收的命令 比 发送出去的命令多
if (ptHasSendCmdPosition != ptReceCMDBufEnd)
{
处理过程
}
else // ptHasSendCmdPosition 追上了ptReceCMDBufEnd 分两种情况
{
//情况1: ptHasSendCmdPosition 被 ptReceFromWkBufEnd 套圈了
// 接收的命令 已经 把两个缓存区装满,还没发送一条命令
if (ReceFromWKTimes > SendCmdTimes) //
{
//提醒重启程序
}
//情况2: ptHasSendCmdPosition 追上 ptReceFromWkBufEnd 接收的命令
//暂时 和 发送出去的命令 一样多
else
{
//啥都不做
}
}
}
return 1;
}
void Csocket_senddata2Dlg::OnBnClickedBegin() //“开始" 按钮的响应函数
{
// TODO: 在此添加控件通知处理程序代码
if(m_SendCmdSocket != NULL)
{
delete m_SendCmdSocket;
m_SendCmdSocket = NULL;
}
if(m_ReceDataSocket != NULL)
{
delete m_ReceDataSocket;
m_ReceDataSocket = NULL;
}
if(m_ReceCmdSocket != NULL)
{
delete m_ReceCmdSocket;
m_ReceCmdSocket = NULL;
}
m_SendCmdSocket = new CSendCMDSocket(m_hWnd);
m_ReceDataSocket = new CReceDATASocket(m_hWnd);
m_ReceCmdSocket = new CReceCMDSocket(m_hWnd);
if(//创建套接字 三个)
{
AfxMessageBox(_T("套接字创建失败!"));
return;
}
if(//连接 三个端口)
{
AfxMessageBox(_T("网络连接失败!"));
return;
}
else
{
AfxMessageBox(_T("网络连接成功!"));
//创建处理命令的线程
CWinThread* thread = AfxBeginThread(DealReceFromWK1, this);
}
}
//在主线程里接收命令
LRESULT Csocket_senddata2Dlg::OnMyMessage2(WPARAM,LPARAM)
{
//WaitForSingleObject(hMutex,INFINITE);
//利用临界区锁定 使得接收命令的过程不被打断,因为命令不能丢
Critical_Section.Lock();
if(m_ReceCmdSocket == NULL)
{
Critical_Section.Unlock();
//ReleaseMutex(hMutex);
return -1;
}
ReceCMDOnceLen = m_ReceCmdSocket->Receive(TempReceCMDBuf,2048);
if(ReceCMDOnceLen < 64)
{
Critical_Section.Unlock();
//ReleaseMutex(hMutex);
return -1;
}
//当前缓存区足够装下一次接受的命令
if (ReceCMDBufRemainLen >= ReceCMDOnceLen)
{
//把TempReceCMDBuf里的命令搬移到当前的缓存区
CopyMemory(ptReceCMDBufEnd,TempReceCMDBuf,ReceCMDOnceLen);
// 以下就是 计算当前缓存区还剩下多少位置 计算指针位置等
ReceCMDBufRemainLen -= ReceCMDOnceLen;
ptReceCMDBufEnd += ReceCMDOnceLen / 4;
if (ReceCMDBufRemainLen == 0)
{
ReceCMDBufRemainLen = 4096;
if ((ptReceCMDBufEnd== ReceCMDBuf2 + 1024))
{
ptReceCMDBufEnd = ReceCMDBuf1;
}
else if((ptReceCMDBufEnd == ReceCMDBuf1 + 1024))
{
ptReceCMDBufEnd = ReceCMDBuf2;
}
}
}
//当前缓存区不够装下一次接受的数据
else
{
//把缓冲区先装满
CopyMemory(ptReceCMDBufEnd,TempReceCMDBuf,ReceCMDBufRemainLen);
ptReceCMDBufEnd += ReceCMDBufRemainLen / 4;
if ((ptReceCMDBufEnd == ReceCMDBuf2 + 1024))
{
ptReceCMDBufEnd = ReceCMDBuf1;
}
else if((ptReceCMDBufEnd == ReceCMDBuf1 + 1024))
{
ptReceCMDBufEnd = ReceCMDBuf2;
}
CopyMemory(ptReceCMDBufEnd,TempReceCMDBuf + ReceCMDBufRemainLen,ReceCMDOnceLen - ReceCMDBufRemainLen);
ptReceCMDBufEnd += (ReceCMDOnceLen - ReceCMDBufRemainLen) / 4;
ReceCMDBufRemainLen = 4096 - ReceCMDOnceLen + ReceCMDBufRemainLen;
}
//临界区解除锁定
Critical_Section.Unlock();
//ReleaseMutex(hMutex);
return 1;
}
问题:
1、因为CMDServer 发送命令的速度非常快,会发生这样的情况,还在搬移命令到缓存区到
过程中(这个过程被临界区锁定),又发送了一次命令。这样肯定会丢命令的。不知道说的对不对?
如果是这样, 如何解决?
2、现在还没有写接收DATAServer 数据的代码,一旦写了,DATAServer 一次发送的数据量
很大,数据又不能丢,接收的过程不能中断,所以必须使用临界区锁定住。到时还会发生这样
的情况,正在接收DATAServer数据的时候,CMDServer发送来了命令。那么这个命令肯定丢了。
如果是我说的这样,该如何解决?
两个问题,请大侠们一定赐教,感激不尽。