会员登录 用户名: 密码: 登录 新会员注册 [找回密码]
当前位置:编程论坛 >> C/S程序开发专区 >> VC++编程论坛 >> 多线程+SOCKET 遇到的问题。请大侠们赐教
首页
  发表一个新主题  发表一个新投票  回复主题 您是本帖的第 3350 个阅读者浏览上一篇主题  刷新本主题   树形显示贴子 浏览下一篇主题
 * 贴子主题:多线程+SOCKET 遇到的问题。请大侠们赐教 悬赏分50 [提问中] 报告本帖给版主  显示可打印的版本  把本贴打包邮递  把本贴加入论坛收藏夹  发送本页面给朋友  把本贴加入IE收藏夹 
 leifyan 帅哥哟,离线,有人找我吗?
  
  
  等 级:初出江湖
  积 分:153
  专家分:0
  提问帖:1/0
  回答帖:0
  总帖数:1
  经验值:53
  注 册:2011/12/24
给leifyan发送一个短消息 把leifyan加入好友 查看leifyan的个人资料 搜索leifyan在VC++编程论坛的所有贴子 引用回复这个贴子 回复这个贴子楼主

发贴心情 多线程+SOCKET 遇到的问题。请大侠们赐教

大侠们,偶遇到困难了,请拔刀啊!!!!

本人用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 0:52:00
  鲜花(0)  鸡蛋(0)
 361378900 帅哥哟,离线,有人找我吗?狮子座1987-8-13
  
  
  头 衔:学习中。。。
  等 级:论坛游侠
  积 分:4437
  专家分:2604
  提问帖:7/7
  回答帖:208
  总帖数:309
  经验值:500
  注 册:2007/12/30
给361378900发送一个短消息 把361378900加入好友 查看361378900的个人资料 搜索361378900在VC++编程论坛的所有贴子 引用回复这个贴子 回复这个贴子2

发贴心情 

通常的做法是把发送或者接收的数据不要马上去处理,放在一个数据列表中,再用一个单独的线程从数据列表中取出数据进行处理

走过了就不要再回头。。。。。。。。。。

发帖:2012/3/14 15:38:00

本主题贴数2,分页:[返回帖子列表] [上一页] [1] [下一页]
 *快速回复:多线程+SOCKET 遇到的问题。请大侠们赐教  [ 回帖是一种美德 :) ]
会员账号 用户名    还没注册?    密码    忘记密码?
内容
  • HTML标签: 不可用
  • UBB标签: 可用
  • 贴图标签: 可用
  • 多媒体标签:可用
  • 表情字符转换:可用
  • 上传图片:不可用
  • 最多15KB
  • 插入代码 粗体 斜体 下划线 居中 超级连接 Email连接 图片 Flash图片 Shockwave文件 realplay视频文件 Media Player视频文件 QuickTime视频文件 引用 飞行字 移动字 发光字 阴影字 查看更多的心情图标 背景音乐
    点击表情图即可在帖子中加入相应的表情
                                
    邮件回复 显示签名   [Ctrl+Enter直接提交贴子]

    管理选项锁定 | 解锁 | 提升 | 删除 | 移动 | 固顶 | 总固顶 | 奖励 | 惩罚 | 发布公告