admin 管理员组

文章数量: 887021


2023年12月22日发(作者:linux虚拟机终端快捷键)

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_Sel()==1)

{

tempStaute=true;

}

else

{

tempStaute=false;

}

}

接着就是添加一些变量用来保存是服务器还是客户端,和IP地址,并将这些变量声明成static,同是将类LandDialog声明成CFiveNodeChessView类的友元类,方便后面使用

变量. 后面就是将dialog类在单文档中创建对象为登陆窗口.

3,创建一个MySocket类并继承于CSocket类,下面介绍在单文档中socket使用一般步骤:

(1)、假定你的工程名叫CA

(2)、在文件中加入

#include

(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

{

…………………………………………………………

}

并且在中加入#include "CCAView.h"

(6)、在CCAView中加入变量CMySocket m_socket; 并在CCAView.h和中加入#include "CCADoc.h"

(7)、在CCAView::InitUpdate中初始化m_socket

m_ = this;

m_(port,SOCK_DGRAM);

(8)、在CCAView中添加成员函数:GetData()和SendData()

(9)、在CMySocket中加入虚函数【用ClassWazard添加】

void CCAView::OnReceive(int nErrorCode)

{

pView->GetData();

}

(10)、在CCAView的GetData()中添加:

{

m_eFrom(………………)

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,/*(),()*/1024,768);

m_dcMemo->SelectObject(m_bmpMemo);

m_bmpMap->m_hObject=::LoadImage(NULL,"",

IMAGE_BITMAP,0,0,LR_LOADFROMFILE);

m_bmpBlack->m_hObject=::LoadImage(NULL,"",

IMAGE_BITMAP,0,0,LR_LOADFROMFILE);

m_bmpWhite->m_hObject=::LoadImage(NULL,"",

IMAGE_BITMAP,0,0,LR_LOADFROMFILE);

DrawChessBoard();

}

(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/h; i++)

{

for (j=0; j<=screen_y/ht; j++)

{

m_dcMemo->BitBlt(i*h,j*ht,h,ht,

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();

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,,r

,(),(),

m_dcTemp->m_hDC,0,0,h,ht,

RGB(255,0,0));

//TransparentBlt使用需要中工程连接中加入

}

else if(Node[i][j]==-1)

{

m_dcTemp -> SelectObject(m_bmpWhite);

::TransparentBlt(m_dcMemo->m_hDC,,r

,(),(),

m_dcTemp->m_hDC,0,0,h,ht,

RGB(255,0,0));

}

}

else//显示背景即可,必须画透明,否则悔棋时,棋子依然在上面

{

//m_dcTemp->SetPixel(0,0,RGB(255,0,0));

CBitmap bitmap;

Bitmap(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)

{

//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("",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_(m_ConnectSocket);

MessageBox("已经建立连接!");

}

//用于关闭连接的套节字

void CFiveNodeChessView::OnClose()

{

m_();

}

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_e(pBuff,nBufSize);

//判断接受是否成功

if (nReceive!=SOCKET_ERROR) {

//仅保留消息有效部分

pBuff[nReceive]=NULL;

//将消息转化为CString对象

RecieveStr=pBuff;

//MessageBox(RecieveStr);

//接收刀信息就重新画棋子

/*********下面实现重新画棋子的功能********/

//将接收到的字符串先处理

int num1,num2;

num1=("_",0);

nstr_x=(0,num1);

num2=("_",num1+1);

nstr_y=(num1+1,num2);

nValue_str=(num2+1,gth()-1);

nDraw_x=atoi(nstr_fer(nstr_gth()));

nDraw_y=atoi(nstr_fer(nstr_gth()));

nValue=atoi(nValue_fer(nValue_gth()));

Node[nDraw_x][nDraw_y]=nValue;

//重新画棋子

PlaySound("",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;

//对信息进行字符串化

//结构为:衡坐标_竖坐标_值

("%d",x_width);

sendMSG +="_";

("%d",y_hight);

sendMSG += tempstr;

if (LandDialog::staute==false) {

sendMSG +="_-1";

else{

sendMSG +="_1";

}

//发送信息

nSent = m_(LPCTSTR(sendMSG),gth());

//判断是否发送成功

if (nSent ==SOCKET_ERROR) {

AfxMessageBox("发送消息错误!",MB_OK|MB_ICONSTOP);

//return false;

}

}

//在关闭窗口的时候关闭套节字

void CFiveNodeChessView::OnDestroy()

{

CView::OnDestroy();

// TODO: Add your message handler code here

m_();//关闭套节字

}

(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("",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.


本文标签: 实现 函数 工程 消息 服务器