MFC的UDP编程实现[通俗易懂]

MFC的UDP编程实现[通俗易懂]1、编程原理UDP是面向非连接的通信协议,比TCP协议简单很多。无论是服务器端还是客户端,其通信过程概括为:创建套接字(socket)–>绑定(bind)–>发送send(或接收recv)–>关闭套接字(closesocket) 2、特殊地址:在实际通信网络中,我们几乎不会用到“0.0.0.0″和“127.0.0.1”这样的IP地址。但是在一台计算机上,特别用于某些测试用

大家好,又见面了,我是你们的朋友全栈君。如果您正在找激活码,请点击查看最新教程,关注关注公众号 “全栈程序员社区” 获取激活教程,可能之前旧版本教程已经失效.最新Idea2022.1教程亲测有效,一键激活。

Jetbrains全系列IDE使用 1年只要46元 售后保障 童叟无欺

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

 

 

 

 

版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 举报,一经查实,本站将立刻删除。

发布者:全栈程序员-用户IM,转载请注明出处:https://javaforall.cn/196203.html原文链接:https://javaforall.cn

【正版授权,激活自己账号】: Jetbrains全家桶Ide使用,1年售后保障,每天仅需1毛

【官方授权 正版激活】: 官方授权 正版激活 支持Jetbrains家族下所有IDE 使用个人JB账号...

(0)


相关推荐

  • 金士顿16G优盘_金士顿u盘格式化分配单元大小

    金士顿16G优盘_金士顿u盘格式化分配单元大小事情起因好好的金士顿16g优盘(绝对是真的,之前本人已经使用了2年多),今天本来准备用U盘装个win10系统,从微软官网下载了MediaCreationTool.exe用这个工具做了一个U盘系统,然后装系统(系统也没有装成。。。。。悲剧),谁知道重启之后,优盘可以识别,但是只显示一个盘符,没有容量,双击优盘,就显示请插入优盘之类的。换了一台电脑,插上U盘,显示需要格式化,那就格式化吧。。。。。。几

  • MPLS 虚拟专用网络 Hub and Spoke实验

    MPLS 虚拟专用网络 Hub and Spoke实验

  • 基因突变基本知识「建议收藏」

    基因突变基本知识「建议收藏」基因、染色体、蛋白质、DNA,RNA之间的关系是什么?赛福基因公开课今天正式开讲。第一课我们来对基因检测进行基本的介绍。今天我主要从以下两个方面介绍一下基因检测的基础知识,一是基因,包括细胞、染

  • python3实现网络字节序和ipv4、ipv6互转[通俗易懂]

    文章目录1.前言2.什么是是网络字节序3.ipv4和ipv6简介4.转换5.参考文献1.前言2.什么是是网络字节序3.ipv4和ipv6简介4.转换5.参考文献[1][2]

  • Loadrunner11激活成功教程详解 .[通俗易懂]

    Loadrunner11激活成功教程详解 .[通俗易懂]使用说明:要以管理员的身份运行1、正常安装完LR11后。然后双击deletelicense.exe2、然后解压替换其中的2个DLL文件拷贝到”C:\ProgramFiles\HP\LoadRunner\bin\”下替换原有文件3、进入LR,输入以上的序列号即可global-100:AEACFSJI-YASEKJJKEAHJD-BCLBRweb-10000:AEABEX

  • springboot介绍一下_SpringBoot打包

    springboot介绍一下_SpringBoot打包一、SpringBoot和SpringMVC的关系SpringBoot是SpringMVC的升级版SpringBoot的特点:化繁为简,简化配置微服务->SpringCloud->SpringBoot二、前置知识利用maven构建项目Spring注解RESTfulAPI

发表回复

您的电子邮箱地址不会被公开。

关注全栈程序员社区公众号