首页 > 其他分享 >利用 TCP 完成文件传输的设计

利用 TCP 完成文件传输的设计

时间:2022-12-20 17:35:29浏览次数:31  
标签:addr buffer 文件传输 TCP filename clie fd printf 设计


利用 TCP 完成文件传输的设计

实验目的

输入文件路径,利用 TCP 实现客户文件向服务器的传输,并实现对 TCP 的基本封装

实验原理

1.服务器

(1)建立 socket
(2)确定服务器 scokaddr_in 结构体
(3)点分十进制 IP 转换
(4)使用 bind 绑定套接字
(5)使用 listen 监听
(6)使用 accept 接受连接请求
(7)accept 返回新的套接字描述符
(8)使用 recv 接收传来的数据(文件路径)
(9)打开文件,这里需要文件名
(10)从该字符串获取文件名
(11)使用 recv 接收文件内容
(12)判断 recv 函数返回的状态
(13)将接收到的内容放入缓冲区
(14)将缓冲区内容写入文件
(15)关闭文件
(16)关闭 socket

# 2.客户端

(1)建立 socket
(2)确定服务器 scokaddr_in 结构体
(3)点分十进制 IP 转换
(4)使用 connect 连接
(5)打开文件
(6)准备缓冲区
(7)缓冲区初始化置空
(8)将文件内容读入缓冲区
(9)使用 send 将缓冲区内容发送到服务器
(10)文件内容发送完成
(11)关闭文件
(12)关闭 socket

实验步骤

1.服务器

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <arpa/inet.h>
#include <unistd.h>

#define PORT 1111 // 设置端口号
#define LISTENQ 10 // 设置监听队列长度
#define BUFFSIZE 1024 // 设置缓冲区大小
#define FILE_BUFFSIZE 100 // 设置文件缓冲区大小
#define END_FLAG "end" // 结束标记

int passiveTCP() {//封装 tcp 的建立
// 创建套接字,使用流数据格式
int serv_fd = socket(AF_INET, SOCK_STREAM, 0);
// 定义一个地址结构体变量
struct sockaddr_in serv_addr;
// 清零地址
memset(&serv_addr, 0, sizeof(serv_addr));
// 给地址结构体设置值
serv_addr.sin_family = AF_INET; // Ipv4
serv_addr.sin_port = htons(PORT); // 指定端口号
serv_addr.sin_addr.s_addr = htonl(INADDR_ANY); // 指定任意ip
bind(serv_fd, (struct sockaddr*)&serv_addr, sizeof(serv_addr)); // 套接字绑定地址结构
listen(serv_fd, LISTENQ); // 设置为监听模式
return serv_fd; // 返回套接字
}
int main() {
int serv_fd = passiveTCP(); // 创建套接字并绑定端口和ip
char filename[FILE_BUFFSIZE];
char buffer[BUFFSIZE];
int cnt = 0;

while (1) {
//将文件接收到服务器根目录
int clie_fd;
// 定义一个新的地址结构变量
struct sockaddr_in clie_addr;
// 清零地址结构
memset(&clie_addr, 0, sizeof(clie_addr));

int len = sizeof(clie_addr);
// 处理连接请求, 返回一个新的套接字,用户客户端通信
printf("初始化成功\n");
if ((clie_fd = accept(serv_fd, (struct sockaddr *)&clie_addr, &len)) < 0) {
printf("error\n");
}
else {
char buff_t[BUFFSIZE] = { 0 }; //做中间临时保存
cnt ++;
printf("===connect success %d===\n", cnt);
// 处理考虑有多个文件的情况
while(1){
memset(filename, 0, FILE_BUFFSIZE);
memset(buffer, 0, BUFFSIZE);
recv(clie_fd, filename, sizeof(filename), 0);//接收文件名

if( strcmp(filename, END_FLAG) == 0 || strcmp(filename, "") == 0){
break; // 文件全部发送完毕
}

printf("#> %s\n", filename);
// 对文件名进行处理
int t = (int)(strchr(filename, '.') - filename); // 计算'.'的下标
// 判断文件有无后缀
if( t < 0 )
{
strcat(filename, "_副本");
printf("#> save filename: [%s]\n", filename);
}
else{
// 将后缀保存
strcpy(buff_t, filename + t);
printf("#> %s\n", buff_t);
strcpy(filename + t, "_副本");
printf("#> %s\n", filename);
strcat(filename, buff_t);
printf("#> save filename: [%s]\n", filename);
}
FILE *fp = fopen(filename, "w");//创建文件
printf("transport start\n");
int n;
// 接收文件内容,并写入打开的文件中,直到文件结尾
while ((n = recv(clie_fd, buffer, BUFFSIZE, 0)) > 0) {
//printf("%d: %s\n", strlen(buffer), buffer);
if( strcmp(buffer, END_FLAG) == 0){
break;
}
fwrite(buffer, sizeof(char), n, fp);
// buffer 清零
memset(buffer, 0, BUFFSIZE);
}
printf("transport finish\n");
printf("_______________________\n");
// 关闭文件
fclose(fp);
}
// 关闭连接新建套接字
close(clie_fd);
printf("===connect close %d===\n", cnt);
}
}
// 关闭服务器套接字
close(serv_fd);

return 0;
}

2.客户端

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <arpa/inet.h>
#include <unistd.h>

#define PORT 1111 // 设置端口号
#define IP "127.0.0.1" // 设置ip
#define BUFFSIZE 1024 // 设置缓冲区大小
#define FILE_BUFFSIZE 100
#define END_FLAG "end"

int main(int argc, char *argv[]) {
// 创建套接字,采用 流格式套接字 SOCK_STREAM
int clie_fd = socket(AF_INET, SOCK_STREAM, 0);
struct sockaddr_in clie_addr;
// 地址结构清零
memset(&clie_addr, 0, sizeof(clie_fd));

// 地址结构赋值
clie_addr.sin_family = AF_INET;
clie_addr.sin_port = htons(PORT);
clie_addr.sin_addr.s_addr = inet_addr(IP);// 指定ip
//inet_pton(AF_INET, IP, &(addr.sin_addr.s_addr));
//
char filename[FILE_BUFFSIZE];
char buffer[BUFFSIZE];

// 将 filename、buffer 清零
memset(filename, 0, sizeof(filename));
memset(buffer, 0, sizeof(buffer));
printf("=====================\n");
if (connect(clie_fd, (struct sockaddr*)&clie_addr, sizeof(clie_addr)) < 0) {
printf("error\n");
}
else {
int cnt = 0;
char file_name_t[FILE_BUFFSIZE][FILE_BUFFSIZE];
printf("===connect success===\n");
if( argc > 1 ){// 表示参数来自程序运行的参数
int i = 0;
for( i = 1;i < argc; i ++)
{
strcpy(file_name_t[cnt ++], argv[i]);
}
}
//输入要传送的文件名,文件确保在根目录下
else{
printf("input filename:");
fgets(filename, FILE_BUFFSIZE, stdin); // 输入遇到回车结束
// 将字符串最后的'\n'去掉
filename[strlen(filename) - 1] = '\0';
// 分割字符串
char *p = strtok(filename, " ");
while(p){
//printf("&> %s\n", p);
strcpy(file_name_t[cnt ++], p);
p = strtok(NULL, " ");
}
}
for(int i = 0; i < cnt; i ++){
if( strcmp(file_name_t[i], "") == 0 ){
continue;
}
FILE* fp = fopen(file_name_t[i], "r"); // 以读的方式打开文件
if (fp == NULL) {
printf("%s :file not exist\n", file_name_t[i]);
printf("$> %s\n\n", END_FLAG);
continue;
}
else {
//先传送文件名,后传送文件内容
printf("transport start\n");
send(clie_fd, file_name_t[i], sizeof(file_name_t[i]), 0);
printf("$> %s\n", file_name_t[i]);
int n;
// 读取文件的内容并发送,直到文件发送内容发送完毕
while ( (n = fread(buffer, sizeof(char), BUFFSIZE, fp)) > 0 ) {
send(clie_fd, buffer, n, 0);
// printf("%s\n", buffer);
// 发送完后将buffer清零
memset(buffer, 0, sizeof(buffer));
}
printf("transport finish\n");
sleep(0.5);
send(clie_fd, END_FLAG, sizeof(END_FLAG), 0); // 发送结束标志
printf("$> %s\n\n", END_FLAG);
}
// 关闭文件
fclose(fp);
sleep(0.5);
}
send(clie_fd, END_FLAG, sizeof(END_FLAG), 0); // 发送结束标志
printf("$> %s\n", END_FLAG);
}
printf("=====================\n");
// 关闭套接字
close(clie_fd);

return 0;
}

实验结果:

传输前客户端根目录下保存着我们
传输的文件 wct.txt

利用 TCP 完成文件传输的设计_socket


利用 TCP 完成文件传输的设计_#include_02


利用 TCP 完成文件传输的设计_#include_03


利用 TCP 完成文件传输的设计_socket_04


利用 TCP 完成文件传输的设计_套接字_05


标签:addr,buffer,文件传输,TCP,filename,clie,fd,printf,设计
From: https://blog.51cto.com/u_15918664/5956353

相关文章

  • 嵌入式软件设计---笔记
    嵌入式软件设计---笔记​​1.1引言​​​​1.1.1嵌入式系统基本概念​​​​1.1.2嵌入式系统举例​​​​1.1.3嵌入式系统的特点​​​​1.1.4嵌入式操作系统体系结构......
  • TCP那些你需要掌握的知识
    什么是TCP/IP?TCP/IP协议模型(TransmissionControlProtocol/InternetProtocol),包含了一系列构成互联网基础的网络协议,是Internet的核心协议。并不只有TCP与IP两种协......
  • 设计模式之六大原则
    关于设计模式的六大设计原则的资料网上很多,但是很多地方解释地都太过于笼统化,我也找了很多资料来看,发现CSDN上有几篇关于设计模式的六大原则讲述的比较通俗易懂,因此转载过来......
  • 嵌入式硬件电路设计六大基本功
    嵌入式设计是个庞大的工程,今天就说说硬件电路设计方面的几个注意事项,首先,咱们了解下嵌入式的硬件构架。我们知道,CPU是这个系统的灵魂,所有的外围配置都与其相关联,这也突出......
  • java中的模板设计模式【抽象类的最佳实践】
    本文主要讲述抽象类最佳实践,模板设计模式。老韩的介绍:示例代码如下:1/**2*需求:计算出执行一个job()方法,所需要花费的时间.3*使用模板设计模式【抽......
  • MySQL开源数据传输中间件架构设计实践
    主要内容: 本次分享将介绍目前数据迁移、数据同步、数据消费,多IDC架构中数据复制技术所面临问题及现有的产品和方案,并分享新开源的能在异构数据存储之间提供高性能和强大复......
  • pyqt5图书管理系统--8、学生页面设计、借阅状态页面设计和所有书籍页面设计
    本节分为三个部分:学生页面、借阅状态页面和所有书籍查询页面。主要流程:1、学生用户主界面,可以使用借阅书籍、归还书籍、查看借阅状态、查看所有书籍信息。     2、......
  • PyQt 界面设计要点
    1.需要先设计布局常规的布局有以下几种:​​QVBoxLayout​​,​​QHBoxLayout​​,​​QGridBoxLayout​​通过情况下的做法是采用QVBoxLayout作为基础的布局之后采用QH......
  • 设计模式 - 桥接模式
    目录​实例​​​数据转换工具​​​桥接模式​​​概念​​​​角色定义​​​​典型代码​​​​具体实现​​​​总结​​​​源码​​实例数据转换工具​​Sunny​​​......
  • PowerDotNet平台化软件架构设计与实现系列(14):平台建设指南
    软件开发中常见的几种不同服务模型包括SaaS(软件即服务)、LaaS(许可即服务)、PaaS(平台即服务)、CaaS(容器即服务)、IaaS(基础设施即服务)和FaaS(功能即服务)。很多人认为IaaS和FaaS是......