C#实现HTTP服务器:(5)压缩传输(GZip,Deflate)

完整项目托管地址:https://github.com/hooow-does-it-work/http

前面文章实现了通过Content-LengthTransfer-Encoding分别向客户端发送数据。
C#实现HTTP服务器:(3)封装用于响应请求的应答器
C#实现HTTP服务器:(4)使用Transfer-Encoding: Chunked标头向客户端发送响应

现在,在传输数据的基础上,我们再对数据进行压缩,C#有对这两种压缩算法的实现。
即,位于System.IO.Compression命名空间下的GZipStreamDeflateStream
这里只讲怎样使用Gzip压缩数据,分别用Content-LengthTransfer-Encoding两种传输方式实现。

0、使用Content-Length实现Gzip压缩数据的传输。

这种方式简单说,就是压缩数据后,取得所有数据的内容,获取到内容长度,然后一股脑的发送给客户端。
直接上代码了,使用Compress方法压缩数据,返回结果,发送到客户端,没什么理解的难度。
这里关键的是,发送Content-Encoding标头。
HttpResponser实现了this索引器,所以可以直接使用[]来设置标头。

public class HttpServer : TcpIocpServer
{
    protected override void NewClient(Socket client)
    {
        Stream stream = new NetworkStream(client, true);
        //捕获一个HttpRequest
        HttpRequest request = HttpRequest.Capture(stream);

        //准备发送到客户端的数据
        string responseText = $"<p>hello world!</p><pre>{request.GetAllRequestHeaders()}</pre>";

        byte[] responseBuffer = Encoding.ASCII.GetBytes(responseText);

        //压缩数据
        responseBuffer = Compress(responseBuffer);

        HttpResponser responser = new HttpResponser();

        //使用Content-Encoding标头,告诉客户端发送的是经过Gzip压缩的数据。 
        responser["Content-Encoding"] = "gzip";

        responser.ContentLength = responseBuffer.Length;

        responser.ContentType = "text/html";
        responser.KeepAlive = false;

        responser.Write(stream, responseBuffer);


        stream.Close();
    }

    /// <summary>
    /// Gzip压缩
    /// </summary>
    /// <param name="source">原内容</param>
    /// <returns>压缩后内容</returns>
    private byte[] Compress(byte[] source)
    {

        //使用内存流保存压缩后的数据
        using (MemoryStream output = new MemoryStream())
        {
            using (GZipStream input = new GZipStream(output, CompressionMode.Compress))
            {
                input.Write(source, 0, source.Length);
            }
            return output.ToArray();
        }
    }
}

启动服务,浏览器访问:http://127.0.0.1:4189
在这里插入图片描述
可以看到浏览器正确处理了Gzip压缩后的数据。

2、使用Transfer-Encoding标头传输Gzip压缩的数据。

话不多说,直接上源码,代码里面使用了ChunkedResponser应答器
这里可以查看ChunkedResponser实现

public class HttpServer : TcpIocpServer
{
    protected override void NewClient(Socket client)
    {
        Stream stream = new NetworkStream(client, true);
        //捕获一个HttpRequest
        HttpRequest request = HttpRequest.Capture(stream);

        //准备发送到客户端的数据
        string responseText = $"<p>hello world!</p><pre>{request.GetAllRequestHeaders()}</pre>";

        byte[] responseBuffer = Encoding.ASCII.GetBytes(responseText);

        //压缩数据
        responseBuffer = Compress(responseBuffer);

        //实例化ChunkedResponser类
        HttpResponser responser = new ChunkedResponser();

        //使用Content-Encoding标头,告诉客户端发送的是经过Gzip压缩的数据。 
        responser["Content-Encoding"] = "gzip";

        responser.ContentType = "text/html";
        responser.KeepAlive = false;

        responser.Write(stream, responseBuffer);
        responser.End(stream);

        stream.Close();
    }

    /// <summary>
    /// Gzip压缩
    /// </summary>
    /// <param name="source">原内容</param>
    /// <returns>压缩后内容</returns>
    private byte[] Compress(byte[] source)
    {
        //使用内存流保存压缩后的数据
        using (MemoryStream output = new MemoryStream())
        {
            using (GZipStream input = new GZipStream(output, CompressionMode.Compress))
            {
                input.Write(source, 0, source.Length);
            }
            return output.ToArray();
        }
    }
}

启动服务,浏览器访问:http://17.0.0.1:4189/在这里插入图片描述
可以看到浏览器正确处理了使用Chunked方式传输的Gzip压缩数据。

2、后话

其实这里的逻辑相比之前的代码,仅仅是加了一个Compress方法去压缩数据,单次压缩,单次写入。
整个逻辑中没有用到流的思想。
如果数据比较大,例如压缩大量的JS、CSS文件的时候,会产生不必要的大块内存消耗。
后面我们会实现一个ChunkedWriteStream,将一个JS文件压缩后,以Chunked的方式发送到客户端。

  • 1
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

Anlige

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值