02.10 TCP之文件传输

1.思维导图
2.作业

服务器代码:

#include <stdio.h>
#include <string.h>
#include <unistd.h>
#include <stdlib.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <pthread.h>
#include <semaphore.h>
#include <wait.h>
#include <signal.h>
#include <sys/socket.h>
#include <arpa/inet.h>
#include <sys/socket.h>
#include <sys/ipc.h>
#include <sys/sem.h>
#include <semaphore.h>
#include <sys/msg.h>
#include <sys/shm.h>
#include <sys/un.h>
#include <sys/epoll.h>typedef struct sockaddr_in addr_in_t;
typedef struct sockaddr addr_t;
typedef struct sockaddr_un addr_un_t;enum Type{TYPE_REGIST,TYPE_LOGIN,TYPE_CHAT,TYPE_FILE_UPLOAD_REQUEST
};typedef struct Pack{enum Type type;char name[20];char pswd[20];char filename[20];long filesize;char tarname[20];char text[1024];
}pack_t;// 李四:你好
typedef struct User{char name[20];char pswd[20];int sock;int hasMsg; // 用来表示当前客户端是否拥有未读消息的数据:0表示不拥有,1表示拥有未读消息char msg[1024]; // 用来缓存针对该用户的未读消息
//	当该用户上线的时候,检索一下hasMsg是0还是1,如果是1,就将msg里面的数据发给自己
}user_t;user_t user_arr[50] = {0};
int user_len = 0;void read_data(int client);
void insert_user(user_t user);
int find_user(const char* username);int main(int argc, const char *argv[])
{if(argc != 2){printf("请输入端口号\n");return 1;}// ./server 8888int port = atoi(argv[1]);// 将字符串 8888 转换成int类型port// 创建服务器套接字int server = socket(AF_INET,SOCK_STREAM,0);// 准备网络地址结构体:struct sockaddr_inaddr_in_t addr = {0};addr.sin_family = AF_INET;addr.sin_port = htons(port);addr.sin_addr.s_addr = inet_addr("0.0.0.0");// 为套接字绑定ip 和 portif(bind(server,(addr_t*)&addr,sizeof(addr)) == -1){perror("bind");return 1;}// 监听listen(server,10);// 创建监视列表int epfd = epoll_create1(EPOLL_CLOEXEC);// 将 0 和 server 存入监视列表 epfd 中struct epoll_event epoll_stdin = {.events = EPOLLIN,.data.fd = 0};struct epoll_event epoll_server = {.events = EPOLLIN,.data.fd = server};epoll_ctl(epfd,EPOLL_CTL_ADD,0,&epoll_stdin);epoll_ctl(epfd,EPOLL_CTL_ADD,server,&epoll_server);// 准备一个数组,用来存放所有激活的描述符struct epoll_event arr[50] = {0};while(1){int len = epoll_wait(epfd,arr,50,-1);for(int i=0;i<len;i++){int fd = arr[i].data.fd;// 将到底是哪个描述符激活了单独取出来if(fd == server){printf("有新客户端连接\n");int client = accept(server,0,0);struct epoll_event epoll_client = {.events = EPOLLIN,.data.fd = client};epoll_ctl(epfd,EPOLL_CTL_ADD,client,&epoll_client);}else if(fd == 0){char buf[64] = "";scanf("%63s",buf);while(getchar()!=10);printf("键盘输入数据:%s\n",buf);}else{read_data(fd);}}}return 0;
}void insert_user(user_t user){user_arr[user_len] = user;user_len ++;
}int find_user(const char* username){for(int i=0;i<user_len;i++){if(strcmp(username,user_arr[i].name) == 0){return i;}}return -1;
}void read_data(int client){//while(1){pack_t pack = {0};int res = read(client,&pack,sizeof(pack));//if(res == 0){break;}switch(pack.type){case TYPE_REGIST:{int res = find_user(pack.name);// 根据用户发来的账号,在数组中查询是否存在char* msg = NULL;if(res == -1){ // 如果不存在返回-1user_t user = {0};strcpy(user.name,pack.name);strcpy(user.pswd,pack.pswd);insert_user(user);msg = "注册成功";}else{// 如果存在,返回这个账号在数组中的下标位置msg = "该账号已存在";}strcpy(pack.text,msg);write(client,&pack,sizeof(pack));break;}case TYPE_LOGIN:{int res  = find_user(pack.name);char* msg = NULL;if(res == -1){msg = "该账号不存在";}else{user_t user = user_arr[res];// 将找到的用户单独拎出来if(strcmp(user.pswd,pack.pswd) == 0){msg = "登录成功";user_arr[res].sock = client;// user_arr[res] 是根据当前登录用户发送过来的账号,找到的存放在数组中的用户结构体// client 是当前正在登录的用户在服务器的套接字if(user_arr[res].hasMsg == 1){// 说明当前用户存在未读消息pack_t pack = {0};pack.type = TYPE_CHAT;strcpy(pack.text , user_arr[res].msg); // 将缓存的消息写入 pack.text 里面write(client,&pack,sizeof(pack)); // 将缓存消息发给新登录的客户端user_arr[res].hasMsg = 0;}}else{	msg = "密码错误";}}strcpy(pack.text,msg);write(client,&pack,sizeof(pack));break;}case TYPE_CHAT:{char* msg = NULL;// 聊天的时候,客户端会发来如下格式的信息 "张三:你好",表明 你好这条消息是发给张三的// 所以我们要根据张三的账号,找到张三的套接字,张三的姓名和套接字都存放在 结构体数组 user_arr里面int res = find_user(pack.tarname);if(res == -1){msg = "该用户不存在";strcpy(pack.text,msg);write(client,&pack,sizeof(pack));}else{user_t user = user_arr[res];// user_arr[res] 为准备接受聊天信息的用户if(user.sock == 0){//msg = "用户未登录";//strcpy(pack.text,msg);//write(client,&pack,sizeof(pack));user_arr[res].hasMsg = 1;// 表明当前用户存在了未读消息strcpy(user_arr[res].msg , pack.text); // 将准备发送给该用户的消息,缓存到user_arr[res].msg里面去}else{// 用户存在并登录的状态int tarsock = user.sock;write(tarsock,&pack,sizeof(pack));}}break;}case TYPE_FILE_UPLOAD_REQUEST:{//printf("接收到客户端文件上传请求:%s %s\n",pack.tarname,pack.filename);int res = find_user(pack.tarname);if(res == -1){// 没注册 printf("该用户不存在\n");break;}else{if(user_arr[res].sock == 0){// 不在线}else{// 目标用户在线,直接将接收到的pack包转发给目标用户printf("转发文件中...\n");write(user_arr[res].sock,&pack,sizeof(pack));}}break;}}//}
}

客户端代码:

#include <stdio.h>
#include <string.h>
#include <unistd.h>
#include <stdlib.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <pthread.h>
#include <semaphore.h>
#include <wait.h>
#include <signal.h>
#include <sys/socket.h>
#include <arpa/inet.h>
#include <sys/socket.h>
#include <sys/ipc.h>
#include <sys/sem.h>
#include <semaphore.h>
#include <sys/msg.h>
#include <sys/shm.h>
#include <sys/un.h>typedef struct sockaddr_in addr_in_t;
typedef struct sockaddr addr_t;
typedef struct sockaddr_un addr_un_t;enum Type{TYPE_REGIST,TYPE_LOGIN,TYPE_CHAT,TYPE_FILE_UPLOAD_REQUEST
};typedef struct Pack{enum Type type;char name[20];char pswd[20];char filename[20];long filesize;char tarname[20];char text[1024];
}pack_t;void* thread_main(void* arg){int client = *(int*)arg;while(1){pack_t pack = {0};int res = read(client,&pack,sizeof(pack));if(res == 0){break;}switch(pack.type){case TYPE_REGIST:{printf("%s\n",pack.text);break;}case TYPE_LOGIN:{printf("%s\n",pack.text);break;}case TYPE_CHAT:{printf("接收到消息:%s\n",pack.text);break;}case TYPE_FILE_UPLOAD_REQUEST:{char filename[128] = "./client_file_system/";// 获取文件名,方便打开文件strcat(filename , pack.filename);int fd = open(filename,O_CREAT | O_TRUNC | O_WRONLY,0666);// 获取文件长度long filesize = pack.filesize;long readed_size = 0;//printf("接收到文件名和文件大小\n");while(1){pack_t filepack = {0};int res = read(client,&filepack,sizeof(filepack)); // 读取别的客户端发来的文件内容if(res != sizeof(filepack)){printf("发生分包\n");}int size = strlen(filepack.text);//printf("接受到文件信息\n");write(fd,filepack.text,size);// 将接受到的文件内容,写入文件中去readed_size += size;if(readed_size >= filesize){close(fd);break;}}break;}}}
}int main(int argc, const char *argv[])
{if(argc != 2){printf("请输入端口号\n");return 1;}// ./server 8888int port = atoi(argv[1]);// 将字符串 8888 转换成int类型portint client = socket(AF_INET,SOCK_STREAM,0);addr_in_t addr = {0};addr.sin_family = AF_INET;addr.sin_port = htons(port);addr.sin_addr.s_addr = inet_addr("192.168.60.77");if(connect(client,(addr_t*)&addr,sizeof(addr)) == -1){perror("connect");return 1;}pthread_t id;pthread_create(&id,0,thread_main,&client);pthread_detach(id);while(1){int ch = -1;printf("1:注册\n");printf("2:登录\n");printf("3:聊天\n");printf("4:发送文件\n");printf("0:退出\n");printf("请选择:");scanf("%d",&ch);while(getchar()!=10);switch(ch){case 1:{pack_t pack = {0};printf("请输入账号:");scanf("%s",pack.name);while(getchar()!=10);printf("请输入密码:");scanf("%s",pack.pswd);while(getchar()!=10);pack.type = TYPE_REGIST;write(client,&pack,sizeof(pack));break;}case 2:{pack_t pack = {0};printf("请输入账号:");scanf("%s",pack.name);while(getchar()!=10);printf("请输入密码:");scanf("%s",pack.pswd);while(getchar()!=10);pack.type = TYPE_LOGIN;write(client,&pack,sizeof(pack));break;}case 3:{// 聊天对象的姓名:聊天内容// 聊天对象的姓名放在pack.tarname里面// 聊天内容放在 pack.text 里面// 张三:你好pack_t pack = {0};pack.type = TYPE_CHAT;scanf("%s %s",pack.tarname,pack.text);printf("tarname = %19s\n",pack.tarname);while(getchar()!=10);write(client,&pack,sizeof(pack));break;}case 4:{pack_t pack = {0};pack.type = TYPE_FILE_UPLOAD_REQUEST;printf("请输入接受文件的用户名:");char tarname[20] = "";scanf("%19s",pack.tarname);strcpy(tarname,pack.tarname);while(getchar()!=10);printf("请输入想要发送的文件名:");scanf("%19s",pack.filename);while(getchar()!=10);int fd = open(pack.filename,O_RDONLY);if(fd == -1){printf("该文件不存在\n");break;}struct stat buf = {0};stat(pack.filename,&buf);pack.filesize = buf.st_size;write(client,&pack,sizeof(pack));while(1){pack_t pack = {0};pack.type = TYPE_FILE_UPLOAD_REQUEST;strcpy(pack.tarname,tarname);int res = read(fd,pack.text,1023);if(res == 0){break;}write(client,&pack,sizeof(pack));}close(fd);break;}case 0:{break;}}}return 0;
}

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

如若内容造成侵权/违法违规/事实不符,请联系长河编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

Qt 控件整理 —— 按钮类

一、PushButton 1. 介绍 在Qt中最常见的就是按钮&#xff0c;它的继承关系如下&#xff1a; 2. 常用属性 3. 例子 我们之前写过一个例子&#xff0c;根据上下左右的按钮去操控一个按钮&#xff0c;当时只是做了一些比较粗糙的去演示信号和槽是这么连接的&#xff0c;这次我们…

1.Excel:某停车场计划调整收费标准❗(13)

目录 函数VLOOKUP ROUNDUP/ROUNDDOWN函数 NO1​ NO2会计专用类型​ NO3收费标准VLOOKUP​ NO4停放时间&#xff08;天&#xff09;​ NO5金额roundup/rounddown​ ​NO6汇总行​ NO7单元格突出显示​ NO8数据透视表​ 函数VLOOKUP VLOOKUP(收费标准!A3:B5 F4&#xf…

玩转大语言模型——使用Kiln AI可视化环境进行大语言模型微调数据合成

系列文章目录 玩转大语言模型——使用langchain和Ollama本地部署大语言模型 玩转大语言模型——三分钟教你用langchain提示词工程获得猫娘女友 玩转大语言模型——ollama导入huggingface下载的模型 玩转大语言模型——langchain调用ollama视觉多模态语言模型 玩转大语言模型—…

OpenAI推出的Computer Use智能体:Operator是什么

OpenAI推出的Computer Use智能体:Operator是什么 是一款能像人一样与图形用户界面交互来操作计算机的AI智能体。以下是其核心原理及举例说明: 核心原理 感知: 屏幕截图获取:利用高性能屏幕捕获模块,如基于WebRTC的截图技术,以极低延迟获取高清晰度页面图像,为后续分析…

k8s部署logstash

1. 编写logstash.yaml配置文件 --- apiVersion: v1 kind: Service metadata:name: logstash spec:type: ClusterIPclusterIP: Noneports:- name: logstash-tcpport: 5000targetPort: 5000- name: logstash-beatsport: 5044targetPort: 5044- name: logstash-apiport: 9600targ…

【AI大模型】Ollama部署本地大模型DeepSeek-R1,交互界面Open-WebUI,RagFlow构建私有知识库

文章目录 DeepSeek介绍公司背景核心技术产品与服务应用场景优势与特点访问与体验各个DeepSeek-R系列模型的硬件需求和适用场景 Ollama主要特点优势应用场景安装和使用配置环境变量总结 安装open-webui下载和安装docker desktop配置镜像源安装open-webui运行和使用 RagFlow介绍主…

【办公】钉钉修改默认存储位置,释放C盘空间

Step1: 右击钉钉图标选择设置 Step2: 通用里面找到文件保存位置&#xff0c;修改文件目录: 最新版本钉钉界面&#xff1a; 设置完成后按提示重启即可&#xff01;

MVC(Model-View-Controller)framework using Python ,Tkinter and SQLite

1.项目结构 sql: CREATE TABLE IF NOT EXISTS School (SchoolId TEXT not null, SchoolName TEXT NOT NULL,SchoolTelNo TEXT NOT NULL) 整体思路 Model&#xff1a;负责与 SQLite 数据库进行交互&#xff0c;包括创建表、插入、删除、更新和查询数据等操作。View&#xff1…

MongoDB 扩缩容实战:涵盖节点配置、服务启动与移除操作

#作者&#xff1a;任少近 文章目录 一、扩容在245节点上配置配置config server&#xff1a;配置mongos启动config server安装工具mongosh添加245新节点到副本集配置分片副本集启动路由并分片 二、缩容Conf server上去掉server4shard上去掉server4mongos上去掉server4 一、扩容…

AGI时代的认知重塑:人类文明的范式转移与思维革命

文章目录 引言:站在文明转型的临界点一、认知危机:当机器开始理解世界1.1 AGI的本质突破:从模式识别到世界建模1.2 人类认知的脆弱性暴露二、认知革命:重构思维的四个维度2.1 元认知升级:从直觉思维到二阶观察2.2 混合智能:人机认知回路的构建2.3 认知安全:防御机器思维…

Java学习进阶路线

Java基础 Java Web 前端HTML/css/js&#xff0c;J2EE&#xff08;Servlet/jsp&#xff09;&#xff0c;数据库&#xff08;Mysql/oracle&#xff09; Java开发框架 Spring MVC/Mybatis/Herbernate/maven 《Java编程思想》 深入了解java基础 Java设计模式 《Effective j…

cursor接入deepseek

cursor安装 cursor下载地址&#xff1a; https://www.cursor.com/ Cursor为新用户提供14天的免费试ai。在这段时间内&#xff0c;你可以使用所有权限内的功能&#xff0c;并享受500次高级模型的快速请求。 额度用完或到期无法使用ai功能&#xff0c;不影响继续使用软件&#…

vscode/cursor+godot C#中使用socketIO

在 Visual Studio Code(VS Code)中安装 NuGet 包&#xff08;例如SocketIOClient&#xff09;&#xff0c;你可以通过以下几种方法&#xff1a; 方法 1&#xff1a;使用dotnet cli 打开终端&#xff1a;在 VS Code 中按下Ctrl 或者通过菜单View -> Terminal打开终端。 导…

LabVIEW 用户界面设计基础原则

在设计LabVIEW VI的用户界面时&#xff0c;前面板的外观和布局至关重要。良好的设计不仅提升用户体验&#xff0c;还能提升界面的易用性和可操作性。以下是设计用户界面时的一些关键要点&#xff1a; 1. 前面板设计原则 交互性&#xff1a;组合相关的输入控件和显示控件&#x…

git服务器搭建,gitea服务搭建,使用systemclt管理服务

文章目录 页面展示使用二进制文件安装git服务下载选择架构使用wget下载安装 验证 GPG 签名服务器设置准备环境创建systemctl文件 备份与恢复备份命令 (dump)恢复命令 (restore) 页面展示 使用二进制文件安装git服务 所有打包的二进制程序均包含 SQLite&#xff0c;MySQL 和 Po…

Kotlin Lambda

Kotlin Lambda 在探索Kotlin Lambda之前&#xff0c;我们先回顾下Java中的Lambda表达式&#xff0c;Java 的 Lambda 表达式是 Java 8 引入的一项强大的功能&#xff0c;它使得函数式编程风格的代码更加简洁和易于理解。Lambda 表达式允许你以一种更简洁的方式表示实现接口&…

Wpf美化按钮,输入框,下拉框,dataGrid

Wpf美化按钮&#xff0c;输入框&#xff0c;下拉框&#xff0c;dataGrid 引用代码后 引用资源 <ControlTemplate x:Key"CustomProgressBarTemplate" TargetType"ProgressBar"><Grid><Border x:Name"PART_Track" CornerRadius&q…

音视频协议

1. 多媒体信息 1.1 多媒体信息的两个主要特点&#xff1a; 信息量很大 标准语音&#xff1a;64Kbits(8KHz采样&#xff0c;8位编码)高质量音频&#xff1a;3Mbps(100KHz采样&#xff0c;12位编码) 在传输多媒体数据时&#xff0c;对时延和时延抖动均有较高要求 1.2 处理时延…

第一天:爬虫介绍

每天上午9点左右更新一到两篇文章到专栏《Python爬虫训练营》中&#xff0c;对于爬虫有兴趣的伙伴可以订阅专栏一起学习&#xff0c;完全免费。 键盘为桨&#xff0c;代码作帆。这趟为期30天左右的Python爬虫特训即将启航&#xff0c;每日解锁新海域&#xff1a;从Requests库的…

稀土抑烟剂——为汽车火灾安全增添防线

一、稀土抑烟剂的基本概念 稀土抑烟剂是一类基于稀土元素&#xff08;如稀土氧化物和稀土金属化合物&#xff09;开发的高效阻燃材料。它可以显著提高汽车内饰材料的阻燃性能&#xff0c;减少火灾发生时有毒气体和烟雾的产生。稀土抑烟剂不仅能提升火灾时的安全性&#xff0c;…