当前位置: 首页 > news >正文

一个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实现文件下载功能&#xff0c;需要自己编写服务器和客户端&#xff0c;实现的功能主要有以下几个&#xff1a; &#xff08;1&#xff09;服务器可以为请求的用户下发文件数据&#xff08;前提是服务器得有这个数据文件&#xff09; &#xff08;2&…...

01.hadoop上课笔记之hadoop介绍

1.大数据介绍 可以对未来数据预测 google通过搜索预测流感,足球球员有一 定关联…caict可以得到数据hbase hive林子雨mooc数据要进行挖掘(推断更多信息) 2.大数据是非结构化数据多:声音,图片… 3.大数据影响因素 大多快低 tb pb eb zb 1.硬件 2.网络带宽 4.大数据的特征 数据量…...

小鹏汽车Q1财报:押注G6、大力降本,明年智驾BOM降半

‍作者 | 德新编辑 | 王博 小鹏汽车本周发了Q1财报&#xff0c;数据不好看&#xff0c;以致于在微博端也发了公开信。 那后续呢&#xff1f; 小鹏第二季度指引是&#xff0c;总交付数量约为2.1 - 2.2万辆&#xff0c;收入预计约为45 - 47亿元&#xff1b;四季度&#xff0c…...

VMware ESXi 8.0U1a 发布 - 领先的裸机 Hypervisor

VMware ESXi 8.0U1a 发布 - 领先的裸机 Hypervisor 请访问原文链接&#xff1a;https://sysin.org/blog/vmware-esxi-8-u1/&#xff0c;查看最新版。原创作品&#xff0c;转载请保留出处。 作者主页&#xff1a;sysin.org 2023-06-01, VMware vSphere 8.0U1a 发布。 详见&am…...

Unity的IPreprocessBuild:深入解析与实用案例

Unity IPreprocessBuild Unity IPreprocessBuild是Unity引擎中的一个非常有用的功能&#xff0c;它可以让开发者在构建项目时自动执行一些操作。这个功能可以帮助开发者提高工作效率&#xff0c;减少手动操作的时间和错误率。在本文中我们将介绍Unity IPreprocessBuild的使用方…...

htmlCSS-----CSS选择器(下)

目录 前言&#xff1a; 2.高级选择器 &#xff08;1&#xff09;子代选择器 &#xff08;2&#xff09;伪类选择器 &#xff08;3&#xff09;后代选择器 &#xff08;4&#xff09;兄弟选择器 相邻兄弟选择器 通用兄弟选择器 &#xff08;5&#xff09;并集选择器 &am…...

RDK X3 Module发布,全新软硬件平台加速实现量产级产品落地

机器人开发是一段美妙的旅程。GEEKROS创始人杨状状是地平线社区的一名开发者&#xff0c;热衷于鼓捣各类机器人&#xff0c;2022年&#xff0c;状状第一时间就拿到了地平线旭日X3派&#xff08;简称旭日X3派&#xff09;&#xff0c;基于TogetheROS™.Bot机器人操作系统&#x…...

【面试实战】Redis缓存设计

文章目录 Redis缓存出现的问题🙎‍♂️面试官:什么是缓存雪崩?🙎‍♂️面试官:怎样解决缓存雪崩?🙎‍♂️面试官:什么是缓存击穿?🙎‍♂️面试官:怎样解决缓存击穿?🙎‍♂️面试官:什么是缓存穿透?🙎‍♂️面试官:怎样解决缓存穿透?🙎‍♂️面试官:…...

如何解决js定时器不准确问题

为什么会出现定时器不准确呢&#xff1f; 这个其实就得提到js执行机制了&#xff0c;叫做事件循环Eventloop 循环机制中&#xff0c;异步事件 setInterval 到时后会把回调函数放入消息队列中Event Queue&#xff0c;主线程的宏任务执行完毕后依次执行消息队列的微任务&#xff…...

学习笔记——vue中使用el-dropdown组件报错

今天在工作中&#xff0c;发现使用el-select做的下拉框&#xff0c;下拉菜单展开后&#xff0c;鼠标点击下拉框之外的区域时&#xff0c;下拉菜单没有收起。然后&#xff0c;我打开控制台&#xff0c;发现了这个错误。 Uncaught TypeError: Cannot read properties of null (re…...

Java之旅(八)

Java 条件运算符 Java 条件运算符用于根据一个条件表达式的布尔值来决定程序执行的流程。条件运算符有三种类型&#xff1a;if、else 和 switch。 if 语句的一般格式如下&#xff1a; if (condition) {// 条件为 true 执行的代码块 } 其中&#xff0c;condition 是一个 bool…...

华为OD机试真题(Java),四则运算(100%通过+复盘思路)

一、题目描述 输入一个表达式(用字符串表示),求这个表达式的值。 保证字符串中的有效字符包括[‘0’-‘9’],‘+’,‘-’, ‘*’,‘/’ ,‘(’, ‘)’,‘[’, ‘]’,‘{’ ,‘}’。且表达式一定合法。 数据范围:表达式计算结果和过程中满足∣val∣≤1000 ,字符串长度满…...

HTML表单标签form分析

说明&#xff1a;在html的标签中&#xff0c;表单标签与后台联系密切&#xff0c;像用户登录、注册&#xff0c;都是用到页面的表单标签&#xff0c;用户将信息填入到表单中&#xff0c;提交到后端业务中校验处理&#xff0c;再将结果反馈给前端页面。 表单内的标签分别有&…...

Qt 项目文件Pri详解

在Qt项目中&#xff0c;pri文件(.pri)是一种类似于makefile的文件&#xff0c;用于定义Qt项目中的编译规则。通常可以用pri文件来配置Qt库、头文件、源文件、链接库等信息&#xff0c;这样可以把这些信息定义在一个文件中&#xff0c;避免在每个工程中都进行重复配置&#xff0…...

Keil 5 MDK 发律师函警告了,如何用STCubeIDE开发标准库的程序(STM32F103C8T6为例)

用STCubeIDE进行标准库开发 1、CubeIDE介绍 https://www.stmcu.com.cn/ecosystem/Cube/STM32CubeIDE 2、CubeIDE下载 点击上面的链接&#xff0c;登录即可下载 3、搭建Demo工程 新建一个工作空间 创建一个工程 选择芯片-STM32F103C8T6 填写工程信息 添加标准库到工程 标…...

接口测试--apipost接口断言详解

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

YYDS练手 130道python练习题 完整版PDF

近年来&#xff0c;Python在编程语言界里赚足了风头&#xff0c;无论是受欢迎程度&#xff0c;还是薪资待遇&#xff0c;都非常可观&#xff0c;相应的&#xff0c;Python岗位要求也越来越高&#xff0c;无论你是零基础还是老前辈&#xff0c;在Python面试中都不能轻视。 不打…...

2-python的变量类型

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

Python之并发编程一背景知识

一、开篇介绍 顾名思义&#xff0c;进程即正在执行的一个过程。进程是对正在运行程序的一个抽象。 进程的概念起源于操作系统&#xff0c;是操作系统最核心的概念&#xff0c;也是操作系统提供的最古老也是最重要的抽象概念之一。操作系统的其他所有内容都是围绕进程的概念展…...

Redis分区

分区 Redis是单线程的&#xff0c;如何提高多核CPU的利用率&#xff1f; 可以在同一个服务器部署多个Redis的实例&#xff0c;并把他们当作不同的服务器来使用&#xff0c;在某些时候&#xff0c;无论如何一个服务器是不够的&#xff0c; 所以&#xff0c;如果你想使用多个CPU&…...

React 第五十五节 Router 中 useAsyncError的使用详解

前言 useAsyncError 是 React Router v6.4 引入的一个钩子&#xff0c;用于处理异步操作&#xff08;如数据加载&#xff09;中的错误。下面我将详细解释其用途并提供代码示例。 一、useAsyncError 用途 处理异步错误&#xff1a;捕获在 loader 或 action 中发生的异步错误替…...

QMC5883L的驱动

简介 本篇文章的代码已经上传到了github上面&#xff0c;开源代码 作为一个电子罗盘模块&#xff0c;我们可以通过I2C从中获取偏航角yaw&#xff0c;相对于六轴陀螺仪的yaw&#xff0c;qmc5883l几乎不会零飘并且成本较低。 参考资料 QMC5883L磁场传感器驱动 QMC5883L磁力计…...

学习STC51单片机31(芯片为STC89C52RCRC)OLED显示屏1

每日一言 生活的美好&#xff0c;总是藏在那些你咬牙坚持的日子里。 硬件&#xff1a;OLED 以后要用到OLED的时候找到这个文件 OLED的设备地址 SSD1306"SSD" 是品牌缩写&#xff0c;"1306" 是产品编号。 驱动 OLED 屏幕的 IIC 总线数据传输格式 示意图 …...

【RockeMQ】第2节|RocketMQ快速实战以及核⼼概念详解(二)

升级Dledger高可用集群 一、主从架构的不足与Dledger的定位 主从架构缺陷 数据备份依赖Slave节点&#xff0c;但无自动故障转移能力&#xff0c;Master宕机后需人工切换&#xff0c;期间消息可能无法读取。Slave仅存储数据&#xff0c;无法主动升级为Master响应请求&#xff…...

CMake 从 GitHub 下载第三方库并使用

有时我们希望直接使用 GitHub 上的开源库,而不想手动下载、编译和安装。 可以利用 CMake 提供的 FetchContent 模块来实现自动下载、构建和链接第三方库。 FetchContent 命令官方文档✅ 示例代码 我们将以 fmt 这个流行的格式化库为例,演示如何: 使用 FetchContent 从 GitH…...

【HTTP三个基础问题】

面试官您好&#xff01;HTTP是超文本传输协议&#xff0c;是互联网上客户端和服务器之间传输超文本数据&#xff08;比如文字、图片、音频、视频等&#xff09;的核心协议&#xff0c;当前互联网应用最广泛的版本是HTTP1.1&#xff0c;它基于经典的C/S模型&#xff0c;也就是客…...

return this;返回的是谁

一个审批系统的示例来演示责任链模式的实现。假设公司需要处理不同金额的采购申请&#xff0c;不同级别的经理有不同的审批权限&#xff1a; // 抽象处理者&#xff1a;审批者 abstract class Approver {protected Approver successor; // 下一个处理者// 设置下一个处理者pub…...

Webpack性能优化:构建速度与体积优化策略

一、构建速度优化 1、​​升级Webpack和Node.js​​ ​​优化效果​​&#xff1a;Webpack 4比Webpack 3构建时间降低60%-98%。​​原因​​&#xff1a; V8引擎优化&#xff08;for of替代forEach、Map/Set替代Object&#xff09;。默认使用更快的md4哈希算法。AST直接从Loa…...

电脑桌面太单调,用Python写一个桌面小宠物应用。

下面是一个使用Python创建的简单桌面小宠物应用。这个小宠物会在桌面上游荡&#xff0c;可以响应鼠标点击&#xff0c;并且有简单的动画效果。 import tkinter as tk import random import time from PIL import Image, ImageTk import os import sysclass DesktopPet:def __i…...

在Zenodo下载文件 用到googlecolab googledrive

方法&#xff1a;Figshare/Zenodo上的数据/文件下载不下来&#xff1f;尝试利用Google Colab &#xff1a;https://zhuanlan.zhihu.com/p/1898503078782674027 参考&#xff1a; 通过Colab&谷歌云下载Figshare数据&#xff0c;超级实用&#xff01;&#xff01;&#xff0…...