1
回答
关于sendfile()函数在linux下C语言的应用?
利用AWS快速构建适用于生产的无服务器应用程序,免费试用12个月>>>   

我好奇sendfile()这个函数,他们说这个函数比较高效,因此我也想用来试试;项目中我用read和write来实现二进制文件传输,很慢;以下是我的tcp C/S 的socket代码,也许是我对sendfile()理解不够深刻,至今未能运行,实现不了功能.特来求助:

server端

int main(int argc, char **argv)
{
	int sockfd;                	/* socket desciptor */
	int connfd;                	/* file descriptor for socket */
	int port = 1234;           	/* port number to use */
	int addrlen;				/* argument to accept */
	int ret;                    /* holds return code of system calls */
	int fd;                    	/* file descriptor for file to send */

	char filename[PATH_MAX];   	/* filename to send */
	off_t offset = 0;          	/* file offset */
	struct stat stat_buf;      	/* argument to fstat */
	
	struct sockaddr_in addrserver;   	/* socket parameters for bind ipv4*/
	struct sockaddr_in addrclient;  	/* socket parameters for accept ipv4*/

	/* check command line arguments, handling an optional port number */
	if (argc == 2) {
		port = atoi(argv[1]);
		if (port <= 0) {
			fprintf(stderr, "invalid port: %s\n", argv[1]);
			exit(1);
		}
	} else if (argc != 1) {
		fprintf(stderr, "usage: %s [port]\n", argv[0]);
		exit(1);
		}

	/* create Internet domain socket */
	sockfd = socket(AF_INET, SOCK_STREAM, 0);
	if (sockfd == -1) {
		fprintf(stderr, "unable to create socket: %s\n", strerror(errno));
		exit(1);
	}

	/* fill in socket structure */
	bzero(&addrserver, sizeof(addrserver));
	addrserver.sin_family = AF_INET;
	addrserver.sin_addr.s_addr = INADDR_ANY;
	addrserver.sin_port = htons(port);

	/* bind socket to the port */
	ret =  bind(sockfd, (struct sockaddr *)&addrserver, sizeof(addrserver));
	if (ret == -1) {
		fprintf(stderr, "unable to bind to socket: %s\n", strerror(errno));
		exit(1);
	}

	/* listen for clients on the socket */
	ret = listen(sockfd, 1);
	if (ret == -1) {
		fprintf(stderr, "listen failed: %s\n", strerror(errno));
		exit(1);
	}

	for ( ;; ) {

		/* wait for a client to connect */
		connfd = accept(sockfd, (struct sockaddr *)&addrclient, &addrlen);
		if (connfd == -1) {
			fprintf(stderr, "accept failed: %s\n", strerror(errno));
			exit(1);
		}

		/* get the file name from the client */
		ret = recv(connfd, filename, sizeof(filename), 0);
		if (ret == -1) {
			fprintf(stderr, "recv failed: %s\n", strerror(errno));
			exit(1);
		}

		/* null terminate and strip any \r and \n from filename */
		filename[ret] = '\0';
		if ( (filename[strlen(filename)-1] == '\n') || \
			(filename[strlen(filename)-1] == '\r'))
			filename[strlen(filename)-1] = '\0';

		/* exit server if filename is "quit" */
		if (strcmp(filename, "quit") == 0) {
			fprintf(stderr, "quit command received, shutting down server\n");
			break;
		}

		fprintf(stderr, "received request to send file %s\n", filename);

		/* open the file to be sent */
		fd = open(filename, O_RDONLY);
		if (fd == -1) {
			fprintf(stderr, "unable to open '%s': %s\n", filename, strerror(errno));
			exit(1);
		}

		/* get the size of the file to be sent */
		fstat(fd, &stat_buf);

		/* copy file using sendfile */
		offset = 0;
		ret = sendfile (connfd, fd, &offset, stat_buf.st_size);
		if (ret == -1) {
			fprintf(stderr, "error from sendfile: %s\n", strerror(errno));
			exit(1);
		}
		
		if (ret != stat_buf.st_size) {
			fprintf(stderr,\
				"incomplete transfer from sendfile: %d of %d bytes\n",\
				ret, (int)stat_buf.st_size);
			exit(1);
		}

		/* close descriptor for file that was sent */
		close(fd);
		/* close socket descriptor */
		close(connfd);
	}//for(;;)
	/* close socket */
	close(sockfd);
	
	return 0;
}



client端

int main(int argc,char **argv)
{
	if(argc != 3)
		usage(argv[0]);

	int fd, sockfd;
	char buf[MAXSIZE];
	struct stat stat_buf;
	ssize_t bytes;

		sockfd = socket(AF_INET,SOCK_STREAM,0);
		struct sockaddr_in srvaddr;
		bzero(&srvaddr,sizeof(srvaddr));
		srvaddr.sin_family = AF_INET;
		inet_pton(AF_INET,argv[1],
			(struct sockaddr *)&(srvaddr.sin_addr));
		srvaddr.sin_port = htons(atoi(argv[2]));
		connect(sockfd, (struct sockaddr *)&srvaddr,
			sizeof(srvaddr));

	fd = fopen("0B01A8C0.img", "ab+");
	fstat(fd, &stat_buf);
	fgets(buf, MAXSIZE, stdin);
	write(sockfd, buf, strlen(buf));
	int max = 5000000;
	printf("st_size:%d\n", stat_buf.st_size);
	while( (bytes = sendfile(fd, sockfd, 0, stat_buf.st_size)) > 0 || (stat_buf.st_size - bytes) > 1000 ) {
		printf("ret = %d \n", bytes);
		max -= bytes;
		continue;
	}

	close(fd);
	close(sockfd);

	return 0;
}


举报
TymonHuang
发帖于5年前 1回/1K+阅
顶部