【计算机网络】基于UDP的简单通讯(服务端)

news2024/10/7 4:25:45

文章目录

    • 流程
    • 代码实现
      • 加载库
      • 创建套接字
      • 绑定ip
      • 接收数据
      • 发送数据
      • 关闭套接字、卸载库

流程

我们UDP通讯就像是在做小买卖,主要就是进行收发数据
在这里插入图片描述

实现UDP协议的服务端需要经过五步操作:

  1. 加载库(Ws2_32.lib)
  2. 创建套接字(socket())
  3. 绑定IP(bind())
  4. 收发数据(recvfrom()、sendto())
  5. 关闭套接字、卸载库(closesocket()、WSACleanup())

代码实现

加载库

在加载库时我们使用一个WSAStartup接口函数,它的返回值是int类型,是用来看是否加载成功的,参数有两个,第一个是输入参数,为WORD类型,用来输入版本号,第二个是输出参数,为WSADATA结构体类型,输出参数一般都为指针类型,所以我们要创建三个变量。由于用到的函数和数据类型都是WinSock2.h库中的,所以我们要先加载头文件

#include<iostream>
#include<WinSock2.h>
using namespace std;

加载库:

    int err = 0;
    WORD version = MAKEWORD(2, 2);
    WSADATA wsaData;
    err = WSAStartup(version, &wsaData);
    //判断返回值
    if (0 != err) {
        cout << "WSAStartup error" << endl;
        return 1;
    }
    //判断加载的版本是否是2.2版本
    if (2 != HIBYTE(wsaData.wVersion) || 2 != LOBYTE(wsaData.wVersion)) {
        cout << "WSAStartup version error" << endl;
        //卸载库
        WSACleanup();
        return 1;
    }else {
            cout << "WSAStartup success" << endl;
    }

创建套接字

创建套接字我们使用socket()函数,它的返回值为SOCKET类型,如果返回INVALID_SOCKET那么创建失败,我们可以通过WSAGetLastError()来打印错误码

socket()有三个参数,都为int类型,第一个参数af是address family的缩写,我们使用AF_INET(ipv4),第二个参数是type,我们使用Udp协议的类型SOCK_DGRAM,第三个参数是protocol,我们使用UDP协议的IPPROTO_UDP。

	SOCKET sock = socket(AF_INET,SOCK_DGRAM, IPPROTO_UDP);
	if (INVALID_SOCKET == sock) {
		cout << "socket error:" << WSAGetLastError() << endl;
		//卸载库
		WSACleanup();
		return 1;
	}
	else {
		cout << "socket success" << endl;
	}

绑定ip

使用bind()函数,返回值为int类型,如果返回值为SOCK_ERROR那就说明绑定失败了,有三个输入参数,第一个参数为SOCKET,第二个参数为sockaddr*,他是一个结构体指针,第三个参数为指针长度

因为结构体为输入参数,所以我们要为里面的参数赋值,它一共有两个参数,第一个是一个ushort类型,第二个是char数组,那么我们对char数组赋值时会特别麻烦,因为要按照一定的顺序进行赋值,所以这里还给了另一个和sockaddr一样大小的数组——sockaddr_in,这个数组就是将char数组分解成了好几个变量,我们只需要对这几个变量进行赋值就可以了。第一个变量是ip地址类型,我们用的ipv4类型,第二个是端口号,第三个是ip地址

在定义端口号时,由于不同计算机可能存储方式不同,可能是大端存储也可能是小端存储,所以我们有一个规定——网络字节序,是TCP/IP中规定好的一种数据表示格式,可以保证数据在不同主机之间传输时能够被正确解释。用到一个函数htons(),再绑定IP地址时,因为我们是接收所有网卡收到的数据,所以我们对主机内任意网卡都进行绑定。

	//是操作系统里面注册端口和ip地址,也就是说当前操作系统收到发给某个端口号和ip地址的数据,就是咱么程序要接收的
	sockaddr_in addr;
	addr.sin_family = AF_INET;
	addr.sin_port = htons(456789);  //转换成网络字节序,也就是大端存储,本机是小端存储
	addr.sin_addr.S_un.S_addr = INADDR_ANY;  //绑定所有网卡

	err = bind(sock,(sockaddr*)&addr,sizeof(addr));
	if (SOCKET_ERROR == err) {
		cout << "bind error" << endl;
		//关闭套接字
		closesocket(sock);
		//卸载库
		WSACleanup();
		return 1;
	}
	else {
		cout << "bind success" << endl;
	}

接收数据

接收数据我们使用recvfrom()函数,它的返回值有三种,如果接收数据成功就返回接收到的字节的个数,等于0就证明连接失败了,如果等于SOCK_ERROR就是接收失败了

函数的参数有六个,第一个为socket,意为使用哪个socket进行接收,第二个参数为char*,是一个输出参数,是用来接收数据的缓冲区,第三个参数为这个缓冲区的大小,第四个参数是一个标志位,用来决定当前的接收方式,我们在这里不做特殊设置,用默认的即可,下一个参数也是一个sockaddr *输出类型的参数,用来存放数据是从哪里来的,最后一个参数当然就是上一个参数的长度,但由于它属于是输出类型的参数,所以要变为指针类型

	int nRecvNum = 0;
	char recvBuf[1024] = "";
	sockaddr_in addrClient;
	int addrClientSize = sizeof(addrClient);
	while (true) {
		//4、接收数据
		nRecvNum = recvfrom(sock, recvBuf,sizeof(recvBuf),0, (sockaddr*)&addrClient,&addrClientSize);
		if (nRecvNum > 0) {
			//接收成功,打印一下接收到的数据内容和发送端的ip地址
			//"192.168.3.145"十进制四等分字符串类型ip地址
			//ulong类型的ip地址:addrClient.sin_addr.S_un.S_addr
			cout << "ip:" << inet_ntoa(addrClient.sin_addr) << " say: " << recvBuf << endl;
			//从ulong转换成字符串类型ip:inet_ntoa(addrClient.sin_addr);
			//从字符串类型转换成ulong类型的ip地址:inet_addr();
		}
		else {
			//接收失败,打印失败日志,结束循环
			cout << "recvfrom error" << WSAGetLastError() << endl;
			break;
		}
    }

发送数据

发送数据使用的是sendto()函数,他也需要卸载循环里,接在上面接收数据后面即可,比如我们发送一个“hahaha”,sendto函数返回值为int类型,如果等于SOCKET_ERROR,那么就是发送失败,它也有六个参数,和接收数据也十分相似,首先是发送用到的socket,然后是发送数据缓冲区和缓冲区大小,然后是标志位,最后是要发送的目标和它的大小,这些都为输入参数

因为我们这里是服务端,所以谁给我们发我们就会给谁一个hahaha,所以目标我们就填接收数据时用来接收的sockaddr

    char msg[] = "hahaha";
    nSendNum = sendto(sock,msg,sizeof(msg),0,(sockaddr*)&addrClient, addrClientSize);
    if (SOCKET_ERROR == nSendNum) {
        //发送失败,打印失败日志,结束循环
        cout << "sendto error" << WSAGetLastError() << endl;
        break;
    }

关闭套接字、卸载库

关闭套接字用到的函数为closesocket(),卸载库就是WSACleanup(),这两个函数在上面也都用到过了,这里就不在赘述了

	closesocket(sock);
	WSACleanup();

现在代码部分我们都写好了,还有一些可能需要的操作,首先我们在尝试运行的时候会发现inet_ntoa会报错,我们可以到项目属性中去将SDL检查关闭即可

在这里插入图片描述

在这里插入图片描述

再次运行,我们会发现出现了许多无法解析的外部符号的错误,那么是因为编译期找不到函数的实现,那么这些函数都是我们直接调用的,所以解决方法就是加载所需要的库

#pragma comment(lib,"Ws2_32.lib")

那么到此为止,我们的UDP服务端就写好了,测试一下也没什么问题,接下来我们就要写客户端了

在这里插入图片描述

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1041157.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

vue组件的通信

文章目录 组件通信父传子父传子:通过prop来进行通信 子传父先在父组件用注册方法 , 在子组件触发使用 emit 函数 组件间通信-平行组件使用事件总线的方法,也就是把整个vue提出来,当为一个事件总线 其他组件通信父组件 provide来提供变量,然后再子组件中通过inject来注入变量 组…

Java之IO流概述

1.1 什么是IO 生活中&#xff0c;你肯定经历过这样的场景。当你编辑一个文本文件&#xff0c;忘记了ctrls &#xff0c;可能文件就白白编辑了。当你电脑上插入一个U盘&#xff0c;可以把一个视频&#xff0c;拷贝到你的电脑硬盘里。那么数据都是在哪些设备上的呢&#xff1f;键…

FlashDuty Changelog 2023-09-21 | 自定义字段和开发者中心

FlashDuty&#xff1a;一站式告警响应平台&#xff0c;前往此地址免费体验&#xff01; 自定义字段 FlashDuty 已支持接入大部分常见的告警系统&#xff0c;我们将推送内容中的大部分信息放到了 Lables 进行展示。尽管如此&#xff0c;我们用户还是会有一些扩展或定制性的需求…

【yolov5】detect.py

执行方法: 代码 # YOLOv5 &#x1f680; by Ultralytics, AGPL-3.0 license """ Run YOLOv5 detection inference on images, videos, directories, globs, YouTube, webcam, streams, etc.Usage - sources:$ python detect.py --weights yolov5s.pt --source …

面经分享 | 某康安全开发工程师

本文由掌控安全学院 - sbhglqy 投稿 一、反射型XSS跟DOM型XSS的最大区别 DOM型xss和别的xss最大的区别就是它不经过服务器&#xff0c;仅仅是通过网页本身的JavaScript进行渲染触发的。 二、Oracle数据库了解多吗 平常用的多的是MySQL数据库&#xff0c;像Oracle数据库也有…

PHP脚本导出MySQL数据库

背景&#xff1a;有时候需要同步数据库的表结构和部分数据&#xff0c;同步全表数据非常大&#xff0c;也不适合。还有一个种办法是使用数据库的dump命令执行备份&#xff0c;无法进入服务器&#xff1f;没有权限怎么办&#xff1f; 这里只要能访问服务器中的 information_sch…

前端项目练习(练习-003-webpack-01)

学习webpack前&#xff0c;首先&#xff0c;创建一个web-003项目&#xff0c;内容和web-002一样。&#xff08;注意将package.json中的name改为web-003&#xff09; 想想&#xff0c;我们开发Java 的时候&#xff0c;Maven帮我们做的主要是编译&#xff0c;打包等等内容。开发前…

org.quartz.SchedulerConfigException: DataSource name not set.

解决&#xff1a; JobStore配置 原&#xff1a; prop.put("org.quartz.jobStore.class", "org.quartz.impl.jdbcjobstore.JobStoreTX"); 改为&#xff1a; prop.put("org.quartz.jobStore.class", "org.springframework.scheduling.qu…

论文笔记:ST2Vec: Spatio-Temporal Trajectory SimilarityLearning in Road Networks

2022 KDD 1 intro 现有的轨迹相似性学习方案强调空间相似性而忽视了时空轨迹的时间维度&#xff0c;这使得它们在有时间感知的场景中效率低下 如上图&#xff0c;在拼车过程中&#xff0c;T1表示司机计划的行程&#xff0c;T2和T3是两个想要搭车的人。T1和T2在空间上更接近&am…

Mac 苹果系统使用nvm use 切换node版本号

windows在使用 nvm 管理并切换 node 时&#xff0c;通过 nvm use 切换node版本会全局切换。也就是node版本号切换后只要不手动更改就会一直保持当前版本号不变。 但博主最近换了苹果系统后&#xff0c;发现苹果系统不能全局更改node版本。我在 vscode中使用nvm use x.x.x之后&…

Django(21):使用Celery任务框架

目录 Celery介绍Celery安装Celery使用项目文件和配置启动Celery编写任务调用异步任务查看任务执行状态及结果 设置定时和周期性任务配置文件添加任务Django Admin添加周期性任务启动任务调度器beat Flower监控任务执行状态Celery高级用法与注意事项给任务设置最大重试次数不同任…

东郊到家app小程序公众号软件开发预约同城服务系统成品源码部署

东郊到家app系统开发&#xff0c;东郊到家软件定制开发&#xff0c;东郊到家小程序APP开发&#xff0c;东郊到家源码定制开发&#xff0c;东郊到家模式系统定制开发 一、上门软件介绍 1、上门app是一家以推拿为主项&#xff0c;个人定制型的o2o平台&#xff0c;上门app平台提…

Nginx的反向代理、动静分离、负载均衡

反向代理 反向代理是一种常见的网络技术&#xff0c;它可以将客户端的请求转发到服务器群集中的一个或多个后端服务器上进行处理&#xff0c;并将响应结果返回给客户端。反向代理技术通常用于提高网站的可伸缩性和可用性&#xff0c;并且可以隐藏真实的后端服务器地址。 #user…

泡泡玛特城市乐园开园在即,知名潮玩IP落地北京朝阳

今年以来&#xff0c;文旅产业成为亮眼消费赛道&#xff0c;大IP主题乐园再次受到市场关注。优质IP可以为园区引流&#xff0c;帮助乐园摆脱门票经济&#xff0c;平衡收入结构。 国内“潮玩第一股”泡泡玛特近日宣布&#xff0c;国内首个潮玩行业沉浸式IP主题乐园——泡泡玛特…

内存对齐--面试常问问题和笔试常考问题

1.内存对齐的意义 C 内存对齐的主要意义可以简练概括为以下几点&#xff1a; 提高访问效率&#xff1a;内存对齐可以使数据在内存中以更加紧凑的方式存储&#xff0c;从而提高了数据的访问效率。处理器通常能够更快地访问内存中对齐的数据&#xff0c;而不需要额外的字节偏移计…

hadoop组件HDFS

HDFS里面的几个组件&#xff0c;分别有哪些功能和作用&#xff1f; Namenode:主角色,负责和客户端进行沟通.Datanode:从角色,负责存储数据Secondary namenode:秘书,服务器数据的收集&#xff0c;将信息传递给namenode注&#xff1a;Namenode宕机时集群会通过选举机制&#xff…

vue安装依赖报错install i 报错提示npm audit fix --force,or `npm audit` for details

vue项目执行npm install初始化后报错 run npm audit fix to fix them, or npm audit for details 出现这类提醒&#xff0c;按照如下操作进行 1、首先安装模块依赖&#xff1a; npm install &#xff08;npm audit fix 含义&#xff1a; 检测项目依赖中的漏洞并自动安装需要…

Java笔记三

包机制&#xff1a; 为了更好地组织类&#xff0c;Java提供了包机制&#xff0c;用于区别类名的命名空间。 包语句的语法格式为&#xff1a;pack pkg1[. pkg2[. pkg3...]]; 般利用公司域名倒置作为包名&#xff1b;如com.baidu.com&#xff0c;如图 导包&#xff1a; 为了能够…

协议-TCP协议-基础概念03-Keep live保活机制-TCP RST-TCP连接

Keep live保活机制-TCP RST-TCP连接 参考来源&#xff1a; 《极客专栏-网络排查案例课》 Keep live保活机制 定时发送心跳探测包&#xff1b; 对于心跳回复包有超时限制&#xff1b; 要打开这个 TCP Keep-alive 特性&#xff0c;你需要使用 setsockopt() 系统调用&#xff0…

Ps:缩放工具

缩放工具 Zoom Tool 常用于对图像进行视图上的放大和缩小。在查看图像细节、处理图像时极为常用。 快捷键&#xff1a;Z ◆ ◆ ◆ 常用操作方法与技巧 1、快捷键 Z 是一个弹簧键。即&#xff0c;在其它工具的状态下&#xff0c;按住 Z 键不放就会临时切换到缩放工具&#xff…