用C#编写的超小型Web服务器

3

我正在编写一个极小的Web服务器,用于教育目的。

对于以下代码,如果我请求包含图像的HTML页面,则无法在浏览器中看到该图像。我做错了什么?

static void Main(string[] args)
{
    TcpListener listener = new TcpListener(9999);
    listener.Start();
    while (true)
    { 
        TcpClient client = listener.AcceptTcpClient();
        string request = GetRequest(client.GetStream(),
            client.ReceiveBufferSize);
        WriteOutput(request, client.GetStream());
        client.Close();
    }
}

static void WriteOutput(string request, NetworkStream output)
{
    try
    {
        string[] reqs = request.Split(' ');
        WriteOutputHelper(output, reqs[1].Substring(1));
    }
    catch (Exception)
    {
        WriteOutputHelper(output, "404.html");
    }
}

private static void WriteOutputHelper(NetworkStream output, string file)
{
    byte[] statusLine = (new System.Text.ASCIIEncoding()).
        GetBytes(GetStatusLine(file) + "\r\n\r\n");
    output.Write(statusLine, 0, statusLine.Length);
    byte[] ContentType = 
        (new System.Text.ASCIIEncoding()).GetBytes(GetContentType(file) + 
            "\r\n\r\n");
    output.Write(ContentType, 0, ContentType.Length);
    byte[] response = System.IO.File.ReadAllBytes("C:\\" + file);
    output.Write(response, 0, response.Length);
    output.Flush();
}

static string GetContentType(string fileName)
{  
    string i = "<META http-equiv=\"Content-Type\" content=\"";
    if ((fileName.IndexOf(".htm") > -1) || (fileName.IndexOf(".html") > -1))
        i = i + "text/html";
    else if (fileName.IndexOf(".jpg") > -1)
        i = i + "image/jpeg";
    i = i + ";\">";
    return i;
}

static string GetStatusLine(string fileName)
{
    string i = "HTTP/1.0 ";
    if (fileName.IndexOf("404") > -1)
        return i + "404 Not Found";
    else if (fileName.IndexOf("jpg") > -1)
        return i + "302 Found";
    return i + "200 OK";
}

static string GetRequest(NetworkStream reqStream,int bufSize)
{
    byte[] bytesFrom = new byte[10025];
    reqStream.Read(bytesFrom, 0, bufSize);
    string request = System.Text.Encoding.ASCII.GetString(bytesFrom);
    return request;
}

抱歉,我没有看到需要翻译的内容。请您重新发送一遍。
    static void imageTest(NetworkStream output)
    {
        byte[] fileContent = System.IO.File.ReadAllBytes("C:\\sachin.jpg");
        string statusLine = "HTTP/1.0 200 OK" + System.Environment.NewLine;
        string contentType = "Content-type: image/jpeg" + System.Environment.NewLine;
        string contentLength = "Content-length: " + fileContent.Length + System.Environment.NewLine;
        System.Text.UnicodeEncoding coding = new UnicodeEncoding();
        byte[] headers = coding.GetBytes(statusLine + contentType + contentLength);
        output.Write(headers, 0, headers.Length);
        output.Write(fileContent, 0, fileContent.Length);
        output.Flush();
    }

对于上面的代码,我在Fiddler中遇到了以下错误。

服务器未返回正确格式的HTTP标头。HTTP标头应以CRLFCRLF结尾,但这些标头以LFLF结尾。

我正在使用Unicode编码,因为我想将字符串转换为字节,并且我只知道使用编码。


1
当您直接在浏览器地址栏中请求jpg时,它是否有效? - Heinzi
请显示生成的包含img标签的HTML。 - The Evil Greebo
不,它只是显示随机字符。 - Raja
以下是页面的HTML代码:<html><body><b>你好,世界</b> <img src="sachin.jpg" /> </body> </html> - Raja
1
为什么对于图像返回302?那是一个重定向。 - CodesInChaos
显示剩余2条评论
4个回答

5

JPG的响应应该只包含HTTP头和JPEG的内容,不应该包括任何HTML标签。

类似于:

HTTP/1.0 200 OK
Content-type: image/jpeg
Content-length: XXXXX

RAWJPEGDATA

将XXXXX替换为Jpeg文件的字节数,并直接输出原始JPEG数据,不进行任何编码。

使用Fiddler或Firebug进行调试——它们可以显示发送的精确请求和响应。


你可以回答一下问题中新添加的代码(imageTest方法)吗?我无法在这里粘贴代码。 - Raja
只需像之前一样使用 "\r\n\r\n" 即可 -- 您无法控制换行符是什么,而HTTP需要它正好是 "\r\n\r\n",无论操作系统如何。 - Lou Franco
即使从 System.Environment.NewLine 更改为 "\r\n",仍然没有成功。 - Raja
@LouFranco 为什么要使用"\r\n\r\n"而不是"\r\n"? - Kevin Le - Khnle
你需要使用额外的分隔符来标记头部的结束。这是HTTP规范的一部分。 - Lou Franco

5

看起来你正在发送JPEG文件的302 Found状态,这是用于重定向的。你需要像HTML文件一样发送200 OK


2
我认为问题出在WriteOutputHelperGetContentTypeHelper这两个方法上。
头部不应该有\r\n\r\n,一个就够了。另外,GetContentTypeHelper方法应该返回如下格式的头部:
Content-type: image/jpeg

这不是一个用于(X)HTML内容的html <meta>元素,也不是一个HTTP头。


0

你有没有考虑使用Cassini?它是一个开源项目,属于utildev。你当然可以自己编写,但你永远无法覆盖所有情况。我猜测问题可能是你的轻型Web服务器不支持所有MIME类型。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接