| 网站首页 | 业界新闻 | 小组 | 威客 | 人才 | 下载频道 | 博客 | 代码贴 | 在线编程 | 编程论坛
欢迎加入我们,一同切磋技术
用户名:   
 
密 码:  
共有 3817 人关注过本帖
标题:多线程 + CSocket 遇到的困惑
取消只看楼主 加入收藏
leiyfan
Rank: 1
等 级:新手上路
帖 子:21
专家分:0
注 册:2008-4-12
结帖率:100%
收藏
 问题点数:0 回复次数:0 
多线程 + 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发送来了命令。那么这个命令肯定丢了。
如果是我说的这样,该如何解决?

两个问题,请大侠们一定赐教,感激不尽。






搜索更多相关主题的帖子: 计算机 客户端 应用程序 多线程 对话框 
2011-12-24 01:20
快速回复:多线程 + CSocket 遇到的困惑
数据加载中...
 
   



关于我们 | 广告合作 | 编程中国 | 清除Cookies | TOP | 手机版

编程中国 版权所有,并保留所有权利。
Powered by Discuz, Processed in 0.037000 second(s), 8 queries.
Copyright©2004-2024, BCCN.NET, All Rights Reserved