logo资料库

MFC下的socket编程实例.doc

第1页 / 共11页
第2页 / 共11页
第3页 / 共11页
第4页 / 共11页
第5页 / 共11页
第6页 / 共11页
第7页 / 共11页
第8页 / 共11页
资料共11页,剩余部分请下载后查看
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 !AfxSocketInit() CCAApp::InitInstance() (3)、在 CAApp::InitInstance 中加入: BOOL { if( { AfxMessageBox("IDP_SOCKETS_INIT_FAILED"); return } FALSE; ) ………… } CMySocket:public (4)、增加一个 CMySocket 类,并且从 CSocket 类中派生 class { ……………… }; CSocket (5)、在 CMySocket 中增加变量: CCAView 注 意 : 你 在 添 加 *pView 时 IDE 会 自 动 给 你 在 CMySocket.h 中 添 加 :#include *pView; "CCAView.h" ,将它删除 CCAView; CMySocket: 并在 CMySocket 定义之前加入 class class { ………………………………………………………… } CSocket public 并且在 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 m_socket.Create(port,SOCK_DGRAM); this; = (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, msimg32.lib RGB(255,0,0)); //TransparentBlt 使用需要中工程连接中加入 } 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; AfxMessageBox("信息接收错误!",MB_OK|MB_ICONSTOP); } else { } } } 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;
分享到:
收藏