Day3:Windows网络编程-UDP

news/2024/5/18 16:08:43 标签: 网络, udp, tcp/ip, windows

  对比TCP与UDP的通信区别

 UDP Server没有listen()和accept()

TCP Server

#include <iostream>
#include <WinSock2.h>
// 包含网络库
#pragma comment(lib,"ws2_32.lib")
using namespace std;

int main()
{
	// 1. 初始化套接字 初始化套接字库
	cout << "UDP Server" << endl;
	WORD wVersion;
	WSADATA wsaData;
	int err;
	wVersion = MAKEWORD(1, 1);
	err = WSAStartup(wVersion, &wsaData);
	if (err != 0)
	{
		return err;
	}
	if (LOBYTE(wsaData.wVersion) != 1 || HIBYTE(wsaData.wVersion) != 1)
	{
		WSACleanup();
		return -1;
	}

	// 2. 创建套接字
	SOCKET sockSrv = socket(AF_INET,SOCK_DGRAM,0);
	if (INVALID_SOCKET == sockSrv) //加入容错机制 
	{
		printf("socket errorNo = %d\n",GetLastError());
		return -1;
	}


	// 3.分配地址和端口
	SOCKADDR_IN addrSrv;
	// h:host to n:net l:long 主机字节序转换为网络字节序
	addrSrv.sin_addr.S_un.S_addr = htonl(INADDR_ANY); 
	addrSrv.sin_family = AF_INET;
	addrSrv.sin_port = htons(6001);

	if(SOCKET_ERROR == bind(sockSrv,(SOCKADDR*)&addrSrv,sizeof(SOCKADDR_IN)))
	{
		printf("bind errorNo = %d\n",GetLastError());
		return -1;
	}

	// 4. 等待接收数据
	SOCKADDR_IN addrCli; // 目的套接字地址族
	int len = sizeof(SOCKADDR_IN);
	char recvBuf[100] = {0};
	char sendBuf[100] = {0};
	while(true)
	{
		recvfrom(sockSrv, recvBuf, 100, 0, (SOCKADDR*)&addrCli, &len);
		cout << recvBuf << endl;

		sprintf_s(sendBuf, 100, "Ack:%s", recvBuf);
		sendto(sockSrv, sendBuf,strlen(sendBuf) + 1,0, (SOCKADDR*)&addrCli, len);
		
	
	}
	// 5. 关闭套接字
	closesocket(sockSrv);
	WSACleanup();
	system("pause");
	return 0;
}

代码逻辑:

  1. 初始化套接字 初始化套接字库
  2. 创建套接字
  3. 分配地址和端口
  4. bind() 分配地址和端口
  5. 等待接收数据 recvfrom()接收数据 sendto()发送数据  while循环

TCP Client

#include <iostream>
#include <WinSock2.h>
// 包含网络库
#pragma comment(lib,"ws2_32.lib")
using namespace std;

int main()
{
	// 1. 初始化套接字 初始化套接字库
	cout << "UDP Client" << endl;
	WORD wVersion;
	WSADATA wsaData;
	int err;
	wVersion = MAKEWORD(1, 1);
	err = WSAStartup(wVersion, &wsaData);
	if (err != 0)
	{
		return err;
	}
	if (LOBYTE(wsaData.wVersion) != 1 || HIBYTE(wsaData.wVersion) != 1)
	{
		WSACleanup();
		return -1;
	}

	// 2. 创建UDP套接字
	SOCKET sockCli = socket(AF_INET, SOCK_DGRAM, 0);
	if (INVALID_SOCKET == sockCli) //加入容错机制 
	{
		printf("socket errorNo = %d\n", GetLastError());
		return -1;
	}

	// 3. 填充地址和端口
	SOCKADDR_IN addrSrv;
	addrSrv.sin_addr.S_un.S_addr = inet_addr("127.0.0.1");
	addrSrv.sin_family = AF_INET;
	addrSrv.sin_port = htons(6001);

	int len = sizeof(SOCKADDR_IN);
	char sendBuf[100] = "hello";
	char recvBuf[100] = { 0 };

	// 4.发送UDP数据
	sendto(sockCli, sendBuf, strlen(sendBuf) + 1,0,(SOCKADDR*)&addrSrv, len);

	// 5.接收UDP数据
	recvfrom(sockCli,recvBuf,100,0,(SOCKADDR*)&addrSrv,&len);
	cout << recvBuf << endl;
	closesocket(sockCli);
	system("pause");
	return 0;
}

代码逻辑:

  1. 初始化套接字 初始化套接字库
  2. 创建UDP套接字
  3. 填充地址和端口
  4. 直接发送/接收数据

运行结果:

关于bind()函数

官方文档:绑定函数将本地地址与套接字相关联。

int bind(
  [in] SOCKET         s,
       const sockaddr *addr,
  [in] int            namelen
);

bind()是一个用于将套接字(socket)与特定的网络地址(IP 地址和端口号)绑定的函数。它在套接字创建后,但在进行网络通信之前被调用。

三个参数的含义:

  • sockfd:需要绑定的套接字描述符(socket descriptor)。
  • addr:指向要绑定的网络地址的结构体指针,通常是 struct sockaddr 或其派生结构体的指针。
  • addrlen网络地址结构体的长度。

关于sendto()函数

官方文档:

sendto 函数将数据发送到特定目标。

int WSAAPI sendto(
  [in] SOCKET         s,
  [in] const char     *buf,
  [in] int            len,
  [in] int            flags,
  [in] const sockaddr *to,
  [in] int            tolen
);

sendto() 是用于发送数据到指定目标地址的函数,通常用于无连接的数据报套接字(SOCK_DGRAM)。它可以向指定的目标地址发送数据,并指定数据的长度和其他参数。

参数的含义:

  • s:要发送数据的套接字描述符(socket descriptor)。
  • buf:指向包含要发送的数据的缓冲区的指针。
  • len:要发送的数据的长度。
  • flags:发送标志,用于控制发送操作的行为,例如是否启用特定的选项。
  • to:指向目标地址的结构体指针,通常是 struct sockaddr 或其派生结构体的指针。
  • tolen:目标地址结构体的长度。

关于recvfrom()函数

官方文档:

recvfrom 函数接收数据报并存储源地址。

int recvfrom(
  [in]                SOCKET   s,
  [out]               char     *buf,
  [in]                int      len,
  [in]                int      flags,
  [out]               sockaddr *from,
  [in, out, optional] int      *fromlen
);

recvfrom() 是用于接收来自指定源地址的数据的函数,通常用于无连接的数据报套接字(SOCK_DGRAM)。它可以从指定的源地址接收数据,并存储到指定的缓冲区中。

参数含义:

  • s:要接收数据的套接字描述符(socket descriptor)。
  • buf:指向接收数据的缓冲区的指针。
  • len:缓冲区的长度,即最大接收的字节数。
  • flags:接收标志,用于控制接收操作的行为,例如是否启用特定的选项。
  • from:指向存储源地址的结构体的指针,通常是 struct sockaddr 或其派生结构体的指针。
  • fromlen:指向存储源地址结构体长度的整型指针。

http://www.niftyadmin.cn/n/368859.html

相关文章

《The Element of Style》阅读笔记 —— 章节 III A Few Matters of Form

前言&#xff1a;本篇为书籍《The Element of Style》第三章的阅读笔记。 本书电子版链接&#xff1a;http://www.jlakes.org/ch/web/The-elements-of-style.pdf 章节 I Elementary Rules of Usage 阅读笔记&#xff1a;链接章节 II Elementary Principles of Composition 阅读…

js常用事件

js常用事件如下&#xff1a; onmouseover&#xff1a;鼠标被移到某元素之上&#xff1b; onmouseout&#xff1a;鼠标从某元素移开&#xff1b; onfocus&#xff1a;元素获得焦点&#xff1b; onblur&#xff1a;元素失去焦点&#xff1b; onclick&#xff1a;鼠标单击事件…

G0第23章:GORM基本示例、GORM Model定义、主键、表名、列名的约定

04 GORM基本示例 注意: 本文以MySQL数据库为例&#xff0c;讲解GORM各项功能的主要使用方法。 往下阅读本文前&#xff0c;你需要有一个能够成功连接上的MySQL数据库实例。 Docker快速创建MySQL实例 很多同学如果不会安装MySQL或者懒得安装MySQL&#xff0c;可以使用一下命令…

支付宝SDK接口调试- cpolar内网穿透工具实现公网地址调试(1)

文章目录 1.测试环境2.本地配置3. 内网穿透3.1 下载安装cpolar内网穿透3.2 创建隧道 4. 测试公网访问5. 配置固定二级子域名5.1 保留一个二级子域名5.2 配置二级子域名 6. 使用固定二级子域名进行访问 转发自cpolar内网穿透的文章&#xff1a;Java支付宝沙箱环境支付&#xff0…

阿里云服务器配置怎么选择合适?CPU内存带宽配置

阿里云服务器配置如何选择&#xff1f;个人用户选择通用算力型u1云服务器或轻量应用服务器&#xff0c;2核2G、2核4G配置即可&#xff0c;企业公司用户可以选择独享型ECS计算型c7、通用型g7等&#xff0c;4核8G、8核16G、4核32G等配置&#xff0c;阿里云百科来详细说下不同用户…

50 Projects 50 Days - Scroll Animation 学习记录

项目地址 Scroll Animation 展示效果 Scroll Animation 实现思路 HTML结构比较简单&#xff0c;就是10个盒子元素。当鼠标滚动时&#xff0c;盒子分别从左右移动过来。 思路上最开始想到的是给每一个盒子标记一个序号&#xff0c;滚动屏幕后&#xff0c;计算已经划动屏幕的…

opencv_c++学习(二十七)

一、单目相机模型 上图为针孔相机成像原理&#xff0c;蓝色坐标中的O即为镜头光心。成像原理与小孔成像相同。 单目相机映射关系如下&#xff1a; 将上式进行变换&#xff0c;就可以从三位空间映射到2维平面的公式。 相机的畸变公式如下&#xff1a; 二、模型投影函数 vo…

C++数据结构:散列表简单实现(hash表)

文章目录 前言一、设计思想二、实现步骤1、定义节点2、定义Hash表类 三、数据示例总结 前言 散列表是一种常用的数据结构&#xff0c;它可以快速地存储和查找数据。散列表的基本思想是&#xff0c;将数据的关键字映射到一个有限的地址空间中&#xff0c;然后在该地址空间中存储…