MFC的UDP编程实现

1、编程原理

UDP是面向非连接的通信协议,比TCP协议简单很多。无论是服务器端还是客户端,其通信过程概括为:

创建套接字(socket)-->绑定(bind)-->发送send(或接收recv)-->关闭套接字(closesocket

 

2、特殊地址:

在实际通信网络中,我们几乎不会用到“0.0.0.0"和“127.0.0.1”这样的IP地址。但是在一台计算机上,特别用于某些测试用途时,这类地址就有用武之地了。

(1)环回地址:127.0.0.1,该地址可用于本地计算机测试接收功能,即本地计算机绑定一IP地址(如192.168.1.2)时,可向环回地址发送信息M,则本地计算机可收到“反馈”回来的同样信息M(具有服务端性质)

(2)全零网络地址:0.0.0.0,可作为源地址,表示整个网络,即“任意地址”

3、重要函数

(1)创建套接字函数socket()

函数原型:SOCKET PASCAL FAR socket( int af, int type, int protocol);

返回值说明:成功返回套接字,失败返回INVALID_SOCKET;

创建流套接字(TCP)时,如:m_socket = socket(AF_INET,SOCK_STREAM,0)

创建数据报套接字(UDP),如:m_socket = socket(AF_INET,SOCK_DGRAM,0)

在成功创建套接字之后,需要填充sockaddr_in结构体作为网络函数参数:

struct sockaddr_in

   {

      shortint sin_family;//地址协议

     unsigned short int sin_port;//端口号

     struct in_addr sin_addr;//IP地址

     unsigned char sin_zero[8];// sockaddr与sockaddr_in两个数据结构保持大小相同而保留的空字节。

    }

如在VS2010中,有:

//SOCKADDR_INaddrSock;//SOCKADDR_INsockadd_in的宏定义,此变量在头文件中定义

((CIPAddressCtrl*)GetDlgItem(IDC_IPADDRESS2))->GetAddress(sourceIP);//获取控件上IP地址

addrSock.sin_family=AF_INET;

addrSock.sin_port=htons(6000);

addrSock.sin_addr.S_un.S_addr=htonl(sourceIP);//sourceIP表示运行该程序的主机IP

 

(2)绑定函数bind()

函数原型:int PASCAL FAR bind(SOCKET s, const struct sockaddr FAR *name,int namelen)

返回值说明:绑定成功,返回0值,否则返回-1SOCKET_ERROR

如:

int retval

retval = bind(m_socket,(SOCKADDR*)&addrSock, sizeof(SOCKADDR))//SOCKADDRsockaddr的宏定义

*3)创建线程函数CreateThread()

创建线程后,立即开启,调度线程函数:

RECVPARAM *pRecvParam=newRECVPARAM;

pRecvParam->sock=m_socket;

pRecvParam->hwnd=m_hWnd;

HANDLE hThread=CreateThread(NULL,0,RecvProc,(LPVOID)pRecvParam,0,NULL);//RecvProc为线程函数

CloseHandle(hThread);

 

//线程函数

DWORD WINAPICMyChatDlg::RecvProc(LPVOIDlpParameter)

{

//lpParmeter为创建线程是所提交的函数参数

    SOCKETsock=((RECVPARAM*)lpParameter)->sock;

    HWNDhwnd=((RECVPARAM*)lpParameter)->hwnd;

    deletelpParameter; //释放对象

SOCKADDR_IN addrFrom;

    int len=sizeof(SOCKADDR);

    char recvBuf[200];

    char tempBuf[300];

    int retval;

    while(TRUE)   //创建线程的必要性

    {

    retval=recvfrom(sock,recvBuf,200,0,(SOCKADDR*)&addrFrom,&len);//获取套接字接收内容

        if(SOCKET_ERROR==retval)

            break;

        sprintf(tempBuf,"%s说: %s",inet_ntoa(addrFrom.sin_addr),recvBuf);

 

        ::PostMessage(hwnd,WM_RECVDATA,0,(LPARAM)tempBuf);//提交消息,触发消息响应

    }

    return 0;

}

分析:

struct RECVPARAM

{

    SOCKET sock;

    HWND hwnd;

};//在头文件中定义该结构体

 

线程的创建是通过函数CreateThread来实现的,调用成功返回句柄和一个id。

HANDLE CreateThread(

LPSECURITY_ATTRIBUTES lpThreadAttributes,  //线程的安全属性,NULL为缺省值

DWORD dwStackSize,                        //线程堆栈的大小,0为系统缺省值

LPTHREAD_START_ROUTINE lpStartAddress,  //线程函数的起始地址可为线程函数名

LPVOID lpParameter,                      //传递给线程函数的参数,重要!

DWORD dwCreationFlags,              //线程创建后是否立即启动,0表示立即启动

LPDWORD lpThreadId                     //线程的ID号

);

(4)获取接收信息的recvfrom函数(经socket接收数据):

函数原型:ssize_trecvfrom(int sockfd,void *buf,int len,unsigned int flags, struct sockaddr*from,socket_t *fromlen);

参数含义详见:http://baike.baidu.com/view/1744189.htm

功能描述:该函数接收来自套接字的数据,数据存到缓冲区,并从sockaddr中可读取到相关网络参数(如接收数据的源地址等)

 

(5)发送函数函数sendto()

函数原型:intPASCAL FAR sendto (

IN SOCKET s,

IN const char FAR *buf,

IN int len,

IN int flags,

IN const structsockaddr FAR *to,

IN int tolen);

如:sendto(m_socket,strSend,strSend.GetLength()+1,0,(SOCKADDR*)&addrTo,sizeof(SOCKADDR));

4、关键点:

(1)UDP实现过程简单,关键是了解每个过程所需要函数及其使用方法

(2)为UDP通信创建线程,是设计更加合理

(3)套接字创建之后很重要的一步是填充sockaddr_in,绑定的成功与否与该结构体具有紧密的关系。

(4)如果是基于人机交互的实现模式,UDP通信之前的工作可以分成几个模块,而这些模块,注意要共用一个套接字(如在类中定义一个SOCKET变量)。如果有默认式的UDP通信模式,可以将UDP通信之前的工作放在一起,即定义一个initial函数,将这些过程全放进去即可。

 

 

 

 

  • 4
    点赞
  • 74
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
MFC(Microsoft Foundation Class)是微软公司提供的一个基于Windows的C++应用程序框架。MFC包含了许多类和函数库,可以帮助开发者更轻松地开发Windows应用程序。网络编程MFC框架中的一部分,通过MFC可以实现基于TCP或UDP协议的网络编程MFC中的网络编程主要依靠Windows Socket API来实现。Windows Socket API是Windows操作系统提供的一套网络编程接口,包括了TCP/IP协议栈以及与之相关的函数库和数据结构。MFC封装了Windows Socket API,提供了更加简单易用的网络编程接口。 以下是一个基于MFC的TCP客户端示例代码: ```cpp // 基于MFC的TCP客户端示例代码 #include "stdafx.h" #include "MFCNetworkProgramming.h" #include "MFCNetworkProgrammingDlg.h" #ifdef _DEBUG #define new DEBUG_NEW #endif // CMFCNetworkProgrammingApp BEGIN_MESSAGE_MAP(CMFCNetworkProgrammingApp, CWinApp) ON_COMMAND(ID_HELP, &CWinApp::OnHelp) END_MESSAGE_MAP() // CMFCNetworkProgrammingApp 构造 CMFCNetworkProgrammingApp::CMFCNetworkProgrammingApp() { // TODO: add construction code here, // Place all significant initialization in InitInstance } // 唯一的 CMFCNetworkProgrammingApp 对象 CMFCNetworkProgrammingApp theApp; // CMFCNetworkProgrammingApp 初始化 BOOL CMFCNetworkProgrammingApp::InitInstance() { // 初始化 MFC 和通用控件 AfxEnableControlContainer(); // 创建对话框 CMFCNetworkProgrammingDlg dlg; m_pMainWnd = &dlg; INT_PTR nResponse = dlg.DoModal(); // 删除对话框对象 if (nResponse == IDOK) { // TODO: Place code here to handle when the dialog is // dismissed with OK } else if (nResponse == IDCANCEL) { // TODO: Place code here to handle when the dialog is // dismissed with Cancel } // 删除该应用程序的最上层窗口,除非该应用程序是使用 // Control Panel 来关闭的或者有其他窗口在等待退出。 return FALSE; } ``` 这是一个基本的MFC框架,它创建了一个对话框,并将其作为程序的主窗口。接下来我们需要在对话框中实现TCP客户端的功能。以下是一个基于MFC的TCP客户端示例代码: ```cpp // 基于MFC的TCP客户端示例代码 #include "stdafx.h" #include "MFCNetworkProgramming.h" #include "MFCNetworkProgrammingDlg.h" #ifdef _DEBUG #define new DEBUG_NEW #endif // CMFCNetworkProgrammingDlg 对话框 CMFCNetworkProgrammingDlg::CMFCNetworkProgrammingDlg(CWnd* pParent /*=NULL*/) : CDialog(CMFCNetworkProgrammingDlg::IDD, pParent) { m_hIcon = AfxGetApp()->LoadIcon(IDR_MAINFRAME); } void CMFCNetworkProgrammingDlg::DoDataExchange(CDataExchange* pDX) { CDialog::DoDataExchange(pDX); DDX_Control(pDX, IDC_SERVER_IP, m_serverIP); DDX_Control(pDX, IDC_SERVER_PORT, m_serverPort); DDX_Control(pDX, IDC_DATA, m_data); } BEGIN_MESSAGE_MAP(CMFCNetworkProgrammingDlg, CDialog) ON_WM_PAINT() ON_WM_QUERYDRAGICON() //}}AFX_MSG_MAP ON_BN_CLICKED(IDC_CONNECT, &CMFCNetworkProgrammingDlg::OnBnClickedConnect) ON_BN_CLICKED(IDC_SEND, &CMFCNetworkProgrammingDlg::OnBnClickedSend) END_MESSAGE_MAP() // CMFCNetworkProgrammingDlg 消息处理程序 BOOL CMFCNetworkProgrammingDlg::OnInitDialog() { CDialog::OnInitDialog(); // 设置此对话框的图标。当应用程序主窗口不是对话框时, // 框架将自动执行此操作 SetIcon(m_hIcon, TRUE); // 设置大图标 SetIcon(m_hIcon, FALSE); // 设置小图标 // TODO: Add extra initialization here return TRUE; // 除非将焦点设置到控件,否则返回 TRUE } // 如果添加了最小化按钮,则需要以下代码来绘制该图标。 // 对于使用文档/视图模型的 MFC 应用程序,这将由框架自动完成。 void CMFCNetworkProgrammingDlg::OnPaint() { if (IsIconic()) { CPaintDC dc(this); // 用于绘制的设备上下文 SendMessage(WM_ICONERASEBKGND, reinterpret_cast<WPARAM>(dc.GetSafeHdc()), 0); // 使图标在工作区矩形中居中 int cxIcon = GetSystemMetrics(SM_CXICON); int cyIcon = GetSystemMetrics(SM_CYICON); CRect rect; GetClientRect(&rect); int x = (rect.Width() - cxIcon + 1) / 2; int y = (rect.Height() - cyIcon + 1) / 2; // 绘制图标 dc.DrawIcon(x, y, m_hIcon); } else { CDialog::OnPaint(); } } //当用户拖动最小化窗口时系统调用此函数取得光标 //显示。 HCURSOR CMFCNetworkProgrammingDlg::OnQueryDragIcon() { return static_cast<HCURSOR>(m_hIcon); } void CMFCNetworkProgrammingDlg::OnBnClickedConnect() { // 创建套接字 m_socket.Create(); // 获取服务器地址和端口 CString strIP, strPort; m_serverIP.GetWindowText(strIP); m_serverPort.GetWindowText(strPort); // 连接服务器 if (m_socket.Connect(strIP, _ttoi(strPort)) == FALSE) { AfxMessageBox(_T("连接服务器失败")); } else { AfxMessageBox(_T("连接服务器成功")); } } void CMFCNetworkProgrammingDlg::OnBnClickedSend() { // 获取发送数据 CString strData; m_data.GetWindowText(strData); // 发送数据 if (m_socket.Send(strData, strData.GetLength()) == SOCKET_ERROR) { AfxMessageBox(_T("发送数据失败")); } else { AfxMessageBox(_T("发送数据成功")); } } ``` 以上代码实现了一个基于MFC的TCP客户端,用户可以在界面上输入服务器地址、端口和数据,然后点击连接按钮进行连接,点击发送按钮可以向服务器发送数据。需要注意的是,在实际使用中需要根据具体情况进行相应的修改和完善。

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值