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.
版权声明:本文标题:MFC下的socket编程实例 内容由网友自发贡献,该文观点仅代表作者本人, 转载请联系作者并注明出处:http://www.freenas.com.cn/free/1703198288h441928.html, 本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌抄袭侵权/违法违规的内容,一经查实,本站将立刻删除。
发表评论