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

 

 

 

 

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

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

(0)
上一篇 2025年10月1日 下午4:22
下一篇 2025年10月1日 下午5:01


相关推荐

  • Wifi开坑

    Wifi开坑缘起:读书期间,大量接触通信基础,无线快速发展,目光关注点自然是高高的基站塔,以及小小的手机(这个信息社会浓缩操作系统、通信、开源和智能化(智能掌机)的结晶当然也不简单)。至于短距离通信里面的形形色色,眼花缭乱的Wifi、BLE(蓝牙)、Zigbee、体域网则是感知中盲区,异类。一直到博士后期到职业才隐隐感知到,天下大事必出于细的道理。云动:就如“小小”体域网(Bodyareanetwork)中除了通用的天线设计、收发、同步、多通道处理外还有特别关注的鲁棒性设计,如何高可靠无中断地始终获取无线信

    2022年7月21日
    16
  • JS,CSS是前端,JAVA PHP ASP是后端,数据库是后端的处理对象,非代表前后底

    JS,CSS是前端,JAVA PHP ASP是后端,数据库是后端的处理对象,非代表前后底大海-mysql-oracle(529513481)  19:02:18象我这边,前台都是php,而php做数据分析是不太理想的,做中间件没人力,难办横瓜(601069289) 19:20:15 用C写中间件D,PHP再调用D横瓜(601069289) 19:20:31 用C写中间件D,PHP再调用D横瓜(601069289) 19:20:3…

    2022年4月29日
    51
  • 矢量积与叉乘_向量积叉乘的几何意义

    矢量积与叉乘_向量积叉乘的几何意义矢量叉乘,向量外积原创不易,路过的各位大佬请点个赞矢量叉乘,向量外积矢量叉乘,向量外积1.矢量叉乘定义2.模长3.方向4.坐标运算6.叉乘矩阵(斜对称矩阵)6.叉乘运算规则1.矢量叉乘定义定义两个向量a\mathbf{a}a和b\mathbf{b}b,他们的叉乘可以写为a×b\mathbf{a}\times\mathbf{b}a×b本质上向量叉乘为向量旋转,满足右手螺旋准则;叉乘结果是一个向量,向量模长是向量A,B组成平行四边形的面积;向量方向是垂直于向量A,B组成的平面;也

    2025年7月28日
    4
  • windows7安装pycharm_pycharm安装教程2019

    windows7安装pycharm_pycharm安装教程2019配置:win7+cuda8.0+vs2015+cudnn6.0+python3.5+tensorflow1.4+pycharm大体思路是:先安装vs2015 再将cudnn6.0的bin路径加入环境变量,再安装tensorflow1.4,再安装pycharm (1)   安装vs2015 + cuda8.0     这一步跟安装其他vs版本一样,安

    2022年8月27日
    4
  • python 图片图像转化视频[通俗易懂]

    python 图片图像转化视频

    2022年2月19日
    48
  • linux安装svn服务器_linux安装svn客户端

    linux安装svn服务器_linux安装svn客户端1.https://tortoisesvn.net/downloads.html网站下载2.安装的时候如果出现下图的报错打开这个网站https://www.microsoft.com/zh-cn/download/confirmation.aspx?id=49062,会自动帮你下载下载完成后安装即可3.没有特殊需求则默认安装4.出现这个则安装成功MySQL安装…

    2022年8月18日
    9

发表回复

您的邮箱地址不会被公开。 必填项已用 * 标注

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