实现在Linux下利用TCP完成简单的文件传输,
但传输内容仅支持:
- 单个文件
- 内容均为单个文件的单个文件夹
在Linux下,设置2个文件夹,其中一个放server.c,作为服务器端,另一个放client.c,作为客户端。
先打开服务器端server.c,再打开客户端client.c。
客户端发送文件,文件接收到服务器根目录。
在传输文件里的各个单个文件时,想使用itoa函数atoi函数先传输文件的大小,客户端将文件大小转换为字符串形式发送给服务器端,服务器端接受该字符串信息后在转换为数字,获取待接收文件的大小。但Linux下没有itoa函数atoi函数,需要自己实现,于是参考了其他人的现成的代码,如有侵权,请告知我删除!:
atoi()函数:https://blog.csdn.net/yue_jijun/article/details/81530906
itoa()函数:https://blog.csdn.net/knowledgeaaa/article/details/38400355
客户端client.c代码:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <arpa/inet.h>
#include <unistd.h>
#include <dirent.h>
#define PORT 12345
#define IP "127.0.0.1"
#define BUFFSIZE 1024
void my_itoa(unsigned long val, char *buf, unsigned radix)
{
char *p; /* pointer to traverse string */
char *firstdig; /* pointer to first digit */
char temp; /* temp char */
unsigned digval; /* value of digit */
p = buf;
firstdig = p; /* save pointer to first digit */
do
{
digval = (unsigned)(val % radix);
val /= radix; /* get next digit */
/* convert to ascii and store */
if (digval > 9)
*p++ = (char)(digval - 10 + 'a'); /* a letter */
else
*p++ = (char)(digval + '0'); /* a digit */
}
while (val > 0);
/* We now have the digit of the number in the buffer, but in reverse
order. Thus we reverse them now. */
*p-- = '\0'; /* terminate string; p points to last digit */
do
{
temp = *p;
*p = *firstdig;
*firstdig = temp; /* swap *p and *firstdig */
--p;
++firstdig; /* advance to next two digits */
}
while (firstdig < p); /* repeat until halfway */
}
int main()
{
int fd = socket(AF_INET, SOCK_STREAM, 0);
struct sockaddr_in addr;
addr.sin_family = AF_INET;
addr.sin_port = htons(PORT);
inet_pton(AF_INET, IP, &(addr.sin_addr.s_addr));
char filename[100];
char foldername[100];
char buffer[BUFFSIZE];
int fileType;//0:Single file;1:folder
char fileTypeBuffer[1];
if (connect(fd, (struct sockaddr*)&addr, sizeof(addr)) < 0)
{
printf("error\n");
}
else
{
printf("connect success\n");
//选择传输文件的类型:
printf("Please select the file type to transfer!\n");
printf("0:Single file , 1:folder\n");
scanf("%d",&fileType);
if(fileType == 0)//Single file
{
fileTypeBuffer[0]='0';
//输入要传送的文件名,文件确保在根目录下
printf("input filename:\n");
scanf("%s", filename);
FILE* fp = fopen(filename, "r");
if (fp == NULL)
{
printf("file not exist\n");
}
else
{
printf("transport start\n");
send(fd,fileTypeBuffer,1,0);//传送文件类型
//先传送文件名,后传送文件内容
send(fd, filename, sizeof(filename), 0);
int t;
while ((t = fread(buffer, sizeof(char), BUFFSIZE, fp)) > 0)
{
send(fd, buffer, t, 0);
}
printf("transport finish\n");
}
fclose(fp);
}
else if(fileType == 1) //folder
{
fileTypeBuffer[0]='1';
send(fd,fileTypeBuffer,1,0);//传送文件类型
printf("input foldername:\n");
scanf("%s", foldername);
DIR * dp;
struct dirent *fp;
FILE* fp_fire;
dp = opendir(foldername);
if (!dp)
{
fprintf(stderr,"open directory error\n");
return 0;
}
send(fd, foldername, sizeof(foldername), 0);//传送文件夹名
char is_have_file[1];
is_have_file[0] = 'T';
while (fp = readdir(dp))
{
printf("filename:%-10s\td_info:%ld\t d_reclen:%us\n",
fp->d_name,fp->d_ino,fp->d_reclen);
if(fp->d_name[0] == '.' && fp->d_name[1] == 0){
continue;
}
else if(fp->d_name[0] == '.' && fp->d_name[1] == '.' && fp->d_name[2] == 0){
continue;
}
is_have_file[0] = 'T';
send(fd,is_have_file,1,0);//传送“还有其他文件”的信息
printf("send: is_have_file: \"%s\"\n",is_have_file);
send(fd,fp->d_name, 100,0);//传送文件名称
printf("send:fp->d_name: \"%s\"\n",fp->d_name);
char path[100]="./";
strcat(path, foldername);
strcat(path, "/");
strcat(path, fp->d_name);
printf("path: \"%s\"\n",path);
fp_fire = fopen(path, "r");
int t;
char file_len[100];
t = fread(buffer, sizeof(char), BUFFSIZE, fp_fire);
my_itoa(t,file_len,10);
printf("t = %d , file_len = \"%s\"\n",t,file_len);
send(fd, file_len, 100, 0);
send(fd, buffer, t, 0);
fclose(fp_fire);
}
is_have_file[0] = 'F';
send(fd,is_have_file,1,0);//传送“没有其他文件”的信息
closedir(dp);
}
else
{
printf("invalid input!\n");
return 0;
}
}
close(fd);
return 0;
}
服务器端server.c代码:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <arpa/inet.h>
#include <unistd.h>
#include <sys/stat.h>
#define PORT 12345
#define LISTENQ 10
#define BUFFSIZE 1024
int my_atoi(const char *str)
{
int flag = 1;
int result = 0;
if(str == NULL)
return 0;
while(*str == ' ' || *str == '\t')
str++;
if(*str == '-')
{
flag = -1;
str++;
}
while(*str != '\0')
{
if(*str >= 0 && *str <= '9')
result = result*10 + (*str - '0');
else
{
break;
}
str++;
}
return result * flag;
}
int passiveTCP() //封装 tcp 的建立
{
int fd = socket(AF_INET, SOCK_STREAM, 0);
struct sockaddr_in addr;
addr.sin_family = AF_INET;
addr.sin_port = htons(PORT);
addr.sin_addr.s_addr = INADDR_ANY;
bind(fd, (struct sockaddr*)&addr, sizeof(addr));
listen(fd, LISTENQ);
return fd;
}
int main()
{
int fd = passiveTCP();
char filename[100];
char foldername[100];
char buffer[BUFFSIZE];
int fileType;//0:Single file;1:folder
char fileTypeBuffer[1];
while (1)
{
//将文件接收到服务器根目录
int fd_;
struct sockaddr_in addr_;
int len = sizeof(addr_);
if ((fd_ = accept(fd, (struct sockaddr*)&addr_, &len)) < 0)
{
printf("error\n");
}
else
{
printf("connect success\n");
recv(fd_, fileTypeBuffer,1, 0);//接收文件类型
if(fileTypeBuffer[0] == '0') //Single file
{
recv(fd_, filename, sizeof(filename), 0);//接收文件名
FILE *fp = fopen(filename, "w");//创建文件
printf("transport start\n");
int t;
while ((t = recv(fd_, buffer, BUFFSIZE, 0)) > 0)
{
printf("--in_while--\n");
fwrite(buffer, sizeof(char), t, fp);//After test,this execute only onces
}
printf("transport finish\n");
fclose(fp);
}
else if(fileTypeBuffer[0] == '1') //folder
{
printf("transport folder start\n");
recv(fd_, foldername, sizeof(foldername), 0);//接收文件夹名
printf("recv: foldername: \"%s\"\n",foldername);
mkdir(foldername,0777);//创建文件夹
char is_have_file[1];
while(1){
printf("----while(1)----\n");//test
recv(fd_, is_have_file, 1, 0);//接收"还有没有文件"的信息
printf("is_have_file = \"%c\"\n",is_have_file[0]);//test
if(is_have_file[0] != 'T'){
break;
}
recv(fd_, filename, 100, 0);//接收文件名//XXX:sizeof(filename)???
printf("in while_1 : filename : \"%s\"\n",filename);
if(filename[0] == '.' && filename[1] == 0){
continue;
}
else if(filename[0] == '.' && filename[1] == '.' && filename[2] == 0){
continue;
}
char path[100]="./";
strcat(path, foldername);
strcat(path, "/");
strcat(path, filename);
printf("path: \"%s\"\n",path);//After test,this path is OK!
FILE *fp = fopen(path, "w");//创建文件
int t;
char file_len[100];
recv(fd_, file_len, 100, 0);
printf("file_len = \"%s\"\n",file_len);
int f_len = my_atoi(file_len);
printf("f_len = %d\n",f_len);
t = recv(fd_, buffer, f_len, 0);
printf("t = %d\n",t);
fwrite(buffer, sizeof(char), t, fp);
fclose(fp);
}
printf("transport folder finish\n");
}
else{
printf("Error:fileTypeBuffer ERROR!");
}
}
close(fd_);
}
close(fd);
return 0;
}