zoukankan      html  css  js  c++  java
  • MFC的UDP编程实现

     

    MFC的UDP编程实现

    分类: C/C++ 网络与通信

    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_IN为sockadd_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值,否则返回-1(SOCKET_ERROR

    如:

    int retval;

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

    *(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函数,将这些过程全放进去即可。

  • 相关阅读:
    oracle 判断字符串是否包含指定内容
    java 如何使用多线程调用类的静态方法?
    oracle 快速复制表结构、表数据
    oracle 清空表数据的2种方式及速度比较
    一、Instrument之Core Animation工具
    net登录积分(每天登录积分仅仅能加一次) 时间的比較
    正规方程 Normal Equation
    笑谈贝叶斯网络(干货)上
    SQL SERVER 面试题
    好的创始人想要改变世界,最好的创始人还要不放弃——扎克伯格清华中文演讲
  • 原文地址:https://www.cnblogs.com/jack-jia-moonew/p/4238760.html
Copyright © 2011-2022 走看看