项目复习:基于TCP的文件服务器

news2024/11/15 21:37:51

 ser.c(服务器):

#include "./fun.h"

int main(int argc,const char * argv[])
{
    //1.判断入参
    if(argc!=3){
        fprintf(stderr,"入参为空,请检查\n");
        return -1;
    }
    //端口号转整型
    int port=atoi(argv[2]);
    //变量声明
    struct sockaddr_in sin;
    int sinLen=sizeof(sin);
    struct sockaddr_in cin;
    int cinLen=sizeof(cin);
    Info_t info;
    int newfd;
    pthread_t tid;
    //2.创建套接字
    int sfd=socket(AF_INET,SOCK_STREAM,0);
    if(sfd==-1){
        PRINT_ERR("socket error");
    }
    //3.快速重用端口号
    int optval=1;
    if(setsockopt(sfd,SOL_SOCKET,SO_REUSEADDR,&optval,sizeof(optval))==-1){
        PRINT_ERR("setsockopt error");
    }
    //3.填充服务器结构体信息
    sin.sin_family=AF_INET;
    sin.sin_addr.s_addr=inet_addr(argv[1]);
    sin.sin_port=htons(port);
    //4.绑定
    if(bind(sfd,(struct sockaddr *)&sin,sinLen)==-1){
        PRINT_ERR("bind error");
    }
    //5.监听
    if(listen(sfd,10)==-1){
        PRINT_ERR("listen error");
    }
    //6.多线程并发
    while(1){
        newfd=accept(sfd,(struct sockaddr *)&cin,&sinLen);
        if(newfd==-1){
            PRINT_ERR("accept error");
        }
        info.newfd=newfd;
        //创建线程,将信息结构体传入线程
        if(pthread_create(&tid,NULL,callBack,&info)==-1){
            PRINT_ERR("pthread_create error");
        }
    }
    //7.关闭套接字
    close(sfd);
    return 0;
}

cli.c(客户端):

#include "./fun.h"

int main(int argc, const char *argv[])
{
    // 1.判断入参
    if (argc != 3) {
        fprintf(stderr, "入参为空,请检查\n");
        return -1;
    }
    //变量声明
    struct sockaddr_in sin;
    int sinLen = sizeof(sin);
    buf_t buf;
    char path[128] = "";
    // 2.端口号转整型
    int port = atoi(argv[2]);
    // 3.创建套接字
    int sfd = socket(AF_INET, SOCK_STREAM, 0);
    if (sfd == -1) {
        PRINT_ERR("socket error");
    }
    // 4.填充结构体信息
    sin.sin_family = AF_INET;
    sin.sin_addr.s_addr = inet_addr(argv[1]);
    sin.sin_port = htons(port);
    // 5.连接服务器
    if (connect(sfd, (struct sockaddr *)&sin, sinLen) == -1) {
        PRINT_ERR("connect error");
    }
    while (1) {
        // 6.打印选项菜单
        puts("*****************************");
        puts("*********1.查看文件***********");
        puts("*********2.下载文件***********");
        puts("*********3.上传文件***********");
        puts("*****************************");
        printf("请输入选项:>>>");
        memset(&buf, 0, sizeof(buf));
        memset(path, 0, sizeof(path));

        scanf("%d", &buf.type);
        getchar();
        switch (buf.type) {
        case 1:
            break;
        case 2:
            if (getcwd(path, sizeof(path)) == NULL) {
                PRINT_ERR("getcwd error");
            }
            strcpy(buf.data1, path);
            strcat(buf.data1, "/download/");
            printf("请输入要下载的文件名:>>>");
            if (fgets(buf.data2, sizeof(buf.data2), stdin) == NULL) {
                PRINT_ERR("fgets error");
            }
            buf.data2[strlen(buf.data2) - 1] = '\0';
            strcat(buf.data1, buf.data2);
            break;
        case 3:
            if (getcwd(path, sizeof(path)) == NULL) {
                PRINT_ERR("getcwd error");
            }
            strcpy(buf.data1, path);
            strcat(buf.data1, "/download/");
            printf("请输入要上传的文件名:>>>");
            if (fgets(buf.data2, sizeof(buf.data2), stdin) == NULL) {
                PRINT_ERR("fgets error");
            }
            buf.data2[strlen(buf.data2) - 1] = '\0';
            strcat(buf.data1, buf.data2);
            break;
        default:
            printf("error");
        }

        // 7.发送消息
        if (send(sfd, &buf, sizeof(buf), 0) == -1) {
            PRINT_ERR("send error");
        }
        // printf("1\n");
        // 8.接收消息
        while (1) {
            memset(&buf, 0, sizeof(buf));
            if (recv(sfd, &buf, sizeof(buf), 0) == -1) {
                PRINT_ERR("recv error");
            }
            // buf.data2是quit说明服务器读取文件名已经读完,退出循环
            if (strcmp(buf.data2, "quit") == 0)
                break;
            puts(buf.data1);
            if (buf.type == 2 || buf.type == 3)
                break;
        }
        //按任意键继续
        printf("<<请按回车键继续>>");
        getchar();
    }
    // 8.关闭套接字
    close(sfd);
    return 0;
}

fun.h(头文件):

#ifndef __FUN_H__
#define __FUN_H__
#include <head.h>
/********共用***********/
//结构体声明
//线程信息结构体
typedef struct{
    int newfd;
}Info_t;
//消息收发结构体
typedef struct{
    int type;
    char data1[256];
    char data2[256];
}buf_t;
/********服务器端***********/
//函数声明
void *callBack(void *arg);
//显示文件
void showFile(int newfd);
//下载文件
void downloadFile(int newfd,buf_t buf);\
//上传文件
void uploadFile(int newfd,buf_t buf);

/********客户端***********/


#endif

fun.c(功能文件):

#include "fun.h"

void *callBack(void *arg)
{
    //转分离态
    pthread_detach(pthread_self());
    Info_t info = *(Info_t *)arg;
    int newfd = info.newfd;

    //变量声明
    buf_t buf;
    //循环收发数据
    while (1) {
        if (recv(newfd, &buf, sizeof(buf), 0) == -1) {
            VPRINT_ERR("recv error");
        }
        switch (buf.type) {
        case 1:
            showFile(newfd);
            break;
        case 2:
            downloadFile(newfd, buf);
            break;
        case 3:
            uploadFile(newfd, buf);
            break;
        default:
            printf("error");
        }
    }

    //关闭文件描述符
    close(newfd);
    //退出线程
    pthread_exit(0);
}
//显示文件
void showFile(int newfd)
{
    //变量声明
    DIR *dir = NULL;
    buf_t buf;
    struct dirent *dp = NULL;
    //打开目录
    dir = opendir("./");
    if (NULL == dir) {
        VPRINT_ERR("opendir error");
    }
    while (1) {
        //循环读取目录,直到读完
        dp = readdir(dir);
        if (dp == NULL) {
            if (errno == 0) {
                strcpy(buf.data2, "quit");
                if (send(newfd, &buf, sizeof(buf), 0) == -1) {
                    VPRINT_ERR("send error");
                }
                break;
            } else {
                VPRINT_ERR("readdir error");
            }
        }
        memset(&buf, 0, sizeof(buf));
        buf.type = 1;
        strcpy(buf.data1, dp->d_name);
        //循环发送
        if (send(newfd, &buf, sizeof(buf), 0) == -1) {
            VPRINT_ERR("send error");
        }
    }
    //关闭目录,dir指向NULL
    closedir(dir);
    dir = NULL;
}
//下载文件
void downloadFile(int newfd, buf_t buf)
{
    //变量声明
    char server_path[256] = "./";
    char client_path[256] = "";
    char str[128] = "";
    int ret;

    strcpy(client_path, buf.data1);
    strcat(server_path, buf.data2);
    // 1.打开2个文件
    int fdr = open(server_path, O_RDONLY);
    int fdw = open(client_path, O_WRONLY | O_CREAT | O_TRUNC, 0664);
    if (fdr == -1 || fdw == -1) {
        VPRINT_ERR("open error");
    }
    while (1) {
        // 2.循环读取
        ret = read(fdr, str, sizeof(str));
        if (ret == -1) {
            VPRINT_ERR("read error");
        } else if (ret == 0) {
            break;
        }
        // 3.循环写入
        write(fdw, str, ret);
    }
    // 4.发送消息
    memset(&buf, 0, sizeof(buf));
    buf.type = 2;
    strcpy(buf.data1, "下载成功");
    if (send(newfd, &buf, sizeof(buf), 0) == -1) {
        VPRINT_ERR("send error");
    }
    // 5.关闭2个文件
    close(fdr);
    close(fdw);
}
//上传文件
void uploadFile(int newfd, buf_t buf)
{
    //变量声明
    char server_path[256] = "./";
    char client_path[256] = "";
    char str[128] = "";
    int ret;

    strcpy(client_path, buf.data1);
    strcat(server_path, buf.data2);
    // 1.打开2个文件
    int fdr = open(client_path, O_RDONLY);
    int fdw = open(server_path, O_WRONLY | O_CREAT | O_TRUNC, 0664);
    if (fdr == -1 || fdw == -1) {
        VPRINT_ERR("open error");
    }
    while (1) {
        // 2.循环读取
        ret = read(fdr, str, sizeof(str));
        if (ret == -1) {
            VPRINT_ERR("read error");
        } else if (ret == 0) {
            break;
        }
        // 3.循环写入
        write(fdw, str, ret);
    }
    // 4.发送消息
    memset(&buf, 0, sizeof(buf));
    buf.type = 3;
    strcpy(buf.data1, "上传成功");
    if (send(newfd, &buf, sizeof(buf), 0) == -1) {
        VPRINT_ERR("send error");
    }
    // 5.关闭2个文件
    close(fdr);
    close(fdw);
}

工程管理文件(makefile):

-include config.mk
#版本1
# a.out:$(NAME).o $(FUN).o
# 	$(CC) $^ -o $@
# %.o:%.c
# 	$(CC) -c $^ -o $@

# .PHONY:clean
# clean:
# 	rm -rf $(NAME).o $(FUN).o a.out

#版本2(生成动态库版本)
# a.out:$(NAME).o lib$(FUN).so
# 	$(CC) $< -L./lib -l$(FUN) -o $@
# lib$(FUN).so:$(FUN).o
# 	$(CC) -shared $^ -o $@
# 	mv $@ ./lib
# $(NAME).o:$(NAME).c
# 	$(CC) -c $^ -o $@
# $(FUN).o:$(FUN).c
# 	$(CC) -Wall -fPIC -c $^ -o $@
# .PHONY:clean
# clean:
# 	rm -rf *.o lib/*.so a.out

#版本3(生成动态库版本+链接线程库版)
# a.out:$(NAME).o lib$(FUN).so
# 	$(CC) $< -L./lib -l$(FUN) -o $@ -lpthread
# lib$(FUN).so:$(FUN).o
# 	$(CC) -shared $^ -o $@
# 	mv $@ ./lib
# $(NAME).o:$(NAME).c
# 	$(CC) -c $^ -o $@
# $(FUN).o:$(FUN).c
# 	$(CC) -Wall -fPIC -c $^ -o $@
# .PHONY:clean
# clean:
# 	rm -rf *.o lib/*.so a.out

#版本4(生成动态库版本+非父子进程通信版本)
# .PHONY:all
# all:F A B
# A:$(NAMEA).o lib$(FUN).so
# 	$(CC) $< -L./lib -l$(FUN) -o $@
# B:$(NAMEB).o lib$(FUN).so
# 	$(CC) $< -L./lib -l$(FUN) -o $@
# F:$(NAMEF).o lib$(FUN).so
# 	$(CC) $< -L./lib -l$(FUN) -o $@
# lib$(FUN).so:$(FUN).o
# 	$(CC) -shared $^ -o $@
# 	mv $@ ./lib
# $(NAMEF).o:$(NAMEF).c
# 	$(CC) -c $^ -o $@
# $(NAMEA).o:$(NAMEA).c
# 	$(CC) -c $^ -o $@
# $(NAMEB).o:$(NAMEB).c
# 	$(CC) -c $^ -o $@
# $(FUN).o:$(FUN).c
# 	$(CC) -Wall -fPIC -c $^ -o $@
# .PHONY:clean
# clean:
# 	rm -rf *.o lib/*.so A B F

#版本5(生成动态库版本+非父子进程通信版本+链接线程库版本)
# .PHONY:all
# all:F A B
# A:$(NAMEA).o lib$(FUN).so
# 	$(CC) $< -L./lib -l$(FUN) -o $@ -lpthread
# B:$(NAMEB).o lib$(FUN).so
# 	$(CC) $< -L./lib -l$(FUN) -o $@ -lpthread
# F:$(NAMEF).o lib$(FUN).so
# 	$(CC) $< -L./lib -l$(FUN) -o $@
# lib$(FUN).so:$(FUN).o
# 	$(CC) -shared $^ -o $@
# 	mv $@ ./lib
# $(NAMEF).o:$(NAMEF).c
# 	$(CC) -c $^ -o $@
# $(NAMEA).o:$(NAMEA).c
# 	$(CC) -c $^ -o $@
# $(NAMEB).o:$(NAMEB).c
# 	$(CC) -c $^ -o $@
# $(FUN).o:$(FUN).c
# 	$(CC) -Wall -fPIC -c $^ -o $@
# .PHONY:clean
# clean:
# 	rm -rf *.o lib/*.so A B F

#版本6(生成动态库版本+客户端服务器通信版本)
# .PHONY:all
# all:cli ser
# ser:$(NAMESER).o lib$(FUN).so
# 	$(CC) $< -L./lib -l$(FUN) -o $@
# cli:$(NAMECLI).o lib$(FUN).so
# 	$(CC) $< -L./lib -l$(FUN) -o $@
# lib$(FUN).so:$(FUN).o
# 	$(CC) -shared $^ -o $@
# 	mv $@ ./lib
# $(NAMESER).o:$(NAMESER).c
# 	$(CC) -c $^ -o $@
# $(NAMECLI).o:$(NAMECLI).c
# 	$(CC) -c $^ -o $@
# $(FUN).o:$(FUN).c
# 	$(CC) -Wall -fPIC -c $^ -o $@
# .PHONY:clean
# clean:
# 	rm -rf *.o lib/*.so ser cli

#版本6(生成动态库版本+客户端服务器通信版本+线程库版本)
.PHONY:all
all:cli ser
ser:$(NAMESER).o lib$(FUN).so
	$(CC) $< -L./lib -l$(FUN) -o $@ -lpthread
cli:$(NAMECLI).o lib$(FUN).so
	$(CC) $< -L./lib -l$(FUN) -o $@ -lpthread
lib$(FUN).so:$(FUN).o
	$(CC) -shared $^ -o $@
	mv $@ ./lib
$(NAMESER).o:$(NAMESER).c
	$(CC) -c $^ -o $@
$(NAMECLI).o:$(NAMECLI).c
	$(CC) -c $^ -o $@
$(FUN).o:$(FUN).c
	$(CC) -Wall -fPIC -c $^ -o $@
.PHONY:clean
clean:
	rm -rf *.o lib/*.so ser cli

工程管理配置文件(config.mk):

#对应版本1,2,3的makefile
# CC=gcc
# NAME=test
# FUN=fun

#对应版本4,5的makefile
# CC=gcc
# NAMEA=Atest
# NAMEB=Btest
# NAMEF=Ftest
# FUN=fun

#对应版本6的makefile
CC=gcc
NAMESER=ser
NAMECLI=cli
FUN=fun

测试结果:

编译makefile:

 打开服务器和客户端:

 上传和下载文件的位置:

 选择1查看文件:

 选择2下载文件:

 另起一个终端客户端,选择3上传文件:

 关闭服务器和客户端,diff测试下载以及上传的文件是否和原来的一致:

 

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

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

相关文章

axios.defaults.baseURL的三种配置方法

axios.defaults.baseURL的三种配置方法目录概述需求&#xff1a;设计思路实现思路分析1.少2.2.动态获取请求地址3.3.采用配置文件参考资料和推荐阅读Survive by day and develop by night. talk for import biz , show your perfect code,full busy&#xff0c;skip hardness,m…

SEAL 0.3 正式发布:国内首个全链路软件供应链安全管理平台

12月1日&#xff0c;软件供应链安全管理平台 SEAL 0.3 正式发布&#xff08;以下简称“SEAL”&#xff09;&#xff0c;这是国内首个以全链路视角保护软件供应链的安全管理平台。两个月前 SEAL 0.2 发布&#xff0c;该版本创新性地提供了依赖项的全局汇总与关联&#xff0c;用户…

DSP篇--C6678功能调试系列之SPI调试

目录 1、初始化 2、数据传输 1、初始化 Perform the following procedure for initializing the SPI: 1. Reset the SPI by clearing the RESET bit in the SPI global control register 0 (SPIGCR0) to 0. 2. Take the SPI out of reset by setting SPIGCR0.RESET to 1. 3. …

【使用 BERT 的问答系统】第 6 章 :BERT 模型应用:其他任务

&#x1f50e;大家好&#xff0c;我是Sonhhxg_柒&#xff0c;希望你看完之后&#xff0c;能对你有所帮助&#xff0c;不足请指正&#xff01;共同学习交流&#x1f50e; &#x1f4dd;个人主页&#xff0d;Sonhhxg_柒的博客_CSDN博客 &#x1f4c3; &#x1f381;欢迎各位→点赞…

【大数据入门核心技术-Zookeeper】(三)Zookeeper的选举机制和流程

目录 一、Zookeeper的选举机制 1、每一个 Server 都会发出一个投票 2、接收来自各个 Server 的投票 3、处理投票 4、统计投票 5、改变服务器状态 二、Zookeeper的选举流程 一、Zookeeper的选举机制 Zookeeper 在配置文件中并没有指定 Master 和 Slave。但是&#xff0c;…

软件测试培训之十个无脚本测试方案

1.自然语言处理(NLP) 目前&#xff0c;一些最新的无脚本自动化测试工具能够通过采用NLP语法&#xff0c;来创建各种测试用例。就像编写简单的英语语句一样&#xff0c;用户可以轻松地实现测试用例的自动化。此类工具一般会带有AI驱动的内核&#xff0c;因此大幅节省了用户对其维…

【遥感图像融合:梯度指导:纹理细节】

GTP-PNet: A residual learning network based on gradient transformation prior for pansharpening &#xff08;一种基于梯度变换的剩余学习网络&#xff09; 提出了一种基于梯度变换先验的残差学习网络GTP-PNet&#xff0c;用于生成光谱分布准确、空间结构合理的高质量HRM…

车间生产设备管理有哪些问题?低代码来助力

随着科学技术对生产技术与生产工艺流程的不断改革创新&#xff0c;同时受市场变化的影响&#xff0c;企业生产管理模式也发生了巨大的改变&#xff0c;对车间生产设备管理的要求更高&#xff0c;并在一定层面推动了车间生产设备管理模式的创新和转变发展。但由于不同的企业面对…

JavaScript---DOM---DOM简介、获取元素、事件基础、操作元素---11.5

DOM简介 什么是DOM 文档对象模型&#xff08;Document Object Model&#xff0c;简称DOM&#xff09;是W3C组织推荐的处理可扩展标记语言&#xff08;HTML或者XML&#xff09;的标准编程接口。 W3C已经定义了一系列的DOM接口&#xff0c;通过这些DOM接口可以改变网页的内容、…

[附源码]计算机毕业设计springboot学生宿舍管理系统

项目运行 环境配置&#xff1a; Jdk1.8 Tomcat7.0 Mysql HBuilderX&#xff08;Webstorm也行&#xff09; Eclispe&#xff08;IntelliJ IDEA,Eclispe,MyEclispe,Sts都支持&#xff09;。 项目技术&#xff1a; SSM mybatis Maven Vue 等等组成&#xff0c;B/S模式 M…

如何在 Windows 10/8.1/8/7 上无密码删除 Deep Freeze

如何在 Windows 10/8.1/8/7 上无密码删除 Deep Freeze 有些人认真对待计算机安全问题。这些人会安装 Deep Freeze 冰点来保护他们的计算机。该应用程序的便利之处在于它会在重新启动时将计算机恢复到原始的预设配置。因此&#xff0c;可以轻松消除重启之间发生的任何变化&#…

海量数据如何在Web端实现动态可视化?看看这家企业是怎么做的

“我们TestLogger公司是一家赛车行业的软件公司&#xff0c;主要是通过分析在赛道上多个传感器收集到的赛车数据&#xff0c;帮助提高赛车性能。TestLogger Analyzer就是其中的一款核心数据分析工具&#xff0c;在我们构建该工具的第一个产品原型时&#xff0c;就发现由于不同类…

(附源码课件)10款Java小游戏满足你各种需求

游戏推荐 黄金矿工项目 飞机大战项目 超级玛丽项目 坦克大战项目 大鱼吃小鱼项目 飞翔的小鸟项目 扫雷项目 贪吃蛇项目 推箱子项目 本套视频课程包含&#xff1a; 1、王者荣耀项目 开发环境&#xff1a;jdk1.8 开发工具:eclipse JavaEE基础如下&#xff1a;变量、数据类型…

[附源码]计算机毕业设计springboot校友社交系统

项目运行 环境配置&#xff1a; Jdk1.8 Tomcat7.0 Mysql HBuilderX&#xff08;Webstorm也行&#xff09; Eclispe&#xff08;IntelliJ IDEA,Eclispe,MyEclispe,Sts都支持&#xff09;。 项目技术&#xff1a; SSM mybatis Maven Vue 等等组成&#xff0c;B/S模式 M…

uni-app入门:自定义tabbar

本文介绍如何使用vant Weapp定义自定义tabbar.按照自定义图标的方式进行添加: 自定义tabbar微信官方链接: https://developers.weixin.qq.com/miniprogram/dev/framework/ability/custom-tabbar.html 1.导入vant weapp并构建npm 项目根目录右键选择外部终端窗口中打开 …

Numpy入门[2]——Matplotlib 基础

Numpy入门[2]——Matplotlib 基础 参考&#xff1a; https://ailearning.apachecn.org/ Python直接使用plot()函数画图 使用Jupyter进行练习 在使用Numpy之前&#xff0c;需要了解一些画图的基础。 Matplotlib是一个类似Matlab的工具包&#xff0c;主页地址为 http://matplot…

梁建章:旅行重回全球时代主题 构建“创新与传承”大场景

近日&#xff0c;在“防疫二十条”等最新措施基础上&#xff0c;国内多地宣布优化调整防疫措施&#xff0c;旅游市场复苏节奏也有望加速推进。 12月2日&#xff0c;携程集团在澳门举办“与时聚进”2022全球合作伙伴峰会。携程集团联合创始人、董事局主席梁建章&#xff0c;携程…

JS中常用的Date内置对象&处理Date内置对象的一些方法

JavaScript 中的对象分为3种&#xff1a;自定义对象 、内置对象、 浏览器对象 内置对象就是指 JS 语言自带的一些对象&#xff0c;这些对象供开发者使用&#xff0c;并提供了一些常用的或是最基本而必要的功能 JavaScript 提供了多个内置对象&#xff1a;Math、 Date 、Array…

2023最新SSM计算机毕业设计选题大全(附源码+LW)之java高校教师科研能力评定系统40n60

要对当前自己的学校对于计算机毕业设计的要求以及严格程度有所了解&#xff0c;这个主要是借助上一届已经毕业的学长学姐了解一下&#xff0c;但是有一点要注意的是&#xff0c;对于每一届毕业生的毕业设计的处理&#xff0c;学校都有很大的调整&#xff0c;这一点尤其重要。其…

springboot基于微信小程序的社区居家养老互助服务管理平台设计与实现毕业设计源码062027

基于springboot微信小程序的社区居家养老互助系统 摘 要 随着我国经济迅速发展&#xff0c;人们对手机的需求越来越大&#xff0c;各种手机软件也都在被广泛应用&#xff0c;但是对于手机进行数据信息管理&#xff0c;对于手机的各种软件也是备受用户的喜爱&#xff0c;微信小…