萬盛學電腦網

 萬盛學電腦網 >> 服務器教程 >> 實現web服務器中的gzip

實現web服務器中的gzip

 web服務器實現壓縮數據發送給浏覽器

web服務器使用gzip壓縮可以提高網站的響應速度,因為數據壓縮會消耗一定的cpu及I/O的。但是可以減少通過網絡傳輸的數據量。

從而提高網站的浏覽速度
本程序本人自己在ubuntu中編譯成功,在ubuntu中經過Firefox中,window 系統IE 8,Firefox、chrome中測試成功。

本程序需要用到zlib壓縮類庫,沒有裝將無法成功,本人只提供在ubuntu中的代碼及運行方式。希望大家諒解。關於用到的

zlib庫中的知識,稍後會出新的博客做解釋,關於gzip壓縮的頭部請看另外一篇博客 gzip頭部格式。


源碼及makefile下載地址:http://pan.baidu.com/share/link?shareid=167795&uk=2181414688

直接給大家上源代碼。下面為源代碼。(如有任何問題,希望大家指出來了)

/* 
*主要實現功能,對傳輸的數據使用gzip進行壓縮了
*1.實現綁定本機機器的1024端口作為ReageWeb服務提供網頁服務的端口。(避免與機器上裝有web服務器產生端口沖突)
* 作者:Reage
* blog:http://blog.csdn.net/rentiansheng
*/
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <sys/un.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <fcntl.h>
#include <string.h>
#include <sys/stat.h>
#include <signal.h>
#include <stdio.h>
#include <string.h>
#include <assert.h>
#include <zlib.h>

#define OS_CODE 0x03 /*Unix OS_CODE*/
#define DEFAULT_COMPRESSION Z_DEFAULT_COMPRESSION
#define DEFAULT_WINDOWSIZE -15
#define DEFAULT_MEMLEVEL 9
#define DEFAULT_BUFFERSIZE 8096
#define MAX 1024
#define METHOD 20 //獲取數據的方式,使用字符串的長度
#define URI 255 //表示URI的最大長度
#define VERSION 15	//HTTP版本好的最大長度
#define TYPE 20     //表示文件的類型的長度


int res_socket;
void app_exit();

static const char gzip_header[10] = {'37', '213', Z_DEFLATED, 0, 0, 0, 0, 0, 0, OS_CODE};

void put_long (unsigned char *string, unsigned long x) {
	string[0] = (x & 0xff);
	string[1] = ((x >> 8) & 0xff) ;
	string[2] = ((x >> 16) & 0xff) ;
	string[3] = ((x >> 24) & 0xff);
}



/*
@description:將數據使用gzip壓縮後發給浏覽器
@parameter
sockd:套接字
file: 要壓縮的內容了
*/
int gzip_buffer (int  sockd, char * msg, int len) {
	z_stream stream;//zlib使用的。
	int ret, flush;
	char in[MAX];//存放輸入的數據
	char send[MAX + 18 ];//存放壓縮過後的數據
	unsigned have;
	memcpy (send, gzip_header, 10);
	memset (in, 0, len);
	stream.zalloc = Z_NULL;
	stream.zfree = Z_NULL;
	stream.opaque = Z_NULL;
	stream.avail_in = 0;
	stream.next_in = Z_NULL;
	memcpy (in, msg, len);
	//壓縮初始化。
	int tmp_result = deflateInit2(&stream,
				Z_DEFAULT_COMPRESSION,//壓縮級別
				Z_DEFLATED,//壓縮方式
				-MAX_WBITS,
				8,
				Z_DEFAULT_STRATEGY);
	if (Z_OK != tmp_result) {
		printf("deflateInit error: %drn", tmp_result);
		return 0;
	}
	stream.avail_in = len; //要壓縮數據的長度
	stream.next_in = in;	//要壓縮數據的首地址
	stream.avail_out = MAX;  //可存放的最大輸出結果的長多。就是壓縮後數據的最大長度
	stream.next_out = send + 10; //存放壓縮數據的開始位置,send前十個字節用來放頭部
	ret = deflate (&stream,Z_FINISH); //壓縮
	assert (ret != Z_STREAM_ERROR);
	switch (ret) { 
		case Z_NEED_DICT:
			ret = Z_DATA_ERROR;
		case Z_DATA_ERROR:
		case Z_MEM_ERROR:
			(void)inflateEnd (&stream);
			return ret;
	}
	have = MAX - stream.avail_out;
	unsigned crc = crc32(0L, in, len); 
	char * tail = send + 10 + have;
	put_long (tail, crc);
	put_long (tail + 4, len);
	write (sockd, send, have + 18);
	deflateEnd (&stream);
	return 1;
}

/* 
@description:開始服務端監聽
@parameter
ip:web服務器的地址
port:web服務器的端口
@result:成功返回創建socket套接字標識,錯誤返回-1

*/
int socket_listen( char *ip, unsigned short int port){
	int res_socket; //返回值
	int res, on;
	struct sockaddr_in address;
	struct in_addr in_ip;
	res = res_socket = socket(AF_INET, SOCK_STREAM, 0);
	setsockopt(res_socket, SOL_SOCKET, SO_REUSEADDR, &on, sizeof(on));
	memset(&address, 0, sizeof(address));
	address.sin_family = AF_INET ;
	address.sin_port =htons(port);
	address.sin_addr.s_addr = htonl(INADDR_ANY); //inet_addr("127.0.0.1");
	res = bind( res_socket, (struct sockaddr *) &address, sizeof( address ) );
	if(res) { printf( "port is used , not to repeat bindn" ); exit(101); };
	res = listen(res_socket,5);
	if(res) { printf( "listen port is error ;n" ); exit( 102 );  };
	return res_socket ;
}

/*
@description:向客戶端發送網頁頭文件的信息
@parameter
conn_socket:套接字描述符。
status:http協議的返回狀態碼。
@s_status:http協議的狀態碼的含義
@filetype:向客戶端發送的文件類型
*/
void send_http_head(int conn_socket){ 
	char buf[MAX];
	memset(buf, 0, MAX);
	sprintf(buf, "HTTP/1.0 %d OKrn", 200);
	sprintf(buf, "%sServer: Reage Web Serverrn", buf);
	sprintf(buf, "%sContent-Type: text/htmlrn", buf);
	sprintf(buf, "%sContent-Encoding: gziprnrn", buf);
	write(conn_socket, buf, strlen(buf));
} 



int main(int argc, char * argv[] ){  
	int  conn_socket;
	int tmp ;
	int line ;
	struct sockaddr_in client_addr;
	char buf[MAX];
	int len = sizeof(client_addr);
	char method[METHOD], uri[MAX], version[VERSION], type[TYPE];
	char msg[] = "<br><br><h1>Reage Web Server gzip support text!
</h1><br/><h1><a href = "http://blog.csdn.net/rentiansheng">Reage blog</a>";
	res_socket = socket_listen( "127.0.0.1", 1024) ;
	//當按ctrl+c結束程序時調用,使用app_exit函數處理退出過程
	signal(SIGINT, app_exit);
	while(1){
		conn_socket = accept( res_socket, (struct sockaddr * )&client_addr, &len );
		printf("reagen");
		tmp = read (conn_socket, buf, MAX-1);
		buf [MAX - 1] = 0;
		send_http_head(conn_socket);
		gzip_buffer (conn_socket, msg, strlen(msg));
		close(conn_socket);
  	} 

}

void app_exit(){
	//回復ctrl+c組合鍵的默認行為
	signal (SIGINT, SIG_DFL);
	//關閉服務端鏈接、釋放服務端ip和端口
	close(res_socket);
	printf("n");
	exit(0);
}

copyright © 萬盛學電腦網 all rights reserved