自己动手写web服务器四(web服务器是如何通过压缩数据,web服务器的gzip模块的实现)

来源:互联网 发布:海康网络视频监控方案 编辑:程序博客网 时间:2024/05/18 20:35

      web服务器为什么要压缩数据?

       web服务器如果将要发送的网页经过压缩后,待发送的数据将会减少一半左右,将会节省很大一部分的带宽,从而提高自己的并发量和减少网页传输时间。加快网页的浏览。

       是不是web服务器开启压缩一定会提高性能?

        不一定的,因为每次压缩,都需要对文件进行压缩算法。将会消耗一定cpu和I/O的。因此,当文件较小时没有必要开启压缩功能。


       本程序本人自己在ubuntu中编译成功,在ubuntu中经过Firefox中,window 系统IE 8,Firefox、chrome中测试成功。

本程序需要用到zlib压缩类库,没有装将无法成功,本人只提供在ubuntu中的代码及运行方式。希望大家谅解。关于用到的

zlib库中的知识,稍后会出新的博客做解释,关于gzip压缩的头部请看另外一篇博客     gzip头部格式

使用zlib说明http://blog.csdn.net/rentiansheng/article/details/8519681


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

运行过程:

1.将代码和makefile文件下载下来

2.在终端中转到代买和makefile所在的文件的目录中

3.执行make命令编译

4 执行生成的reage程序,(./reage)

5.在浏览器中输入127.0.0.1:1024 就可以看到结果了

(我的压缩内容时固定,不好意思了。也忘记输出压缩前的大小和压缩后的大小作比较了。因为内容少压缩的有点体现不出来的。重在功能实现的)

直接给大家上源代码。下面为源代码。(如有任何问题,希望大家指出来了)

/* *主要实现功能,对传输的数据使用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] = {'\037', '\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压缩后发给浏览器@parametersockd:套接字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: %d\r\n", 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:开始服务端监听@parameterip: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 bind\n" ); exit(101); };res = listen(res_socket,5);if(res) { printf( "listen port is error ;\n" ); exit( 102 );  };return res_socket ;}/*@description:向客户端发送网页头文件的信息@parameterconn_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 OK\r\n", 200);sprintf(buf, "%sServer: Reage Web Server\r\n", buf);sprintf(buf, "%sContent-Type: text/html\r\n", buf);sprintf(buf, "%sContent-Encoding: gzip\r\n\r\n", 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("reage\n");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);}

blogs:http://blog.csdn.net/rentiansheng/article/details/8517631

原创粉丝点击