使用零拷贝函数———sendfile函数以提高服务器性能

一、函数说明

sendfie函数在两个文件描述符之间直接传递数据,其中的操作完全在内核中执行,从而避免了内核缓冲区和用户缓冲区之间的数据拷贝,大大提高了效率,被称为零拷贝。sendfile函数定义如下:

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

参数说明:

  • in_fd:待读出内容的文件描述符
  • out_fd:待写入内容的文件描述符
  • offset:指定从读入文件流哪个位置开始,NULL则从起始位置
  • count:指定传输的字节数

sendfile成功返回传输的字节数,失败返回-1并设置errno。

注意 —— in_fd文件描述符必须指向一个真正存在的文件,不能是socket或是管道;out_fd则必须指向socket。

二、使用sendfile

//使用C实现简单的HTTP服务

#include<stdio.h>
#include<string.h>
#include<stdlib.h>
#include<assert.h>
#include<fcntl.h>
#include<sys/types.h>
#include<netinet/in.h>
#include<sys/stat.h>
#include<sys/socket.h>
#include<arpa/inet.h>
#include<sys/sendfile.h>


char * SendHead(int c, int size, char *pathname)   /* 发送头部信息 */
{
	char buff[1024] = {0};
	strcpy(buff, "HTTP/1.1 200 OK\n\r");
	strcat(buff, "Server: myhttpd/1.0\n\r");
	strcat(buff,"Content-Length: ");
	sprintf(buff+strlen(buff),"%d",size);//将size的%d值写入到buff+strlen(buff)处
	strcat(buff, "\n\r");
	strcat(buff, "Content-Type: text/html;charset=utf-8\n\r");
//	strcat(buff, "Set-Cookie: \n\r");
//	strcat(buff, "Via: \n\r");

	strcat(buff,"\n\r\n\r");

	send(c, buff, strlen(buff), 0);
}

void SendError(int c)  /* 错误信息 */
{
	char buff[1024] = {0};
	strcpy(buff, "HTTP/1.1 404 NOTFOUND\n\r");

	send(c, buff, strlen(buff), 0);
}

void AnayRequst(char *recvbuf, char *pathname)  /* 分析客户端请求 */
{
	//GET /index.heml HTTP/1.1
	char *p = strtok(recvbuf, " ");
	p = strtok(NULL, " ");
	strcpy(pathname, "/var/www/html");
	strcat(pathname, p);
}

void SendData(char *pathname, int c)  /* 回馈客户端 */
{
	struct stat st;
	stat(pathname, &st);
	SendHead(c, st.st_size, pathname);

	int fd = open(pathname, O_RDONLY);
	assert(fd != -1);
	
	sendfile(c, fd, NULL, st.st_size);

	close(c);
}

int main()
{
	int sockfd = socket(AF_INET, SOCK_STREAM, 0);
	assert(sockfd != -1);

	struct sockaddr_in ser,cli;
	memset(&ser, 0, sizeof(ser));

	ser.sin_family = AF_INET;
	ser.sin_port = htons(80);
	ser.sin_addr.s_addr = inet_addr("192.168.31.36");

	int res = bind(sockfd, (struct sockaddr *)&ser, sizeof(ser));
	assert(res != -1);

	listen(sockfd, 5);

	while(1)
	{
		int len = sizeof(cli);
		int c= accept(sockfd, (struct sockaddr *)&cli, &len);
		if(c < 0)
		{
			continue;
		}
	
		while(1)
		{
			char recvbuf[1024] = {0};
			int n = recv(c, recvbuf, 1023, 0);
			if(n <= 0)
			{
				SendError(c);
				close(c);
				break;
			}

			printf("%s\n",recvbuf);

			char pathname[128] = {0};

			AnayRequst(recvbuf, pathname);

			SendData(pathname, c);
			
			close(c);
		}
	}
}

结果:

猜你喜欢

转载自blog.csdn.net/judgejames/article/details/84791949
今日推荐