基于visual studio 2013 环境下 udp 单播 协议Demo C++


前言

UDP是一个无连接协议,传输数据之前源端和终端不建立连接,当它想传送时就简单地去抓取来自应用程序的数据,并尽可能快地把它扔到网络上。在发送端,UDP传送数据的速度仅仅是受应用程序生成数据的速度、计算机的能力和传输带宽的限制;在接收端,UDP把每个消息段放在队列中,应用程序每次从队列中读一个消息段。
由于传输数据不建立连接,因此也就不需要维护连接状态,包括收发状态等,因此一台服务机可同时向多个客户机传输相同的消息。
UDP信息包的标题很短,只有8个字节,相对于TCP的20个字节信息包而言UDP的额外开销很小。
吞吐量不受拥挤控制算法的调节,只受应用软件生成数据的速率、传输带宽、源端和终端主机性能的限制。
UDP是面向报文的。发送方的UDP对应用程序交下来的报文,在添加首部后就向下交付给IP层。既不拆分,也不合并,而是保留这些报文的边界,因此,应用程序需要选择合适的报文大小。

虽然UDP是一个不可靠的协议,但它是分发信息的一个理想协议。例如,在屏幕上报告股票市场、显示航空信息等等。UDP也用在路由信息协议RIP(Routing Information Protocol)中修改路由表。在这些应用场合下,如果有一个消息丢失,在几秒之后另一个新的消息就会替换它。UDP广泛用在多媒体应用中。

二、visual studio 2013 环境

1. 发送端完整 代码如下(示例):

#include<iostream>
#include<WinSock2.h>
#include<WS2tcpip.h>
 
int send_a(INT16 port, char ip[20]);
using namespace std;
 
#pragma comment(lib,"ws2_32.lib")
 
int main()
{
	
 
 
	send_a(6000,"127.0.0.1"); //发送目标的端口 及IP
	return 0;
}
 
 
int send_a(INT16 port,char ip[20])
{
	WORD wVersionRequested;
	WSADATA wsaData; //初始化信息
	wVersionRequested = MAKEWORD(1, 1);
	int err = WSAStartup(wVersionRequested, &wsaData);
	if (err != 0)
	{
		return -1;
	}
	if (LOBYTE(wsaData.wVersion) != 1 || HIBYTE(wsaData.wVersion) != 1)
	{
		WSACleanup();
		return -1;
	}
	// 创建套接字
	SOCKET sockCli = socket(AF_INET, SOCK_DGRAM, 0);
 
	// 发送数据
	//不需要建立连接
	SOCKADDR_IN addrSrv,addrlocal;
	
 
	addrlocal.sin_family = AF_INET;
	addrlocal.sin_port = htons(port);
	addrlocal.sin_addr.s_addr = inet_addr(ip);
 
	bind(sockCli,(const sockaddr*)&addrlocal,sizeof(addrlocal));
 
	addrSrv.sin_family = AF_INET;
	addrSrv.sin_port = htons(port);
	addrSrv.sin_addr.s_addr = inet_addr(ip);
	//inet_pton(AF_INET, "127.0.0.1", &addrSrv.sin_addr);
 
 
	sendto(sockCli, "huanhuncao", strlen("huanhuncao"), 0, (SOCKADDR*)&addrSrv, sizeof(SOCKADDR));
 
 
	// 关闭套接字
	closesocket(sockCli);
 
	WSACleanup();
}

2. 接收端完整 代码如下(示例):

 
#include<stdio.h>
#include<tchar.h>
#include <iostream>
#include <WinSock2.h>
#include <Windows.h>
#include <WS2tcpip.h>
using namespace std;
 
int receive_a(int port, char b[14]);
#pragma comment(lib, "ws2_32.lib")
int _tmain(int argc, _TCHAR* argv[])   //_tmain,要加#include <tchar.h>才能用
{
	receive_a(6000, "127.0.0.1");    //调用函数
	return 0;
}
int receive_a(int port,char b[14])   //封装接收函数
{
	WSAData wsd;           //初始化信息
	SOCKET soRecv;         //接收SOCKET
	char* pszRecv = NULL;  //接收数据的数据缓冲区指针
	int nRet = 0;
	//int i = 0;
	int dwSendSize = 0;
	SOCKADDR_IN siRemote, siLocal;    //远程发送机地址和本机接收机地址
 
	//启动Winsock
	if (WSAStartup(MAKEWORD(2, 2), &wsd) != 0) {
		cout << "WSAStartup Error = " << WSAGetLastError() << endl;
		return 0;
	}
	else {
		cout << "start Success" << endl;
	}
 
	//创建socket
	soRecv = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP);
	if (soRecv == SOCKET_ERROR) 
	{
		cout << "socket Error = " << WSAGetLastError() << endl;
		return 1;
	}
	else 
	{
		cout << "socket Success" << endl;
	}
 
	//设置端口号
	int nPort = 5150;
	siLocal.sin_family = AF_INET;
	siLocal.sin_port = htons(port);         //设置端口
	siLocal.sin_addr.s_addr = inet_addr(b);    //设置IP
	//inet_pton(AF_INET, "127.0.0.1", (void*)&siLocal.sin_addr.s_addr);
 
	//绑定本地地址到socket
	if (bind(soRecv, (SOCKADDR*)&siLocal, sizeof(siLocal)) == SOCKET_ERROR)
	{
		cout << "bind Error = " << WSAGetLastError() << endl;
		return 1;
	}
	else 
	{
		cout << "bind Success" << endl;
	}
 
	//申请内存
	pszRecv = new char[4096];
	if (pszRecv == NULL) 
	{
		cout << "pszRecv new char Error " << endl;
		return 0;
	}
	else 
	{
		cout << "pszRecv new char Success" << endl;
	}
 
	// 一直等待数据
	while (true)
	{
		
		dwSendSize = sizeof(siRemote);
		//开始接受数据
		nRet = recvfrom(soRecv, pszRecv, 4096, 0, (SOCKADDR*)&siRemote, &dwSendSize);
		if (nRet == SOCKET_ERROR)
		{
			cout << "recvfrom Error " << WSAGetLastError() << endl;
			break;
		}
		else if (nRet == 0) 
		{
			break;
		}
		else
		{
			pszRecv[nRet] = '\0';
			char sendBuf[20] = { '\0' };
			inet_ntop(AF_INET, (void*)&siRemote.sin_addr, sendBuf, 16);
			cout << "IP地址: " << sendBuf << endl
				<< "数据: " << pszRecv << endl;
		}
	}
	//关闭socket连接
	closesocket(soRecv);
	delete[] pszRecv;
 
	//清理
	WSACleanup();
	system("pause");
}

总结

sendto 函数解析

 int sendto(int s, const void *buf, int len, unsigned int flags, const struct sockaddr *to, int tolen);

返回值说明:

成功则返回实际传送出去的字符数,失败返回-1,错误原因会存于errno 中。

  • 参数说明:
    s: socket描述符;

    buf:UDP数据报缓存区(包含待发送数据);

    len: UDP数据报的长度;

    flags:调用方式标志位(一般设置为0);

    to:  指向接收数据的主机地址信息的结构体(sockaddr_in需类型转换);

    tolen:to所指结构体的长度;

recvfrom 函数解析

int recvfrom(int s, void *buf, int len, unsigned int flags,  struct sockaddr *from, int *fromlen); 

返回值说明:

成功则返回实际接收到的字符数,失败返回-1,错误原因会存于errno 中。

  • 参数说明:

    s: socket描述符;

    buf: UDP数据报缓存区(包含所接收的数据);

    len: 缓冲区长度。

    flags: 调用操作方式(一般设置为0)。

    from: 指向发送数据的客户端地址信息的结构体(sockaddr_in需类型转换);

    fromlen:指针,指向from结构体长度值。

  • 3
    点赞
  • 11
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 1
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

东.'

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值