用tcp实现文件传输
文件发送端(tcp客户端)
1.网络链接
2.发送文件信息(文件名称, 文件大小)
3.发送文件内容(分段发送)文件接收端 (tcp服务器)
1.网络初始化监听
2.接收文件信息(创建一个空文件准备接收数据)
3.接收文件内容(分段接收,计算接收得长度==文件大小)
完整代码:
发文件
/*
1. 文件发送端(tcp客户端)
1.网络链接
2.发送文件信息(文件名称, 文件大小)
3.发送文件内容(分段发送)
*/
#include <stdio.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <string.h>
#include <unistd.h>
#include <sys/stat.h>
#include <stdlib.h>
#include <arpa/inet.h>
#include <string.h>
//创建文件信息的结构体
struct fileinfo{
char name[128];
unsigned int size;
};
int main(int argc, char **argv)
{
//判断传过来的参数是不是这4个
if(argc < 4)
{
printf("use:./sendfile ip port filepath\n"); // sendfile->发送文件程序 ip->ip地址 port->端口号 filepath->文件路径
return -1;
}
//创建套接字
int socketfd = socket(AF_INET,SOCK_STREAM, 0);//AF_INET ->IPV4 / AF_INET6->IPV6 /SOCK_STREAM(TCP协议)
if(socketfd < 0)
{
perror("socket fail");
return -1;
}
//连接服务器
struct sockaddr_in addr;
//socklen_t len = sizeof(addr);
memset(&addr, 0 ,sizeof(addr));//清空
addr.sin_family = AF_INET;
addr.sin_port = htons(atoi(argv[2]));//把字符串转成整性数
addr.sin_addr.s_addr = inet_addr(argv[1]);
int ret = connect(socketfd, (struct sockaddr *)&addr,sizeof(addr));//三次握手已经在这个connect函数内部完成了
// 获取文件信息
char *ptr = "/home/book/my.avi";
struct stat sbuf;
ret = stat(ptr,&sbuf);
unsigned int size = sbuf.st_size;
//创建存储文件信息的结构体
struct fileinfo info;
info.size = size;
//提取文件名称->strrchr用来查询最后的/的路径
char *p = NULL;
if(p = strrchr(ptr, '/'))
{
strcpy(info.name, p+1);//如果p="/",就取/后面的名称
}
else
{
strcpy(info.name, p);//如果p!="/",就取/
}
// while(1)
// {
write(socketfd, &info, sizeof(info));
// }
close(socketfd);
return 0;
}
收文件
/*
2. 文件接收端 (tcp服务器)
1.网络初始化监听
2.接收文件信息(创建一个空文件准备接收数据)
3.接收文件内容(分段接收,计算接收得长度==文件大小)
*/
#include <stdio.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <string.h>
#include <unistd.h>
#include <stdlib.h>
#include <arpa/inet.h>
//创建文件信息的结构体
struct fileinfo{
char name[128];
unsigned int size;
};
int main(int argc, char **argv)
{
int socketfd = socket(AF_INET,SOCK_STREAM, 0);//AF_INET ->IPV4 / AF_INET6->IPV6 /SOCK_STREAM(TCP协议)
if(socketfd < 0)
{
perror("socket fail");
return 0;
}
//初始化
//创建套接字
struct sockaddr_in addr;
//struct sockaddr_in *p = (struct sockaddr_in*)&addr;这个和上面的结构体是一样的,只是细化了
memset(&addr, 0 ,sizeof(addr)) ;//清空
addr.sin_family = AF_INET;//地址族
addr.sin_port = htons(8989);//转化端口号
addr.sin_addr.s_addr = INADDR_ANY;//结构体里的结构sin_addr里的s_addr;INADDR_ANY这个宏就是0
//绑定->端口号只能绑定一次,被用过不能再用
int ret = bind(socketfd, (struct sockaddr *)&addr, sizeof(addr)); //bind()是绑定函数
if(ret < 0)
{
perror("绑定失败");
return -1;
}
//监听
ret = listen(socketfd, 5);//长度为5
if(ret < 0)
{
perror("监听失败");
return -1;
}
//接受连接,这个函数是阻塞的
struct sockaddr_in clientaddr;
socklen_t len = sizeof(clientaddr);
int clientfd = accept(socketfd, (struct sockaddr*)&clientaddr, &len);
if(clientfd < 0)
{
perror("连接失败");
return -1;
}
//接受读取数据->读到的是http通信的数据
struct fileinfo info;
memset(&info, 0, sizeof(info));
char recvbuffer[1024];
while(1)
{
//接收文件头
ssize_t rd = read(clientfd, &info, sizeof(info));
if(rd <= 0)
{
printf("客户端掉线\n");
break;
}
printf("读到的数据:%s----%u\n", info.name, info.size);//数据时浏览器发过来的
}
//关闭
close(clientfd);
close(socketfd);
return 0;
}
执行结果
版权声明:本文为qq_42343682原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接和本声明。