MFC socket编程 网络五子棋详解

, 序言
   大四了,这学期也没有课,实在无聊,这整天在寝室里面待着也实在无聊啊,于是就想起了实现一个网络的五子棋,
也算四对自己在VC++编程的一个熟练,同时以前对socket编程不是很了解,也可以通过这个机会学习加深.因为在编写
过程中自己遇到了一些问题,也通过了网络和书籍自己解决了,最后也想通过这篇文章和大家分享一些经验,希望对初
学socket编程的人有帮助.
, 五子棋设计
   我们实在MFC中用单文档来完成我们的程序.
      (1),我们定义一个二维数组来存储棋子:Node[20][20],并且初始化全部为0,1表示是黑棋,-1表示是白棋,0表示没有下棋.
      (2),定义一个类:MySocket,该类继承于CSocket,用来实现服务器和客户端的通信
      (3),还有其他一些变量,在开发过程需要在添加
, 具体实现
   下面我们就一步一步的实现
     1, 建立工程
       启动Visual C++6.0,在IDE中建立一个单文档的MFC工程(具体怎么实现,相信不大家都知道吧!),但是要记住在建工程的时候
一定要选择Windows Socket ,假设我们建的工程名为:FiveNodeChess
     2, 完成窗口
       在ResourceView中的Dialog中右键->插入dialog,然后右键创建的Dialog->建立类向导->create new class,确定,为新建的dialog
创建一个类,这个Dialog将是我们的登陆窗口,类名:LandDialog,如图(图-3)
      然后在我们的Dialog上加上我们要用到的控件,如图(图-4),其中:
                 comb box控件是选择作为服务器还是客户端用的------m_combox
                 Edit控件是为输入ip地址用的----------------------m_ipEdit
     然后在类向导中为comb box控件的CBN_SELENDCANCLE添加一个处理函数:OnSelchangeComboType(),并向名:LandDialog类中添加一个
bool变量tempStaute,用来保存选择服务器还是客户端的状态,OnSelchangeComboType()函数添加代码如下:
void LandDialog::OnSelchangeComboType()
{
       // TODO: Add your control notification handler code here
       UpdateData(TRUE);
       if(m_combox.GetCurSel()==1)
       {
              tempStaute=true;
             
       }
       else
       {
              tempStaute=false;
       }
      
}
     接着就是添加一些变量用来保存是服务器还是客户端,和IP地址,并将这些变量声明成static,同是将类LandDialog声明成CFiveNodeChessView类的友元类,方便后面使用变量. 后面就是将dialog类在单文档中创建对象为登陆窗口.
     3, 创建一个 MySocket 类并继承于 CSocket , 下面介绍在单文档中 socket 使用一般步骤 :
  (1)、假定你的工程名叫CA  
   
  (2)、在CA.CPP文件中加入  
  #include   <afxsock.h>  
   
  (3)、在CAApp::InitInstance中加入:  
  BOOL   CCAApp::InitInstance()  
  {  
  if(   !AfxSocketInit()   )  
  {  
  AfxMessageBox("IDP_SOCKETS_INIT_FAILED");  
  return   FALSE;  
  }  
    …………  
  }  
    
  (4)、增加一个CMySocket类,并且从CSocket类中派生  
  class   CMySocket:public   CSocket  
  {  
  ………………  
  };  
   
  (5)、在CMySocket中增加变量:  
  CCAView   *pView;
  注意 :你在添加*pView时IDE会自动给你在CMySocket.h中添加:#include "CCAView.h" ,将它删除  
  并在CMySocket定义之前加入  
  class   CCAView;  
  class   CMySocket:   public   CSocket  
  {  
  …………………………………………………………  
  } 
    并且在CMySocket.cpp中加入#include "CCAView.h"
   
  (6)、在CCAView中加入变量CMySocket   m_socket;  并在 CCAView.h和CCAView.cpp中加入#include "CCADoc.h"
   
  (7)、在CCAView::InitUpdate中初始化m_socket  
  m_socket.pView   =   this;  
  m_socket.Create(port,SOCK_DGRAM);  
   
  (8)、在CCAView中添加成员函数:GetData()和SendData()  
   
  (9)、在CMySocket中加入虚函数【用ClassWazard添加】  
  void   CCAView::OnReceive(int   nErrorCode)  
  {   
          pView->GetData();  
  }  
   
  (10)、在CCAView的GetData()中添加:  
  {  
          m_socket.ReceiveFrom(………………)  
          MessageBox(..............);  
  }  
   
  (11)、在CCAView::SendData()中添加:  
  {  
          SendTo(………………);
  }
   以上时在单文档中使用socket的一般步骤.
   
   4, 完成 view 中各种出了函数 :
      (1),添加create消息处理
          //添加的一个create 消息句柄
 
int CFiveNodeChessView::OnCreate(LPCREATESTRUCT lpCreateStruct)
{
       if (CView::OnCreate(lpCreateStruct) == -1)
              return -1;
      
       // TODO: Add your specialized creation code here
//实现各种图片的载入
      
       CClientDC dc(this);
      
       m_dcMemo->CreateCompatibleDC(&dc);
       m_dcTemp->CreateCompatibleDC(&dc);
 
       CRect rect;
       GetClientRect(&rect);
       m_bmpMemo->CreateCompatibleBitmap(&dc,/*rect.Width(),rect.Height()*/1024,768);
       m_dcMemo->SelectObject(m_bmpMemo);
 
       m_bmpMap->m_hObject=::LoadImage(NULL,"res//bkground.bmp",
                                                               IMAGE_BITMAP,0,0,LR_LOADFROMFILE);
       m_bmpBlack->m_hObject=::LoadImage(NULL,"res//black.bmp",
                                                               IMAGE_BITMAP,0,0,LR_LOADFROMFILE);
       m_bmpWhite->m_hObject=::LoadImage(NULL,"res//white.bmp",
                                                               IMAGE_BITMAP,0,0,LR_LOADFROMFILE);
 
       DrawChessBoard();
      
       return 0;
     (2),画棋盘函数
//实现画棋盘的功能
void CFiveNodeChessView::DrawChessBoard()
{
 
       int i,j;
 
       //绘制背景
       BITMAP bmp;
       m_bmpMap->GetBitmap(&bmp);
       m_dcTemp->SelectObject(m_bmpMap);
 
       int screen_x=::GetSystemMetrics(SM_CXSCREEN);
       int screen_y=::GetSystemMetrics(SM_CYSCREEN);
 
       for (i=0; i<=screen_x/bmp.bmWidth; i++)
       {
              for (j=0; j<=screen_y/bmp.bmHeight; j++)
              {
                     m_dcMemo->BitBlt(i*bmp.bmWidth,j*bmp.bmHeight,bmp.bmWidth,bmp.bmHeight,
                                                  m_dcTemp,0,0,SRCCOPY);//把临时DC和内存DC相关联起来
              }
       }
      
       //绘制棋盘
       //m_nWidth+=20;
       for(i=1;i<=20;i++)
       {
              for(j=1;j<=20;j++)
              {
                     m_dcMemo->MoveTo(m_nWidth,m_nWidth*i);
                     m_dcMemo->LineTo(m_nWidth*20,m_nWidth*i);
                     m_dcMemo->MoveTo(m_nWidth*i,m_nWidth);
                     m_dcMemo->LineTo(m_nWidth*i,m_nWidth*20);
              }
       }
}
     (3),画棋子函数
//实现画棋子的功能
void CFiveNodeChessView::DrawChess()
{
              //绘制棋子
      
    DrawChessBoard();
       int i,j;
       //CFiveNodeChessDoc *pDoc=GetDocument();
       BITMAP bmp;
 
       for(i=0;i<20;i++)
       {
              for(j=0;j<20;j++)
              {
                     CRect rect=CRect((i+1)*m_nWidth-14,(j+1)*m_nWidth-14,
                                                          (i+1)*m_nWidth+14,(j+1)*m_nWidth+14);
                     if(Node[i][j]!=0)
                     {
                            if(Node[i][j]==1)
                            {
                                   m_bmpBlack->GetBitmap(&bmp);
                                   m_dcTemp -> SelectObject(m_bmpBlack);
                                   ::TransparentBlt(m_dcMemo->m_hDC,rect.left,rect.top,rect.Width(),rect.Height(),
                                          m_dcTemp->m_hDC,0,0,bmp.bmWidth,bmp.bmHeight,
                                          RGB(255,0,0));
                                   //TransparentBlt使用需要中工程连接中加入msimg32.lib
                            }
                            else if(Node[i][j]==-1)
                            {
                                   m_bmpWhite->GetBitmap(&bmp);
                                   m_dcTemp -> SelectObject(m_bmpWhite);
                                   ::TransparentBlt(m_dcMemo->m_hDC,rect.left,rect.top,rect.Width(),rect.Height(),
                                                                m_dcTemp->m_hDC,0,0,bmp.bmWidth,bmp.bmHeight,
                                                                RGB(255,0,0));
                            }
                     }
                     else//显示背景即可,必须画透明,否则悔棋时,棋子依然在上面
                     {
                            //m_dcTemp->SetPixel(0,0,RGB(255,0,0));
                            CBitmap bitmap;
                            bitmap.CreateBitmap(1,1,0,0,NULL);
                            m_dcTemp->SelectObject(&bitmap);
                            m_dcMemo->BitBlt(0,0,1,1,m_dcTemp,0,0,SRCCOPY);
                     }
              }
       }
 
}
    (4),鼠标点击下棋处理函数
void CFiveNodeChessView::OnLButtonDown(UINT nFlags, CPoint point)
{
       // TODO: Add your message handler code here and/or call default
       //MessageBox(IPAddress);
 
       //MessageBox(LandDialog::IP);
 
       int nDraw_x,nDraw_y;
       if (DrawOrWait==true) {
      
       if(point.x>15 && point.x<615 && point.y>15 && point.y<615)
       {
              nDraw_x=(point.x+m_nWidth/2)/m_nWidth-1;
              nDraw_y=(point.y+m_nWidth/2)/m_nWidth-1;
       }
       else
       {
              return;
       }
 
       if(Node[nDraw_x][nDraw_y]!=0)
       {
              MessageBox("此处已经有棋子,请重新下棋子");
              return;
       }
       else
       {
              if (LandDialog::staute==true) {
                     Node[nDraw_x][nDraw_y]=1;
              }
              else if (LandDialog::staute==false) {
                     Node[nDraw_x][nDraw_y]=-1;
              }
       }
       PlaySound("res//sound1.wav",NULL,SND_ASYNC);
              DrawChess();
              SendMSG(nDraw_x,nDraw_y);
       //刷新,保存棋子信息
       CRect rect=CRect((nDraw_x+1)*m_nWidth-14,
                                    (nDraw_y+1)*m_nWidth-14,
                                   (nDraw_x+1)*m_nWidth+14,
                                    (nDraw_y+1)*m_nWidth+14);
       //Invalidate();//对屏幕进行刷新(清除原图形)和重绘
       InvalidateRect(&rect);
       UpdateWindow();
       Judgement();
       DrawOrWait=false;
       }
       CView::OnLButtonDown(nFlags, point);
}
      (5)网络socket处理函数
/***************************下面实现对网络通信功能,即CSocket*************************/
 
//该函数用于服务器接受请求
void CFiveNodeChessView::OnAccept()
{
 
      
 
       m_ListenSocket.Accept(m_ConnectSocket);
    MessageBox("已经建立连接!");
}
//用于关闭连接的套节字
void CFiveNodeChessView::OnClose()
{
 
       m_ConnectSocket.Close();
 
}
 
void CFiveNodeChessView::OnReceive()
{
 
       char *pBuff=new char[10];
       int nBufSize=8;
       int nReceive;
       CString RecieveStr;
       CString nstr_x,nstr_y,nValue_str;
 
 
       int nDraw_x,nDraw_y,nValue;//保存接受的坐标和值
 
       //接收消息
       if(DrawOrWait==false){
      
       nReceive=m_ConnectSocket.Receive(pBuff,nBufSize);
 
       //判断接受是否成功
       if (nReceive!=SOCKET_ERROR) {
              //仅保留消息有效部分
              pBuff[nReceive]=NULL;
              //将消息转化为CString对象
              RecieveStr=pBuff;
              //MessageBox(RecieveStr);
              //接收刀信息就重新画棋子
              /*********下面实现重新画棋子的功能********/
              //将接收到的字符串先处理
              int num1,num2;
              num1=RecieveStr.Find("_",0);
              nstr_x=RecieveStr.Mid(0,num1);
              num2=RecieveStr.Find("_",num1+1);
              nstr_y=RecieveStr.Mid(num1+1,num2);
              nValue_str=RecieveStr.Mid(num2+1,RecieveStr.GetLength()-1);
              nDraw_x=atoi(nstr_x.GetBuffer(nstr_x.GetLength()));
              nDraw_y=atoi(nstr_y.GetBuffer(nstr_y.GetLength()));
              nValue=atoi(nValue_str.GetBuffer(nValue_str.GetLength()));
 
              Node[nDraw_x][nDraw_y]=nValue;
 
              //重新画棋子
              PlaySound("res//sound1.wav",NULL,SND_ASYNC);
              DrawChess();
              //刷新,保存棋子信息
              CRect rect=CRect((nDraw_x+1)*m_nWidth-14,
                                    (nDraw_y+1)*m_nWidth-14,
                                   (nDraw_x+1)*m_nWidth+14,
                                    (nDraw_y+1)*m_nWidth+14);
              //Invalidate();//对屏幕进行刷新(清除原图形)和重绘
              InvalidateRect(&rect);
              UpdateWindow();
              Judgement();
              DrawOrWait=true;
       }
       else
       {
              AfxMessageBox("信息接收错误!",MB_OK|MB_ICONSTOP);
       }
       }
      
}
 
void CFiveNodeChessView::OnConnect()
{
      
}
//实现下棋发送消息函数
void CFiveNodeChessView::SendMSG(int x_width,int y_hight)
{
 
       CString sendMSG;
       int nSent;//已经发送消息长度
 
       CString tempstr;
 
       //对信息进行字符串化
    //结构为:衡坐标_竖坐标_值
 
       sendMSG.Format("%d",x_width);
       sendMSG +="_";
       tempstr.Format("%d",y_hight);
       sendMSG += tempstr;
       if (LandDialog::staute==false) {
              sendMSG +="_-1";
       }
       else{
      
 
       sendMSG +="_1";
       }
 
       //发送信息
       nSent = m_ConnectSocket.Send(LPCTSTR(sendMSG),sendMSG.GetLength());
 
       //判断是否发送成功
       if (nSent ==SOCKET_ERROR) {
              AfxMessageBox("发送消息错误!",MB_OK|MB_ICONSTOP);
              //return false;
       }
}
//在关闭窗口的时候关闭套节字
void CFiveNodeChessView::OnDestroy()
{
       CView::OnDestroy();
      
       // TODO: Add your message handler code here
       m_ConnectSocket.Close();//关闭套节字
      
}
     (6),判断胜负函数
//判断胜负函数
void CFiveNodeChessView::Judgement()
{
 
       for(int i=0;i<20;i++)
       {
              for(int j=0;j<20;j++)
              {
                     int sum[4]={0,0,0,0};
                    
                     for(int k=0;k<5;k++)
                     {
                            int clrnum1=0;
                            int clrnum2=0;
                            int clrnum3=0;
                            int clrnum4=0;
                           
                            if(Node[i][j+k]!=0)
                            {
                                   clrnum1=Node[i][j+k];
                            }
                            if(Node[i+k][j]!=NULL)
                            {
                                   clrnum2=Node[i+k][j];
                            }
                            if(Node[i+k][j+k]!=NULL)
                            {
                                   clrnum3=Node[i+k][j+k];
                            }
                            if(Node[i+k][j+4-k]!=NULL)
                            {
                                   clrnum4=Node[i+k][j+4-k];
                            }
                           
                            sum[0]+=clrnum1;//纵向
                            sum[1]+=clrnum2;//横向
                            sum[2]+=clrnum3;//斜向下
                            sum[3]+=clrnum4;//斜向上
                     } 
                     for(int t=0;t<4;t++)
                     {
                            if(5==sum[t])
                            {
                                   //PlaySound("res//222.wav",NULL,SND_ASYNC);
                                   MessageBox("黑棋胜");
                                for(int a=0;a<20;a++)
                                          for(int n=0;n<20;n++)
                                          {
                                           if(Node[a][n]!=0)
                                           {
                                                             
                                                        Node[a][n]=0;
                                           }                                      
                                          }
                             DrawChess();  
                            Invalidate();                 
                            UpdateWindow();
                                          return ;
 
                            }
                            else if(sum[t]==-5)
                            {
                                   MessageBox("白棋胜");
 
                                   for(int a=0;a<20;a++)
                                          for(int n=0;n<20;n++)
                                          {
                                           if(Node[a][n]!=0)
                                           {
                                                      
                                                        Node[a][n]=0;
                                           }                                      
                                          }
                                         
                            DrawChess();  
                          &n, bsp; Invalidate();                 
                            UpdateWindow();
                                          return ;
                            }
                     }
              }
       }
}
, 总结
     男人就是要敢想敢做,迎难而上,不会的找baidu,google,没有什么不可能的,实践才硬道理啊!不多说来了,有需要源代码的在留言版留下eMail.
       
  • 1
    点赞
  • 21
    收藏
    觉得还不错? 一键收藏
  • 82
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 82
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值