这是一个用socket传输文件或文件夹的例子,经过若干测试没有问题。不过有几处疑问,已用红色标出,哪位大神指点迷津?以下是源码:
#include <sys/types.h>
#include <stdlib.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <arpa/inet.h>
#include <sys/socket.h>
#include <sys/sendfile.h>
#include <errno.h>
#include <stdio.h>
#include <string.h>
#include <unistd.h>
#include <dirent.h>
int mftpd_main(int argc,char **argv);
int mftp_main(int argc,char **argv);
void c_push(int sockfd,char *fn,char *rmfn);
void c_pull(int sockfd,char *rmfn,char *fn);
int main(int argc,char **argv)
{
char *tmp;
tmp = strrchr(argv[0],'/');
if(tmp != NULL)
argv[0] =tmp+1;
if(strcmp(argv[0],"mftpd")==0)
return mftpd_main(argc,argv);
else if(strcmp(argv[0],"mftp")==0)
return mftp_main(argc,argv);
else
fprintf(stderr,"%s: no such command.\n",argv[0]);
return -1;
}
#define PORT 5588
#define BUF_LEN 4096
void create_server();
int mftpd_main(int argc,char **argv)
{
create_server();
/*
switch(fork()){
case 0:
setsid();
switch(fork()){
case 0:
create_server();
break;
case -1:
perror("fork:");
return -1;
default:
exit(0);
}
break;
case -1:
perror("fork:");
return -1;
default:
exit(0);
}
*/
}
void s_push(int sockfd,char *cmd);
void s_pull(int sockfd,char *cmd);
void create_server()
{
struct sockaddr_in lcaddr,rmaddr;
int sockfd,rmaddr_len,rmsockfd;
ssize_t recv_len;
<font color="#ff0000"> char *buf = malloc(BUF_LEN); //Cannot use buf[BUF_LEN] ?!!
// char buf[BUF_LEN];
</font>
lcaddr.sin_port = htons(PORT);
lcaddr.sin_addr.s_addr = INADDR_ANY;
lcaddr.sin_family = AF_INET;
bzero(lcaddr.sin_zero,sizeof(lcaddr.sin_zero));
sockfd = socket(AF_INET,SOCK_STREAM,0);
if(sockfd == -1){
perror("socket:");
return;
}
if(bind(sockfd,(struct sockaddr*)&lcaddr,sizeof(lcaddr))==-1){
perror("bind:");
close(sockfd);
return;
}
if(listen(sockfd,1)==-1){
perror("listen:");
close(sockfd);
return;
}
while(1){
rmsockfd = accept(sockfd,(struct sockaddr*)&rmaddr,&rmaddr_len);
if(rmsockfd==-1){
fprintf(stderr,"accept error!\n");
continue;
}
recv_len = recv(rmsockfd,buf,BUF_LEN,MSG_WAITALL);
if(recv_len != BUF_LEN){
fprintf(stderr,"recieve header error:%s\n",buf);
close(rmsockfd);
continue;
}
if(strncmp(buf,"push",strlen("push"))==0){
s_push(rmsockfd,buf);
fprintf(stderr,"Finish!\n");
}
else if(strncmp(buf,"pull",strlen("pull"))==0){
s_pull(rmsockfd,buf);
fprintf(stderr,"Finish!\n");
}
else
fprintf(stderr,"no such command.\n");
close(rmsockfd);
}
}
void s_push(int sockfd,char *fn)
{
int fd,len;
off_t fsize;
struct stat fst;
<font color="#ff0000"> char oldfn[BUF_LEN]; //Cannot use heap memory here?!!
// char *oldfn = malloc(BUF_LEN);</font>
while(1){
memcpy(&fst,fn+BUF_LEN-sizeof(fst),sizeof(fst));
fn += strlen("push");
while(*fn == ' ')fn++;
if(S_ISLNK(fst.st_mode)){
len = recv(sockfd,oldfn,BUF_LEN,MSG_WAITALL);
if(len!=BUF_LEN){
fprintf(stderr,"recieve link path fail!\n");
break;
}
if(symlink(oldfn,fn)<0){
fprintf(stderr,"symlink %s to %s fail!\n",fn,oldfn);
}
}
else if(S_ISDIR(fst.st_mode)){
printf("mkdir %s\n",fn);
mkdir(fn,fst.st_mode);
}
else if(S_ISREG(fst.st_mode)){
fd = open(fn,O_WRONLY|O_CREAT|O_TRUNC,fst.st_mode);
fsize = fst.st_size;
printf("recieve file %s,its size is %ld\n",fn,fsize);
while(fsize>0){
len = recv(sockfd,fn,BUF_LEN<fsize?BUF_LEN:fsize,0);
if(len<0&&errno == EINTR)
continue;
if(len>0){
write(fd,fn,len);
fsize-=len;
continue;
}
}
close(fd);
}
while((len=recv(sockfd,fn,BUF_LEN,MSG_WAITALL))==-1&&errno==EINTR);
if(len!=BUF_LEN)
break;
}
}
void s_pull(int sockfd,char *fn)
{
int fd;
off_t fsize,offset=0;
ssize_t len;
char *buf = malloc(BUF_LEN);
fn += strlen("pull");
while(*fn == ' ')fn++;
if((len=recv(sockfd,buf,BUF_LEN,MSG_WAITALL))!=BUF_LEN){
fprintf(stderr,"recieve remote file name fail!\n");
return;
}
c_push(sockfd,fn,buf);
free(buf);
}
int mftp_main(int argc,char **argv)
{
int sockfd;
struct sockaddr_in lcaddr,rmaddr;
char buf[BUF_LEN];
if(argc!=6){
fprintf(stderr,"%s:\n\tusage:%s ipaddr port push[pull] localfile[remotefile] remotefile[localfile]\n",argv[0],argv[0]);
return -1;
}
lcaddr.sin_family = AF_INET;
lcaddr.sin_port = 0;
lcaddr.sin_addr.s_addr = INADDR_ANY;
bzero(lcaddr.sin_zero,sizeof(lcaddr.sin_zero));
rmaddr.sin_family = AF_INET;
rmaddr.sin_addr.s_addr = inet_addr(argv[1]);
rmaddr.sin_port = htons(atoi(argv[2]));
bzero(rmaddr.sin_zero,sizeof(rmaddr.sin_zero));
sockfd = socket(AF_INET,SOCK_STREAM,0);
if(sockfd<0){
perror("socket:");
return -1;
}
if(connect(sockfd,(struct sockaddr*)&rmaddr,sizeof(rmaddr))==-1){
perror("connet:");
close(sockfd);
return -1;
}
if(strcmp(argv[3],"push")==0){
c_push(sockfd,argv[4],argv[5]);
}
else if(strcmp(argv[3],"pull")==0){
c_pull(sockfd,argv[4],argv[5]);
}
else
fprintf(stderr,"%s:command not implement.\n",argv[3]);
close(sockfd);
return 0;
}
void c_push(int sockfd,char *fn,char *rmfn)
{
int fd;
off_t fsize;
off_t offset=0;
ssize_t pathlen;
struct stat fst;
char buf[BUF_LEN];
if(lstat(fn,&fst)==-1){
perror("stat:");
return;
}
strcpy(buf,"push");
strcat(buf,rmfn);
if(strlen(buf)+sizeof(fst)>BUF_LEN){
fprintf(stderr,"length of path too long!\n");
return;
}
memcpy(buf+BUF_LEN-sizeof(fst),&fst,sizeof(fst));
if(send(sockfd,buf,BUF_LEN,0)!=BUF_LEN){
perror("send header failed:");
return;
}
if(S_ISLNK(fst.st_mode)){
pathlen = readlink(fn,buf,BUF_LEN);
if(pathlen ==-1){
perror("readlink");
return;
}
else if(pathlen == BUF_LEN){
fprintf(stderr,"link path too long!\n");
return;
}
buf[pathlen] = '\0';
if(send(sockfd,buf,BUF_LEN,0)!=BUF_LEN){
perror("send link path fail");
return;
}
}
else if(S_ISDIR(fst.st_mode)){
DIR* pdir;
struct dirent *cf;
pdir = opendir(fn);
if(pdir==NULL){
perror("opendir");
return;
}
while((cf = readdir(pdir))!=NULL){
if(strcmp(cf->d_name,".")==0||strcmp(cf->d_name,"..")==0)
continue;
char *rmsubf = (char*) malloc(strlen(rmfn)+strlen(cf->d_name)+2);
char *subf = (char*) malloc(strlen(fn)+strlen(cf->d_name)+2);
if(subf==NULL||rmsubf==NULL){
fprintf(stderr,"no enough memory!\n");
free(subf);
free(rmsubf);
return;
}
strcpy(subf,fn);
strcat(subf,"/");
strcat(subf,cf->d_name);
strcpy(rmsubf,rmfn);
strcat(rmsubf,"/");
strcat(rmsubf,cf->d_name);
c_push(sockfd,subf,rmsubf);
free(subf);
free(rmsubf);
}
closedir(pdir);
}
else if(S_ISREG(fst.st_mode)){
fd = open(fn,O_RDONLY);
if(fd <0){
perror("open:");
return;
}
fsize = lseek(fd,0,SEEK_END);
printf("sending file %s,its size is %ld\n",fn,fsize);
if(sendfile(sockfd,fd,&offset,fsize)!=fsize){
perror("sendfile:");
}
close(fd);
}
}
void c_pull(int sockfd,char *rmfn,char *fn)
{
int fd;
ssize_t len;
char *buf = malloc(BUF_LEN);
<font color="#ff0000">// char buf[BUF_LEN]; //Can't use this instead of malloc?!!</font>
strcpy(buf,"pull");
strcat(buf,rmfn);
if(send(sockfd,buf,BUF_LEN,0)!=BUF_LEN){
fprintf(stderr,"send pull request fail!\n");
return;
}
strcpy(buf,fn);
if(send(sockfd,buf,BUF_LEN,0)!=BUF_LEN){
fprintf(stderr,"send local file name fail!\n");
return;
}
if((len=recv(sockfd,buf,BUF_LEN,MSG_WAITALL))!=BUF_LEN){
fprintf(stderr,"recv file info fail!\n");
return;
}
s_push(sockfd,buf);
<font color="#ff0000">// free(buf); //Cannot free it?!!</font>
// buf=NULL;
}