linux高級I/O函數(2)——sendfile和splice

1、sendfile和splice相同之處

sendfile和splice這兩個函數都是在文件描述符之間傳輸數據的,而且兩者都是“零拷貝”,數據不需要內核空間和用戶空間直接做無謂的複製,區別在於,
sendfile函數的兩個文件描述符參數out_fd必須爲socket,
而splice函數的兩個文件描述符參數必須有一個是管道

#include<sys/sendfile.h>
ssize_t senfile(int out_fd,int in_fd,off_t* offset,size_t count);

#include <fcntl.h>
ssize_t splice(int fdin, loff_t *offin, int fdout, loff_t *offout, size_t len, unsigned int flags);
2、下面用兩個函數寫個簡單例子

用sendfile將文件的內容通過服務器發送給連接上的客戶端。
用splice函數寫一個簡單的回射服務器(將客戶端的數據返回給客戶端)。

3、sendfile
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <stdio.h>
#include <unistd.h>
#include <string.h>
#include <stdlib.h>
#include <poll.h>
#include <fcntl.h>
#include <errno.h>
#include <sys/sendfile.h>
#include <sys/stat.h>

/*sendfile 將文件內的數據發送給連接上的客戶端*/

const int  g_port = 10086;
const char* file_name = "test.txt";

int main(void)
{
	int filefd = open(file_name, O_RDONLY);
	if (filefd < 0) {
		printf("open err\n");
		return -1;
	}
	/*int fstat(int fdp, struct stat *struct_stat);  //通過文件描述符獲取文件對應的屬性。fdp爲文件描述符

下面是這個結構的結構
struct stat {
        mode_t     st_mode;       //文件對應的模式,文件,目錄等
        ino_t      st_ino;       //inode節點號
        dev_t      st_dev;        //設備號碼
        dev_t      st_rdev;       //特殊設備號碼
        nlink_t    st_nlink;      //文件的連接數
        uid_t      st_uid;        //文件所有者
        gid_t      st_gid;        //文件所有者對應的組
        off_t      st_size;       //普通文件,對應的文件字節數
	    ime_t     st_atime;      //文件最後被訪問的時間
        time_t     st_mtime;      //文件內容最後被修改的時間
        time_t     st_ctime;      //文件狀態改變時間
        blksize_t st_blksize;    //文件內容對應的塊大小
        blkcnt_t   st_blocks;     //偉建內容對應的塊數量
      };*/
	struct stat stat_buf;
	fstat(filefd, &stat_buf);

	struct sockaddr_in addr_server;
	bzero(&addr_server, sizeof(addr_server));
	addr_server.sin_family = AF_INET;
	addr_server.sin_port = htons(g_port);
	addr_server.sin_addr.s_addr = htonl(INADDR_ANY);

	int sfd = socket(AF_INET, SOCK_STREAM, 0);
	if (sfd < 0) {
		printf("socket err \n");
		return -1;
	}
	int ret = bind(sfd, (struct sockaddr*)&addr_server, sizeof(addr_server));
	if (ret < 0) {
		printf("binf err \n");
		return -1;
	}

	ret = listen(sfd, 10);
	if (ret < 0) {
		printf("listen err\n");
		return -1;
	}
	struct sockaddr_in addr_client;
	socklen_t addrlen_client = sizeof(addr_client);
	//bzero(&addr_client, addrlen_client);

	int cfd = accept(sfd, (struct sockaddr*)&addr_client, &addrlen_client);
	if (cfd < 0) {
		printf("accept err \n");
		return -1;
	}
	else
	{
		/*出現了*/
		/*#include<sys/sendfile.h>	
		ssize_t senfile(int out_fd,int in_fd,off_t* offset,size_t count);*/
		sendfile(cfd, filefd, NULL, stat_buf.st_size);
		close(cfd);
	}
	close(sfd);
	return 0;
}
4、splice
#define _GNU_SOURCE 1

#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <stdio.h>
#include <unistd.h>
#include <string.h>
#include <stdlib.h>
#include <fcntl.h>
#include <errno.h>


/*splice 實現的回射服務器*/

const int  g_port = 10086;


int main(void)
{
	int ret = 0;
	struct sockaddr_in addr_server;
	bzero(&addr_server, sizeof(addr_server));
	addr_server.sin_family = AF_INET;
	addr_server.sin_port = htons(g_port);
	addr_server.sin_addr.s_addr = htonl(INADDR_ANY);

	int sfd = socket(AF_INET, SOCK_STREAM, 0);
	if (sfd < 0) {
		printf("socket err \n");
		return -1;
	}
	ret = bind(sfd, (struct sockaddr*)&addr_server, sizeof(addr_server));
	if (ret < 0) {
		printf("binf err \n");
		return -1;
	}

	ret = listen(sfd, 10);
	if (ret < 0) {
		printf("listen err\n");
		return -1;
	}
	struct sockaddr_in addr_client;
	socklen_t addrlen_client = sizeof(addr_client);
	//bzero(&addr_client, addrlen_client);

	int cfd = accept(sfd, (struct sockaddr*)&addr_client, &addrlen_client);
	if (cfd < 0) {
		printf("accept err \n");
		return -1;
	}
	else
	{
		int pipefd[2];
		ret = pipe(pipefd);
		if (ret < 0) {
			printf("pipe err \n");
			return -1;
		}
		ret = splice(cfd, NULL, pipefd[1], NULL, 1024, SPLICE_F_MORE | SPLICE_F_MOVE);
		if (ret < 0) {
			printf("splice1 err\n");
			return -1;
		}
		ret = splice(pipefd[0], NULL, cfd, NULL, 1024, SPLICE_F_MORE | SPLICE_F_MOVE);
		if (ret < 0) {
			printf("splice2 err\n");
			return -1;
		}
		close(cfd);
	}
	close(sfd);
	return 0;
}
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章