UDP网络编程

步骤:
一、加载套接字库
二、创建套接字
三、套接字绑定
四、创建接收线程
五、启动发送

一、加载套接字库

#include <Afxsock.h>//需要添加此头文件
if(!AfxSocketInit())
{
	AfxMessageBox("加载套接字库失败!");
	return;
}

二、创建套接字

SOCKET m_socket;
m_socket = socket(AF_INET,SOCK_DGRAM,0);
if(INVALID_SOCKET==m_socket)
{
	AfxMessageBox("套接字创建失败!");
	return;
}

套接字需要定义成成员函数,因为在其他地方要使用。

三、套接字绑定

int retval;
SOCKADDR_IN addrSock;
addrSock.sin_family=AF_INET;	
addrSock.sin_addr.S_un.S_addr=htonl(INADDR_ANY);
if( bFlag )
{	
	//非0,绑定用户指定的端口
	int port=wPort;
	addrSock.sin_port=htons(port);	
	retval=bind(m_socket,(SOCKADDR*)&addrSock,sizeof(SOCKADDR));
	if( 0x00 != retval )
	{		
		AfxMessageBox("套接字绑定失败!");
		return ;
	}
}
else
{
	//0,绑定系统自动分配的端口
	int port=wPort;//一般给个初值,不建议从0开始。可以从10000开始。
	while(1)
	{
		addrSock.sin_port=htons(port);	
		retval=bind(m_socket,(SOCKADDR*)&addrSock,sizeof(SOCKADDR));
		if(0==retval)
		{
			//绑定成功
			break;
		}
		//绑定失败,端口加一继续试
		port++;
	}	
}	

INADDR_ANY:当电脑有多个网卡时,就会有多个IP地址,绑定时使用这个值,可以接收来自所有网卡的数据。

四、创建接收线程

//由于接收函数是阻塞模式,为了使超时重传能够起作用,为接收函数新建个线程
typedef struct re 
{
	SOCKET sock;	//已创建的套接字
	CCom *pCom;		//实例句柄或者对话框句柄pDlg	
}RECVPARAM_COM;
RECVPARAM_COM *pRecvParam=new RECVPARAM_COM;
pRecvParam->pCom = this;
pRecvParam->sock = m_socket;		
HANDLE hThread1 = CreateThread(NULL,0,RecvProc,(LPVOID)pRecvParam,0,NULL);
CloseHandle(hThread1);

//线程函数
DWORD WINAPI CCom::RecvProc(LPVOID lpParameter)
{
   	//接收参数
   	CCom *pCom = ((RECVPARAM_COM *)lpParameter)->pCom;
   	SOCKET sock =  ((RECVPARAM_COM *)lpParameter)->sock;
   	
   	int retval;
   	SOCKADDR_IN addrFrom;
   	int len=sizeof(SOCKADDR);
   	char UDP_RecvBuf[50]={0};		//接收缓冲区	   	
   	FRAME_HDR *frame_hdr = (FRAME_HDR *)UDP_RecvBuf;
   	FRAME_BODY_14 *frame_body_14 = (FRAME_BODY_14 *)&UDP_RecvBuf[3];
   	while(1)
   	{
   		retval=recvfrom(sock,UDP_RecvBuf,sizeof(UDP_RecvBuf),0,(SOCKADDR*)&addrFrom,&len);//如果没有数据到达,此函数会阻塞。
   		//能走到这一步,说明要么发生了错误,要么已经接收到了数据
   		if(SOCKET_ERROR==retval)
   		{	//接收函数调用失败,UDP时一般是WSAECONNRESET错误,不重要,可以忽略
   			AfxMessageBox("接收函数调用失败!");
   		}		
   		//接收数据过滤
   		if( (pCom->m_addrTo.sin_addr.S_un.S_addr == addrFrom.sin_addr.S_un.S_addr) &&
   			(pCom->m_addrTo.sin_port == addrFrom.sin_port)  )			
   		{	//是应答帧,解析数据,
   			//电脑作为通讯主动发起者时,建议对各个从机依次操作,即处理完一个再处理另一个,并且对从机的IP地址和端口进行过滤,才能保证收到的是有效的回应。  
   			//电脑作为服务器端,一般都是通讯的被动接受者,可以接收来自不同IP地址和端口的数据,则不能过滤。
   			…………								
   		}
   	}
   
   	//返回
   	return 0;
}

参数(套接字,接收缓冲区,接收数据长度,0,源地址,源地址长度指针)
recvfrom函数要放在死循环里,不停地等待数据的到来。当收到应答数据后,要通过标记通知主线程。

五、启动发送

//准备发送内容
FRAME_HDR *frame_hdr = (FRAME_HDR *)UDP_SendBuf;
FRAME_BODY_13 *frame_body_13 = (FRAME_BODY_13 *)&UDP_SendBuf[3];
frame_hdr->pass[0] = 0x55;
frame_hdr->pass[1] = 0xAA;
frame_hdr->type = FRAME_TYPE_SEND;
frame_body_13->type = m_bSubframeType;
//发送地址
m_addrTo.sin_family=AF_INET;
m_addrTo.sin_port=htons(1);\\对方端口号
m_addrTo.sin_addr.S_un.S_addr=htonl(m_dwIP);\\对方IP地址
//发送
sendto(m_socket,UDP_SendBuf,4,0,(SOCKADDR*)&m_addrTo,sizeof(SOCKADDR));

参数(套接字,发送缓冲区,发送数据长度,0,目标地址,目标地址长度)
一般不关注sendto的返回值,因为UDP是面向无连接的,所以必须由上层进行差错控制,是否发送成功只能通过对方的回应来判断。
连续重发时,中间需要加上延时,否则只有最后一条指令起作用。
//发送,防止丢包,多发几次

sendto(sock,UDP_SendBuf,sizeof(FRAME_HDR)+sizeof(FRAME_BODY_0F),0,(SOCKADDR*)&addrTo,sizeof(SOCKADDR));
Sleep(100);
sendto(sock,UDP_SendBuf,sizeof(FRAME_HDR)+sizeof(FRAME_BODY_0F),0,(SOCKADDR*)&addrTo,sizeof(SOCKADDR));
Sleep(100);
sendto(sock,UDP_SendBuf,sizeof(FRAME_HDR)+sizeof(FRAME_BODY_0F),0,(SOCKADDR*)&addrTo,sizeof(SOCKADDR));
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值