VC++MFCsocket编程.docx
- 文档编号:24778496
- 上传时间:2023-06-01
- 格式:DOCX
- 页数:24
- 大小:52.91KB
VC++MFCsocket编程.docx
《VC++MFCsocket编程.docx》由会员分享,可在线阅读,更多相关《VC++MFCsocket编程.docx(24页珍藏版)》请在冰豆网上搜索。
VC++MFCsocket编程
注意:
1由于连接需要的时间不是即时的,也就是一个语句所用的时间是不够的,所以需要运用计时器反复进行连接(调用从connect函数)并检测连接结果。
2当Create一个套接字时注意功能参数(如设置为FD_WRITE则,只拥有发送功能,不能触发OnReceive函数)。
VC++MFCsocket编程
MFC和VC++2008-08-2902:
16:
40阅读3056评论3 字号:
大中小 订阅
socket编程用法----随着计算机网络化的深入,计算机网络编程在程序设计的过程中变得日益重要。
由于C++语言对底层操作的优越性,许多文章都曾经介绍过用VC++进行Socket编程的方法。
但由于都是直接利用动态连接库wsock32.dll进行操作,实现比较繁琐。
其实,VC++的MFC类库中提供了CAsyncSocket这样一个套接字类,用他来实现Socket编程,是非常方便的。
----本文将用一个Echo例程来介绍CAsyncSocket类的用法。
----一.客户端
----1.创建一个DialogBased项目:
CSockClient。
----2.设计对话框
----去掉Ok和Cancle两个按钮,增加ID_Connect(连接)、ID_Send(发送)、ID_Exit(关闭)按钮,增加ListBox控件IDC_LISTMSG和Edit控件IDC_EDITMSG,并按下表在ClassWizard中为CCSockClientDlg类添加变量。
ControlIDTypeMember
IDC_EDITMSGCEditm_MSG
IDC_LISTMSGClistBoxm_MSGS
----3.CAsyncSocket类用DoCallBack函数处理MFC消息,当一个网络事件发生时,DoCallBack函数按网络事件类型:
FD_READ、FD_WRITE、FD_ACCEPT、FD_CONNECT分别调用OnReceive、OnSend、OnAccept、OnConnect函数。
由于MFC把这些事件处理函数定义为虚函数,所以要生成一个新的C++类,以重载这些函数,做法如下:
----以Public方式继承CAsyncSocket类,生成新类MySock;
----为MySock类添加虚函数OnReceive、OnConnect、OnSend
----4.在MySock.ccp中添加以下代码
#include"CSockClient.h"
#include"CSockClientDlg.h"
----5.在MySock.h中添加以下代码
public:
BOOLm_bConnected; //是否连接
UINTm_nLength; //消息长度
charm_szBuffer[4096]; //消息缓冲区
----6.在MySock.ccp中重载各函数
MySock:
:
MySock()
{
m_nLength=0;
memset(m_szBuffer,0,sizeof(m_szBuffer));
m_bConnected=FALSE;
}
MySock:
:
~MySock()
{
//关闭套接字
if(m_hSocket!
=INVALID_SOCKET)
Close();
}
voidMySock:
:
OnReceive(intnErrorCode)
{
m_nLength=Receive(m_szBuffer,sizeof(m_szBuffer),0);
//下面两行代码用来获取对话框指针
CCSockClientApp*pApp=(CCSockClientApp*)AfxGetApp();
CCSockClientDlg*pDlg=(CCSockClientDlg*)pApp->m_pMainWnd;
pDlg->m_MSGS.InsertString(0,m_szBuffer);
memset(m_szBuffer,0,sizeof(m_szBuffer));
CAsyncSocket:
:
OnReceive(nErrorCode);
}
voidMySock:
:
OnSend(intnErrorCode)
{
Send(m_szBuffer,m_nLength,0);
m_nLength=0;
memset(m_szBuffer,0,sizeof(m_szBuffer));
//继续提请一个“读”的网络事件,接收Server消息
AsyncSelect(FD_READ);
CAsyncSocket:
:
OnSend(nErrorCode);
}
voidMySock:
:
OnConnect(intnErrorCode)
{
if(nErrorCode==0)
{
m_bConnected=TRUE;
CCSockClientApp*pApp=(CCSockClientApp*)AfxGetApp();
CCSockClientDlg*pDlg=(CCSockClientDlg*)pApp->m_pMainWnd;
memcpy(m_szBuffer,"Connectedto",13);
strncat(m_szBuffer,pDlg->m_szServerAdr,
sizeof(pDlg->m_szServerAdr));
pDlg->m_MSGS.InsertString(0,m_szBuffer);
AsyncSelect(FD_READ); ////提请一个“读”的网络事件,准备接收
}
CAsyncSocket:
:
OnConnect(nErrorCode);
}
----7.新建对话框IDD_Addr,用来输入IP地址和Port;生成新类CAddrDlg。
增加两个Edit控件:
IDC_Addr、IDC_Port按下表在ClassWizard中为CAddrDlg类添加变量。
ControlIDTypeMember
IDC_AddrCStringm_Addr
IDC_PortIntm_Port
----8.在CSockClientDlg.ccp中添加代码
#include"AddrDlg.h"
protected:
intTryCount;
MySockm_clientSocket;
UINTm_szPort;
public:
charm_szServerAdr[256];
----9.双击IDD_CSOCKCLIENT_DIALOG对话框中的“连接”按钮,添加以下代码
voidCCSockClientDlg:
:
OnConnect()
{
m_clientSocket.ShutDown
(2);
m_clientSocket.m_hSocket=INVALID_SOCKET;
m_clientSocket.m_bConnected=FALSE;
CAddrDlgm_Dlg;
//默认端口1088
m_Dlg.m_Port=1088;
if(m_Dlg.DoModal()==IDOK&&!
m_Dlg.m_Addr.IsEmpty())
{
memcpy(m_szServerAdr,m_Dlg.m_Addr,sizeof(m_szServerAdr));
m_szPort=m_Dlg.m_Port;
//建立计时器,每1秒尝试连接一次,直到连上或TryCount>10
SetTimer(1,1000,NULL);
TryCount=0;
}
}
----10.添加Windows消息WM_TIMER响应函数OnTimer
voidCCSockClientDlg:
:
OnTimer(UINTnIDEvent)
{
if(m_clientSocket.m_hSocket==INVALID_SOCKET)
{
BOOLbFlag=m_clientSocket.Create(0,SOCK_STREAM,FD_CONNECT);
if(!
bFlag)
{
AfxMessageBox("SocketError!
");
m_clientSocket.Close();
PostQuitMessage(0);
return;
}
}
m_clientSocket.Connect(m_szServerAdr,m_szPort);
TryCount++;
if(TryCount>=10||m_clientSocket.m_bConnected)
{
KillTimer
(1);
if(TryCount>=10)
AfxMessageBox("ConnectFailed!
");
return;
}
CDialog:
:
OnTimer(nIDEvent);
}
----11.双击IDD_CSOCKCLIENT_DIALOG对话框中的“发送”按钮,添加以下代码
voidCCSockClientDlg:
:
OnSend()
{
if(m_clientSocket.m_bConnected)
{
m_clientSocket.m_nLength=m_MSG.GetWindowText
(m_clientSocket.m_szBuffer,sizeof(m_clientSocket.m_szBuffer));
m_clientSocket.AsyncSelect(FD_WRITE);
m_MSG.SetWindowText("");
}
}
----12.双击IDD_CSOCKCLIENT_DIALOG对话框中的“关闭”按钮,添加以下代码
voidCCSockClientDlg:
:
OnExit()
{
//关闭Socket
m_clientSocket.ShutDown
(2);
//关闭对话框
EndDialog(0);
}
----
12.运行此项目,连接时输入主机名或IP均可,CAsyncSocket类会自动处理。
----
二.服务端
----
Server端的编程与Client端的类似,下面主要介绍他的Listen及Accept函数
----
1.建立一个CNewSocket类,重载CAsyncSocket类的OnReceive、OnSend函数,如何进行信息的显示和发送可以参考Client程序。
本例中采用将收到信息原封不动发回的方法来实现Echo功能,代码如下
CNewSocket:
:
OnReceive(intnErrorCOde)
{
m_nLength=Receive(m_szBuffer,sizeof(m_szBuffer),0);
//直接转发消息
AsyncSelect(FD_WRITE);
}
CNewSocket:
:
OnSend(intnErrorCode)
{
Send(m_szBuffer,m_nLength,0);
}
----
2.建立一个CMyServerSocket类,重载CAsyncSocket类的OnAccept函数代码如下
----
在MyServerSocket.h中声明变量
public:
:
CNewSocket* m_pSocket;
voidCMyServerSocket:
:
OnAccept(intnErrorCode)
{
//侦听到连接请求,调用Accept函数
CNewSocket*pSocket=newCNewSocket();
if(Accept(*pSocket))
{
pSocket->AsyncSelect(FD_READ);
m_pSocket=pSocket;
}
else
deletepSocket;
}
----
3.为对话框添加一个“侦听”按钮,添加如下代码
----
在CsockServerDlg.ccp中声明变量
public:
CMyServerSocket m_srvrSocket;
voidCCSockServerDlg:
:
OnListen()
{
if(m_srvrSocket.m_hSocket==INVALID_SOCKET)
{
BOOLbFlag=m_srvrSocket.Create
(UserPort,SOCK_STREAM,FD_ACCEPT);
if(!
bFlag)
{
AfxMessageBox(“SocketError!
”);
M_srvrSocket.Close();
PostQuitMessage(0);
Return;
}
}
//“侦听”成功,等待连接请求
if(!
m_srvrSocket。
Listen
(1))
{
intnErrorCode=m_srvrSocket.GetLastError();
if(nError!
=WSAEWOULDBLOCK)
{
AfxMessageBox(“SocketError!
”);
M_srvrSocket.Close();
PostQuitMessage(0);
Return;
}
}
}
----
4.目前程序只能实现Echo功能,将信息原封不动的转发,若能将Accept中由CNewSocket*pSocket= newCNewSocket();得到的Socket指针存入一个CList或一个数组中,便像Client端那样,对所有的连接进行读写控制。
----
三.总结
----
CAsyncSocket类为我们使用Socket提供了极大方便。
建立Socket的WSAStartup过程和bind过程被简化成为Create过程,IP地址类型转换、主机名和IP地址转换的过程中许多复杂的变量类型都被简化成字符串和整数操作,特别是CAsyncSocket类的异步特点,完全可以替代繁琐的线程操作。
MFC提供了大量的类库,我们若能灵活的使用他们,便会大大提高编程的效率。
一、TCP/IP体系结构与特点
1、TCP/IP体系结构
TCP/IP协议实际上就是在物理网上的一组完整的网络协议。
其中TCP是提供传输层服务,而IP则是提供网络层服务。
TCP/IP包括以下协议:
(结构如图1.1)
(图1.1)
IP:
网间协议(InternetProtocol)负责主机间数据的路由和网络上数据的存储。
同时为ICMP,TCP, UDP提供分组发送服务。
用户进程通常不需要涉及这一层。
ARP:
地址解析协议(AddressResolutionProtocol)
此协议将网络地址映射到硬件地址。
RARP:
反向地址解析协议(ReverseAddressResolutionProtocol)
此协议将硬件地址映射到网络地址
ICMP:
网间报文控制协议(InternetControlMessageProtocol)
此协议处理信关和主机的差错和传送控制。
TCP:
传送控制协议(TransmissionControlProtocol)
这是一种提供给用户进程的可靠的全双工字节流面向连接的协议。
它要为用户进程提供虚电路服务,并为数据可靠传输建立检查。
(注:
大多数网络用户程序使用TCP)
UDP:
用户数据报协议(UserDatagramProtocol)
这是提供给用户进程的无连接协议,用于传送数据而不执行正确性检查。
FTP:
文件传输协议(FileTransferProtocol)
允许用户以文件操作的方式(文件的增、删、改、查、传送等)与另一主机相互通信。
SMTP:
简单邮件传送协议(SimpleMailTransferProtocol)
SMTP协议为系统之间传送电子邮件。
TELNET:
终端协议(TelnetTerminalProcotol)
允许用户以虚终端方式访问远程主机
HTTP:
超文本传输协议(HypertextTransferProcotol)
TFTP:
简单文件传输协议(TrivialFileTransferProtocol)
2、TCP/IP特点
TCP/IP协议的核心部分是传输层协议(TCP、UDP),网络层协议(IP)和物理接口层,这三层通常是在操作系统内核中实现。
因此用户一般不涉及。
编程时,编程界面有两种形式:
一、是由内核心直接提供的系统调用;二、使用以库函数方式提供的各种函数。
前者为核内实现,后者为核外实现。
用户服务要通过核外的应用程序才能实现,所以要使用套接字(socket)来实现。
图1.2是TCP/IP协议核心与应用程序关系图。
(图1.2)
二、专用术语
1、套接字
套接字是网络的基本构件。
它是可以被命名和寻址的通信端点,使用中的每一个套接字都有其类型和一个与之相连听进程。
套接字存在通信区域(通信区域又称地址簇)中。
套接字只与同一区域中的套接字交换数据(跨区域时,需要执行某和转换进程才能实现)。
WINDOWS中的套接字只支持一个域——网际域。
套接字具有类型。
WINDOWSSOCKET1.1版本支持两种套接字:
流套接字(SOCK_STREAM)和数据报套接字(SOCK_DGRAM)
2、WINDOWSSOCKETS实现
一个WINDOWSSOCKETS实现是指实现了WINDOWSSOCKETS规范所描述的全部功能的一套软件。
一般通过DLL文件来实现
3、阻塞处理例程
阻塞处理例程(blockinghook,阻塞钩子)是WINDOWSSOCKETS实现为了支持阻塞套接字函数调用而提供的一种机制。
4、多址广播(multicast,多点传送或组播)
是一种一对多的传输方式,传输发起者通过一次传输就将信息传送到一组接收者,与单点传送
(unicast)和广播(Broadcast)相对应。
一、客户机/服务器模式
在TCP/IP网络中两个进程间的相互作用的主机模式是客户机/服务器模式(Client/Servermodel)。
该模式的建立基于以下两点:
1、非对等作用;2、通信完全是异步的。
客户机/服务器模式在操作过程中采取的是主动请示方式:
首先服务器方要先启动,并根据请示提供相应服务:
(过程如下)
1、打开一通信通道并告知本地主机,它愿意在某一个公认地址上接收客户请求。
2、等待客户请求到达该端口。
3、接收到重复服务请求,处理该请求并发送应答信号。
4、返回第二步,等待另一客户请求
5、关闭服务器。
客户方:
1、打开一通信通道,并连接到服务器所在主机的特定端口。
2、向服务器发送服务请求报文,等待并接收应答;继续提出请求……
3、请求结束后关闭通信通道并终止。
二、基本套接字
为了更好说明套接字编程原理,给出几个基本的套接字,在以后的篇幅中会给出更详细的使用说明。
1、创建套接字——socket()
功能:
使用前创建一个新的套接字
格式:
SOCKETPASCALFARsocket(intaf,inttype,intprocotol);
参数:
af:
通信发生的区域
type:
要建立的套接字类型
procotol:
使用的特定协议
2、指定本地地址——bind()
功能:
将套接字地址与所创建的套接字号联系起来。
格式:
intPASCALFARbind(SOCKETs,conststructsockaddrFAR*name,intnamelen);
参数:
s:
是由socket()调用返回的并且未作连接的套接字描述符(套接字号)。
其它:
没有错误,bind()返回0,否则SOCKET_ERROR
地址结构说明:
structsockaddr_in
{
shortsin_family;//AF_INET
u_shortsin_port;//16位端口号,网络字节顺序
structin_addrsin_addr;//32位IP地址,网络字节顺序
charsin_zero[8];//保留
}
3、建立套接字连接——connect()和accept()
功能:
共同完成连接工作
格式:
intPASCALFARconnect(SOCKETs,conststructsockaddrFAR*name,intnamelen);
SOCKETPASCALFARaccept(SOCKETs,structsockaddrFAR*name,intFAR*addrlen);
参数:
同上
4、监听连接——listen()
功能:
用于面向连接服务器,表明它愿意接收连接。
格式:
intPASCALFARlisten(SOCKETs,intbacklog);
5、数据传输——send()与recv()
功能:
数据的发送与接收
格式:
intPASCALFARsend(SOCKETs,constcharFAR*buf,intlen,intflags);
intPASCALFARrecv(SOCKETs,constcharFAR*buf,intlen,intflags);
参数:
buf:
指向存有传输数据的缓冲区的指针。
6、多路复用——select()
功能:
用来检测一个或多个套接字状态。
格式:
intPASCALFARselect(intnfds,fd_setFAR*readfds,fd_setFAR*writefds,
fd_setFAR*exceptfds,conststructtimevalFAR*timeout);
参数:
readfds:
指向要做读检
- 配套讲稿:
如PPT文件的首页显示word图标,表示该PPT已包含配套word讲稿。双击word图标可打开word文档。
- 特殊限制:
部分文档作品中含有的国旗、国徽等图片,仅作为作品整体效果示例展示,禁止商用。设计者仅对作品中独创性部分享有著作权。
- 关 键 词:
- VC MFCsocket 编程