Linux-C 简单的TCP文件传输例子
一、简述
记--使用TCP协议进行端到端的文件传输 的简单例子。并利用该程序将Ubuntu将文件传输到开发板。
例子打包:链接: https://pan.baidu.com/s/1q88GZLWTQ-yQqkLAsQ9r_Q 提取码: spms
例子是一个简单的测试,还有很多细节没有考虑,还有待完善!
二、效果
在Ubuntu16.04上测试,recv接收文件,send发送文件。(注意测试环境不同可能结果不同,多数是因为程序逻辑问题)
三、源文件
recv.c文件
#include <stdio.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <stdlib.h>
#include <unistd.h>
#include <string.h>
#include <pthread.h>
#include <sys/stat.h>
#include <fcntl.h>
int main(int argc, char *argv[])
{
//判断命令行参数是否匹配
if(argc != 2)
{
printf("./recv port\n");
return -1;
}
//创建tcp通信socket
int tcp_socket = socket(AF_INET, SOCK_STREAM, 0);
if (tcp_socket == -1)
{
perror("create socketfd failed\n");
return -1;
}
//绑定地址
struct sockaddr_in local_addr = {0};
local_addr.sin_family = AF_INET;
local_addr.sin_port = htons(atoi(argv[1]));
local_addr.sin_addr.s_addr = INADDR_ANY;//让系统自动检测本地网卡IP并绑定
int ret = bind(tcp_socket, (struct sockaddr *)&local_addr, sizeof(local_addr));
if (ret == -1)
{
perror("bind failed\n");
return -1;
}
//设置监听队列
ret = listen(tcp_socket, 5);
if(ret == -1)
{
perror("listen is fail\n");
return -1;
}
//客户端地址信息
struct sockaddr_in client_addr={0};
int len = sizeof(client_addr);
printf("server is running\n");
//通信socket
int new_socket = 0;
while (1)
{
//等待客户端的请求
new_socket = accept(tcp_socket,(struct sockaddr *)&client_addr,&len);
if(new_socket < 0)
{
perror("accept error\n");
continue;
}
//输出对方的IP地址信息
printf("client connected [%s:%d]\n",inet_ntoa(client_addr.sin_addr),ntohs(client_addr.sin_port));
char file_len[16] = {0};//文件长度
char file_name[128] = {0};//文件名称
char buf[1024] = {0};//数据缓冲区
//读取文件大小和文件名称
read(new_socket, buf, sizeof(buf));
strncpy(file_len, buf, sizeof(file_len));//取出文件大小
strncpy(file_name, buf+sizeof(file_len), sizeof(file_name));//取出文件名称
printf("ready receive!!!! file name:[%s] file size:[%s] \n",file_name, file_len);
//新的文件名
sprintf(buf, "recv-%s", file_name);
//创建新文件
int fd = open(buf, O_RDWR | O_CREAT | O_TRUNC, 0666);
int size = atoi(file_len);//文件大小
int write_len = 0;//记录已写入的字节数
//接收文件
while(1)
{
bzero(buf, 1024);
//接收文件数据
ret = read(new_socket, buf, sizeof(buf));
if( ret <= 0)
{
printf("\n [recv-%s] receive file done!!!\n", file_name);
break;
}
//将数据写入文件
write(fd, buf, ret);
write_len += ret;//记录写入的字节数
//动态的输出接收进度
printf("uploading %.2f%% \n", (float)write_len/size * 100);
}
break;
}
//关闭socket
close(new_socket);
close(tcp_socket);
return 0;
}
send.c文件
#include <stdio.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <stdlib.h>
#include <unistd.h>
#include <string.h>
#include <pthread.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <libgen.h>//basename():从路径中获取文件名及后缀
int main(int argc, char * argv[])
{
if(argc != 3)
{
printf("请输入文件接收方的IP、端口号\n");
return -1;
}
int port = atoi(argv[2]);
//创建TCP通信socket
int tcp_socket = socket(AF_INET, SOCK_STREAM, 0);
if (tcp_socket == -1)
{
perror("create socketfd is fail\n");
return -1;
}
//目的地址
struct sockaddr_in dest_addr = {0};
dest_addr.sin_family = AF_INET;
dest_addr.sin_port = htons(port);
dest_addr.sin_addr.s_addr = inet_addr(argv[1]);
int ret = -1;
//请求连接目标地址
ret = connect(tcp_socket, (struct sockaddr *)&dest_addr, sizeof(dest_addr));
if(ret != 0)//连接成功
{
perror("connect failed\n");
return -1;
}
printf("\nConnect succeed!\n");
char file_path[128] = {0};//文件路径
char file_info[2048] = {0};//文件信息
char buf[1024] = {0};
//获取用户输入的文件路径
printf("Please enter file path: ");
scanf("%s", file_path);
//从文件路径中获取文件名,如"test/a.txt" ==> "a.txt"
char file_name[128] = {0};
strncpy(file_name, basename(file_path), sizeof(file_name));
//打开文件
int fd = open(file_path, O_RDWR);
if (fd == -1)
{
printf("open [%s] failed", file_path);
return -1;
}
//计算文件大小
int len = lseek(fd, 0, SEEK_END);
//文件光标偏移到文件开始位置
lseek(fd, 0, SEEK_SET);
//将文件大小和文件名存放到file_info
sprintf(file_info, "%d", len);
strcpy(file_info + 16, file_name);
// 将需要上传的文件名告诉对方
write(tcp_socket, file_info, 144);
int send_len = 0;//记录发送了多少字节
while (1)
{
bzero(buf, sizeof(buf));
//读取数据
ret = read(fd, buf, sizeof(buf));
if (ret <= 0)
{
printf("send file[%s] succeed!!!!\n", file_name);
break;
}
//发送数据
write(tcp_socket, buf, ret);
send_len += ret;//统计发送了多少字节
//上传文件的百分比
printf("uploading %.2f%%\n", (float)send_len/len * 100);
}
// 关闭文件
close(fd);
//关闭通信socket
close(tcp_socket);
return 0;
}
四、Ubuntu传输文件到开发板
注:Ubuntu与开发板互相ping通。
五、接收文件内容为空
请在send.c 的以下内容添加以下延时
感谢qq_****2863指出!!! (是在Ubuntu 12.04.2 LTS 32bit上遇到的)