一个socket实例引发的神奇问题。

这是一个用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;
}

what?代码区不能标颜色?

发现不同构架之间传输出现错误(arm<–>x86_64),花了点时间终于找到问题所在。注意到源码的134行和 252行,这里严重依赖sizeof(struct stat)的值,在arm上是88,在x86_64上却是144。因此出错了。:lol