编写了一个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);

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;
	char buf[BUF_LEN];


	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){
//			perror("accept:");
			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);
		else if(strncmp(buf,"pull",strlen("pull"))==0)
			s_pull(rmsockfd,buf);
		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;
	do{
		memcpy(&fst,fn+BUF_LEN-sizeof(fst),sizeof(fst));
		fn += strlen("push");
		while(*fn == ' ')fn++;
		if(S_ISLNK(fst.st_mode)){
			continue; //暂时不处理链接文件
		}
		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\n",fn);
			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(recv(sockfd,fn,BUF_LEN,MSG_WAITALL)==BUF_LEN);
}

void s_pull(int sockfd,char *fn)
{
	int fd;
	off_t fsize,offset=0;
	ssize_t sndlen;
	fn += strlen("pull ");
	while(*fn == ' ')fn++;
	fd = open(fn,O_RDONLY);
	if(fd<0){
		perror("open:");
		return;
	}
	fsize = lseek(fd,0,SEEK_END);
	if(fsize==(off_t)-1){
		perror("lseek:");
		close(fd);
		return;
	}
	sndlen = sendfile(sockfd,fd,&offset,fsize);
	if(sndlen != fsize)
		perror("sendfile:");
	close(fd);
}

void c_push(int sockfd,char *fn,char *rmfn);
void c_pull(int sockfd,char *fn);

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){
		strcpy(buf,argv[3]);
		strcat(buf," ");
		strcat(buf,argv[4]);
		if(send(sockfd,buf,BUF_LEN-1,0)!=BUF_LEN-1){
			perror("send header failed:");
			return -1;
		}

		c_pull(sockfd,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;
	struct stat fst;
	char buf[BUF_LEN];
	if(stat(fn,&fst)==-1){
		perror("stat:");
		return;
	}
	if(S_ISLNK(fst.st_mode)){
		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_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...\n",fn);
		if(sendfile(sockfd,fd,&offset,fsize)!=fsize){
			perror("sendfile:");
		}
		close(fd);
	}
}

void c_pull(int sockfd,char *fn)
{
	int fd;
	ssize_t len;
	char buf[BUF_LEN];
	fd = open(fn,O_WRONLY|O_CREAT|O_TRUNC,0666);
	if(fd<0){
		perror("open:");
		return;
	}
	while(1){
		len = recv(sockfd,buf,BUF_LEN,0);
		if(len == 0){
			break;
		}
		else if(len>0){
			if(write(fd,buf,len)==-1)
				perror("write:");
			continue;
		}
		else if(errno==EINTR)
			continue;
		break;
	}
	close(fd);
}

仅需分析push那部分(pull还没改)。实在不知道什么情况了。传少量文件可以,但是传很多,比如某个工程的源代码时,就会出现错误。我是在本地127.0.0.1测试的。
编译后为mftp,创建mftpd软链接指向mftp,然后运行mftpd,再./mftp 127.0.0.1 5588 push ~/somefolder ~/newfolder