一个UDP下载服务器的实现(模拟下载文件)
本期分享的主要是使用UDP实现文件下载功能,需要自己编写服务器和客户端,实现的功能主要有以下几个:
(1)服务器可以为请求的用户下发文件数据(前提是服务器得有这个数据文件)
(2)客户端请求下载数据文件
下面带大家来认真分析下,大家可以对照我遇到的问题是不是大家有遇到,避免大家踩坑,server端代码如下:
首先当然还是头文件部分,没这个可不行呀,哈哈:
#ifndef __HEAD_H__
#define __HEAD_H__#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <unistd.h>
#include <fcntl.h>
#include <pthread.h>#endif
1.接下来看一下具体server的代码实现:
#include "head.h"struct sockaddr_in senaddr;//存放服务器的Ip以及端口号的结构体
int bindOfIP(const char *pIp, int Port) //绑定服务器的ip和端口
{int sockfd = 0;int ret = 0;sockfd = socket(AF_INET, SOCK_DGRAM, 0);if (-1 == sockfd){perror("fail to sockfd");return -1;}senaddr.sin_family = AF_INET;senaddr.sin_port = htons(Port);senaddr.sin_addr.s_addr = inet_addr(pIp);ret = bind(sockfd, (struct sockaddr *)&senaddr, sizeof(senaddr));if (-1 == ret){perror("fail to bind");return -1;}return sockfd;
}
以下是发送文件的模块,自从用了UDP发送数据才知道了IO的部分还比较欠缺,那么来看下那一部分有问题:
(1)当选择fread去读取文件的时候(第二个参数设置为1,也就是每次读取成员的大小一个字节),一定要知道它的返回值就是是成功读取文件字节的个数;只有当参数不是1的时候,那么返回值就是成功读取成员的个数;但是最终读取的成员最终还是存放在了我们定义的第一个参数中了;
ret = fread(tmpbuff, 1, sizeof(tmpbuff), fp);
因此在sendto的第三个参数中我们恰好可以使用fread的返回值;
sendto(sockfd, tmpbuff, ret, 0, sendaddr, len);
(2)不使用字节进行传输时,不能在sendto时把第三个变量换位strlen(tmpbuff),因为二进制文件不允许strlen;
int sendFile(char *filename, int sockfd, struct sockaddr *sendaddr, socklen_t len)
{FILE *fp = NULL;char tmpbuff[4096] = {0};ssize_t ret = 0;char *ptmp = NULL;fp = fopen(filename, "r");if (NULL == fp){perror("fail to fopen");return -1;}printf("开始发送!\n");while(1){memset(tmpbuff, 0, sizeof(tmpbuff));ret = fread(tmpbuff, 1, sizeof(tmpbuff), fp);if (ret <= 0){break;}ret = sendto(sockfd, tmpbuff, ret, 0, sendaddr, len);if (-1 == ret){perror("fail to sendto");return -1;}}memset(tmpbuff, 0, sizeof(tmpbuff));sprintf(tmpbuff, "__quit__");ret = sendto(sockfd, tmpbuff, strlen(tmpbuff), 0, sendaddr, len);if (-1 == ret){perror("fail to sendto");return -1;}return 0;
}int main(int argc, const char *argv[])
{int sockfd = 0;char filename[32] = {0};ssize_t nsize = 0;socklen_t len = sizeof(senaddr);int ret = 0;sockfd = bindOfIP("192.168.209.128", 50000);while (1){nsize = recvfrom(sockfd, filename, sizeof(filename), 0, (struct sockaddr *)&senaddr, &len);if (-1 == nsize){perror("fail to recvfrom");return -1;}else{printf("请求的文件名和路径:filename = %s\n", filename);ret = sendFile(filename, sockfd, (struct sockaddr *)&senaddr, len);if (0 == ret){printf("发送成功!\n");}}}return 0;
}
2.下面来看一下client端的实现:
#include "head.h"struct sockaddr_in recvbuf;
int bindOfIP(const char *pIp, int Port)
{int sockfd = 0;int ret = 0;sockfd = socket(AF_INET, SOCK_DGRAM, 0);if (-1 == sockfd){perror("fail to sockfd");return -1;}recvbuf.sin_family = AF_INET;recvbuf.sin_port = htons(Port);recvbuf.sin_addr.s_addr = inet_addr(pIp);ret = bind(sockfd, (struct sockaddr *)&recvbuf, sizeof(recvbuf));if (-1 == ret){perror("fail to bind");return -1;}return sockfd;
}
//接收服务器的文件
int recvFile(int sockfd, char *filename)
{FILE *fp = NULL;char tmpbuff[4096] = {0};ssize_t nsize = 0;printf("进来了\n");fp = fopen(filename, "w");if (NULL == fp){perror("fail to fopen");return -1;}while (1){memset(tmpbuff, 0, sizeof(tmpbuff));nsize = recvfrom(sockfd, tmpbuff, sizeof(tmpbuff), 0, NULL, NULL);if (nsize <= 0){break;}if (!strcmp("__quit__", tmpbuff)){break;}fwrite(tmpbuff, sizeof(char), nsize, fp);fflush(fp);}fclose(fp);return 0;
}int main(int argc, const char *argv[])
{int sockfd = 0;char filename[32] = {0};char *name = NULL;ssize_t nsize = 0;socklen_t len;struct sockaddr_in senaddr;int ret = 0;// sockfd = bindOfIP("192.168.209.129", 50001);如果需要可以绑定自己的IP地址和端口sockfd = socket(AF_INET, SOCK_DGRAM, 0);if (-1 == sockfd){perror("fail to sockfd");return -1;}senaddr.sin_family = AF_INET;senaddr.sin_port = htons(50000);senaddr.sin_addr.s_addr = inet_addr("192.168.209.128");while (1){printf("请输入您需要下载的文件路径:");gets(filename);nsize = sendto(sockfd, filename, strlen(filename), 0, (struct sockaddr *)&senaddr, sizeof(senaddr));if (-1 == nsize){perror("fail to sendto");return -1;}name = filename + strlen(filename) - 1;while (*name != '/'){--name;}++name;//解析出文件名printf("name = %s\n", name);//调试代码ret = recvFile(sockfd, name);if (0 == ret){printf("接收成功!\n");break;}}return 0;
}
这个就是一个简单的UDP下载服务器的实现,其实也是很简单的,但是需要注意的细节还是很多的,能提高对IO操作以及UDP通信的深入了解;不懂就问,欢迎评论区留言哦!
相关文章:
一个UDP下载服务器的实现(模拟下载文件)
本期分享的主要是使用UDP实现文件下载功能,需要自己编写服务器和客户端,实现的功能主要有以下几个: (1)服务器可以为请求的用户下发文件数据(前提是服务器得有这个数据文件) (2&…...
01.hadoop上课笔记之hadoop介绍
1.大数据介绍 可以对未来数据预测 google通过搜索预测流感,足球球员有一 定关联…caict可以得到数据hbase hive林子雨mooc数据要进行挖掘(推断更多信息) 2.大数据是非结构化数据多:声音,图片… 3.大数据影响因素 大多快低 tb pb eb zb 1.硬件 2.网络带宽 4.大数据的特征 数据量…...

小鹏汽车Q1财报:押注G6、大力降本,明年智驾BOM降半
作者 | 德新编辑 | 王博 小鹏汽车本周发了Q1财报,数据不好看,以致于在微博端也发了公开信。 那后续呢? 小鹏第二季度指引是,总交付数量约为2.1 - 2.2万辆,收入预计约为45 - 47亿元;四季度,…...

VMware ESXi 8.0U1a 发布 - 领先的裸机 Hypervisor
VMware ESXi 8.0U1a 发布 - 领先的裸机 Hypervisor 请访问原文链接:https://sysin.org/blog/vmware-esxi-8-u1/,查看最新版。原创作品,转载请保留出处。 作者主页:sysin.org 2023-06-01, VMware vSphere 8.0U1a 发布。 详见&am…...
Unity的IPreprocessBuild:深入解析与实用案例
Unity IPreprocessBuild Unity IPreprocessBuild是Unity引擎中的一个非常有用的功能,它可以让开发者在构建项目时自动执行一些操作。这个功能可以帮助开发者提高工作效率,减少手动操作的时间和错误率。在本文中我们将介绍Unity IPreprocessBuild的使用方…...

htmlCSS-----CSS选择器(下)
目录 前言: 2.高级选择器 (1)子代选择器 (2)伪类选择器 (3)后代选择器 (4)兄弟选择器 相邻兄弟选择器 通用兄弟选择器 (5)并集选择器 &am…...

RDK X3 Module发布,全新软硬件平台加速实现量产级产品落地
机器人开发是一段美妙的旅程。GEEKROS创始人杨状状是地平线社区的一名开发者,热衷于鼓捣各类机器人,2022年,状状第一时间就拿到了地平线旭日X3派(简称旭日X3派),基于TogetheROS™.Bot机器人操作系统&#x…...
【面试实战】Redis缓存设计
文章目录 Redis缓存出现的问题🙎♂️面试官:什么是缓存雪崩?🙎♂️面试官:怎样解决缓存雪崩?🙎♂️面试官:什么是缓存击穿?🙎♂️面试官:怎样解决缓存击穿?🙎♂️面试官:什么是缓存穿透?🙎♂️面试官:怎样解决缓存穿透?🙎♂️面试官:…...
如何解决js定时器不准确问题
为什么会出现定时器不准确呢? 这个其实就得提到js执行机制了,叫做事件循环Eventloop 循环机制中,异步事件 setInterval 到时后会把回调函数放入消息队列中Event Queue,主线程的宏任务执行完毕后依次执行消息队列的微任务ÿ…...

学习笔记——vue中使用el-dropdown组件报错
今天在工作中,发现使用el-select做的下拉框,下拉菜单展开后,鼠标点击下拉框之外的区域时,下拉菜单没有收起。然后,我打开控制台,发现了这个错误。 Uncaught TypeError: Cannot read properties of null (re…...
Java之旅(八)
Java 条件运算符 Java 条件运算符用于根据一个条件表达式的布尔值来决定程序执行的流程。条件运算符有三种类型:if、else 和 switch。 if 语句的一般格式如下: if (condition) {// 条件为 true 执行的代码块 } 其中,condition 是一个 bool…...
华为OD机试真题(Java),四则运算(100%通过+复盘思路)
一、题目描述 输入一个表达式(用字符串表示),求这个表达式的值。 保证字符串中的有效字符包括[‘0’-‘9’],‘+’,‘-’, ‘*’,‘/’ ,‘(’, ‘)’,‘[’, ‘]’,‘{’ ,‘}’。且表达式一定合法。 数据范围:表达式计算结果和过程中满足∣val∣≤1000 ,字符串长度满…...

HTML表单标签form分析
说明:在html的标签中,表单标签与后台联系密切,像用户登录、注册,都是用到页面的表单标签,用户将信息填入到表单中,提交到后端业务中校验处理,再将结果反馈给前端页面。 表单内的标签分别有&…...
Qt 项目文件Pri详解
在Qt项目中,pri文件(.pri)是一种类似于makefile的文件,用于定义Qt项目中的编译规则。通常可以用pri文件来配置Qt库、头文件、源文件、链接库等信息,这样可以把这些信息定义在一个文件中,避免在每个工程中都进行重复配置࿰…...

Keil 5 MDK 发律师函警告了,如何用STCubeIDE开发标准库的程序(STM32F103C8T6为例)
用STCubeIDE进行标准库开发 1、CubeIDE介绍 https://www.stmcu.com.cn/ecosystem/Cube/STM32CubeIDE 2、CubeIDE下载 点击上面的链接,登录即可下载 3、搭建Demo工程 新建一个工作空间 创建一个工程 选择芯片-STM32F103C8T6 填写工程信息 添加标准库到工程 标…...

接口测试--apipost接口断言详解
在做接口测试的时候,会对接口进行断言,一个完整的接口测试,包括:请求->获取响应正文->断言。 一、apipost如何进行断言 apipost的断言设置实在后执行脚本中进行编写的。apipost本身提供了11中断言: apt.asser…...

YYDS练手 130道python练习题 完整版PDF
近年来,Python在编程语言界里赚足了风头,无论是受欢迎程度,还是薪资待遇,都非常可观,相应的,Python岗位要求也越来越高,无论你是零基础还是老前辈,在Python面试中都不能轻视。 不打…...

2-python的变量类型
内容提要 主要回顾了python中的变量类型,区分它们和c中的区别 python中的数字没有long python中的字符串不能被改变,也就是说不能对其内字符元素进行赋值操作 python中列表的数据类型与c访问方式有一定的区别列表的下标可以是负数,无论正负&…...

Python之并发编程一背景知识
一、开篇介绍 顾名思义,进程即正在执行的一个过程。进程是对正在运行程序的一个抽象。 进程的概念起源于操作系统,是操作系统最核心的概念,也是操作系统提供的最古老也是最重要的抽象概念之一。操作系统的其他所有内容都是围绕进程的概念展…...
Redis分区
分区 Redis是单线程的,如何提高多核CPU的利用率? 可以在同一个服务器部署多个Redis的实例,并把他们当作不同的服务器来使用,在某些时候,无论如何一个服务器是不够的, 所以,如果你想使用多个CPU&…...
mongodb源码分析session执行handleRequest命令find过程
mongo/transport/service_state_machine.cpp已经分析startSession创建ASIOSession过程,并且验证connection是否超过限制ASIOSession和connection是循环接受客户端命令,把数据流转换成Message,状态转变流程是:State::Created 》 St…...

SpringBoot+uniapp 的 Champion 俱乐部微信小程序设计与实现,论文初版实现
摘要 本论文旨在设计并实现基于 SpringBoot 和 uniapp 的 Champion 俱乐部微信小程序,以满足俱乐部线上活动推广、会员管理、社交互动等需求。通过 SpringBoot 搭建后端服务,提供稳定高效的数据处理与业务逻辑支持;利用 uniapp 实现跨平台前…...

Mac软件卸载指南,简单易懂!
刚和Adobe分手,它却总在Library里给你写"回忆录"?卸载的Final Cut Pro像电子幽灵般阴魂不散?总是会有残留文件,别慌!这份Mac软件卸载指南,将用最硬核的方式教你"数字分手术"࿰…...
【JavaSE】绘图与事件入门学习笔记
-Java绘图坐标体系 坐标体系-介绍 坐标原点位于左上角,以像素为单位。 在Java坐标系中,第一个是x坐标,表示当前位置为水平方向,距离坐标原点x个像素;第二个是y坐标,表示当前位置为垂直方向,距离坐标原点y个像素。 坐标体系-像素 …...
【C++从零实现Json-Rpc框架】第六弹 —— 服务端模块划分
一、项目背景回顾 前五弹完成了Json-Rpc协议解析、请求处理、客户端调用等基础模块搭建。 本弹重点聚焦于服务端的模块划分与架构设计,提升代码结构的可维护性与扩展性。 二、服务端模块设计目标 高内聚低耦合:各模块职责清晰,便于独立开发…...
Java数值运算常见陷阱与规避方法
整数除法中的舍入问题 问题现象 当开发者预期进行浮点除法却误用整数除法时,会出现小数部分被截断的情况。典型错误模式如下: void process(int value) {double half = value / 2; // 整数除法导致截断// 使用half变量 }此时...
MinIO Docker 部署:仅开放一个端口
MinIO Docker 部署:仅开放一个端口 在实际的服务器部署中,出于安全和管理的考虑,我们可能只能开放一个端口。MinIO 是一个高性能的对象存储服务,支持 Docker 部署,但默认情况下它需要两个端口:一个是 API 端口(用于存储和访问数据),另一个是控制台端口(用于管理界面…...
在 Spring Boot 项目里,MYSQL中json类型字段使用
前言: 因为程序特殊需求导致,需要mysql数据库存储json类型数据,因此记录一下使用流程 1.java实体中新增字段 private List<User> users 2.增加mybatis-plus注解 TableField(typeHandler FastjsonTypeHandler.class) private Lis…...
【Elasticsearch】Elasticsearch 在大数据生态圈的地位 实践经验
Elasticsearch 在大数据生态圈的地位 & 实践经验 1.Elasticsearch 的优势1.1 Elasticsearch 解决的核心问题1.1.1 传统方案的短板1.1.2 Elasticsearch 的解决方案 1.2 与大数据组件的对比优势1.3 关键优势技术支撑1.4 Elasticsearch 的竞品1.4.1 全文搜索领域1.4.2 日志分析…...
Python 高效图像帧提取与视频编码:实战指南
Python 高效图像帧提取与视频编码:实战指南 在音视频处理领域,图像帧提取与视频编码是基础但极具挑战性的任务。Python 结合强大的第三方库(如 OpenCV、FFmpeg、PyAV),可以高效处理视频流,实现快速帧提取、压缩编码等关键功能。本文将深入介绍如何优化这些流程,提高处理…...