简单消息服务器,(9条消息)C#开发一个简单的Http服务器及客户端

本文档展示了如何使用C#编写一个简单的HTTP服务器,该服务器可以处理GET和POST请求。代码包括解析HTTP请求、读取头部信息以及处理GET和POST请求的方法。服务器在本地运行并监听8888端口,当接收到请求时,会返回一个JSON响应。对于POST请求,服务器读取请求体并将数据保存到内存流中。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

/*

*

* C#实现了一个最简单的HTTP服务器类,你可以将它嵌入到自己的项目中,或者也可以阅读代码来学习关于HTTP协议的知识。

* 高性能的WEB应用一般都架设在强大的WEB服务器上,例如IIS, Apache, 和Tomcat。然而,HTML是非常灵活的UI标记语言,

* 也就是说任何应用和后端服务都可以提供HTML的生成支持。在这个小小的例子中,像IIS,、Apache这样的服务器消耗的资源太大了,

* 我们需要自己实现一个简单的HTTP服务器,将它嵌入到我们的应用中用来处理WEB请求。我们仅需要一个类就可以实现了,很简单。

*

*

* 如果你编译运行这个项目,你会在浏览器http://localhost:8888/地址下看到页面上生成的示例内容。让我们来简单看一下这个HTTP服务器引擎是怎么实现的。

*/

using System;

using System.Collections;

using System.IO;

using System.Net;

using System.Net.Sockets;

using System.Threading;

using System.Threading.Tasks;

namespace SimpleHttpServer

{

public class HttpProcessor

{

public TcpClient socket;

public HttpServer srv;

private Stream inputStream;

public StreamWriter outputStream;

public String http_method;

public String http_url;

public String http_protocol_versionstring;

public Hashtable httpHeaders = new Hashtable();

private static int MAX_POST_SIZE = 10 * 1024 * 1024; // 10MB

public HttpProcessor(TcpClient s, HttpServer srv)

{

this.socket = s;

this.srv = srv;

}

private string streamReadLine(Stream inputStream)

{

int next_char;

string data = "";

while (true)

{

next_char = inputStream.ReadByte();

if (next_char == '\n') { break; }

if (next_char == '\r') { continue; }

if (next_char == -1) { Thread.Sleep(1); continue; };

data += Convert.ToChar(next_char);

}

return data;

}

public void process()

{

// we can't use a StreamReader for input, because it buffers up extra data on us inside it's

// "processed" view of the world, and we want the data raw after the headers

inputStream = new BufferedStream(socket.GetStream());

// we probably shouldn't be using a streamwriter for all output from handlers either

outputStream = new StreamWriter(new BufferedStream(socket.GetStream()));

try

{

parseRequest();

readHeaders();

if (http_method.Equals("GET"))

{

handleGETRequest();

}

else if (http_method.Equals("POST"))

{

handlePOSTRequest();

}

}

catch (Exception e)

{

Console.WriteLine("Exception: " + e.ToString());

writeFailure();

}

outputStream.Flush();

// bs.Flush(); // flush any remaining output

inputStream = null; outputStream = null; // bs = null;

socket.Close();

}

public void parseRequest()

{

String request = streamReadLine(inputStream);

string[] tokens = request.Split(' ');

if (tokens.Length != 3)

{

throw new Exception("invalid http request line");

}

http_method = tokens[0].ToUpper();

http_url = tokens[1];

http_protocol_versionstring = tokens[2];

Console.WriteLine("starting: " + request);

}

public void readHeaders()

{

Console.WriteLine("readHeaders()");

String line;

while ((line = streamReadLine(inputStream)) != null)

{

if (line.Equals(""))

{

Console.WriteLine("got headers");

return;

}

int separator = line.IndexOf(':');

if (separator == -1)

{

throw new Exception("invalid http header line: " + line);

}

String name = line.Substring(0, separator);

int pos = separator + 1;

while ((pos < line.Length) && (line[pos] == ' '))

{

pos++; // strip any spaces

}

string value = line.Substring(pos, line.Length - pos);

Console.WriteLine("header: {0}:{1}", name, value);

httpHeaders[name] = value;

}

}

public void handleGETRequest()

{

srv.handleGETRequest(this);

}

private const int BUF_SIZE = 4096;

public void handlePOSTRequest()

{

// this post data processing just reads everything into a memory stream.

// this is fine for smallish things, but for large stuff we should really

// hand an input stream to the request processor. However, the input stream

// we hand him needs to let him see the "end of the stream" at this content

// length, because otherwise he won't know when he's seen it all!

Console.WriteLine("get post data start");

int content_len = 0;

MemoryStream ms = new MemoryStream();

if (this.httpHeaders.ContainsKey("Content-Length"))

{

content_len = Convert.ToInt32(this.httpHeaders["Content-Length"]);

if (content_len > MAX_POST_SIZE)

{

throw new Exception(

String.Format("POST Content-Length({0}) too big for this simple server",

content_len));

}

byte[] buf = new byte[BUF_SIZE];

int to_read = content_len;

while (to_read > 0)

{

Console.WriteLine("starting Read, to_read={0}", to_read);

int numread = this.inputStream.Read(buf, 0, Math.Min(BUF_SIZE, to_read));

Console.WriteLine("read finished, numread={0}", numread);

if (numread == 0)

{

if (to_read == 0)

{

break;

}

else

{

throw new Exception("client disconnected during post");

}

}

to_read -= numread;

ms.Write(buf, 0, numread);

}

ms.Seek(0, SeekOrigin.Begin);

}

Console.WriteLine("get post data end");

srv.handlePOSTRequest(this, new StreamReader(ms));

}

public void writeSuccess()

{

outputStream.WriteLine("HTTP/1.0 200 OK");

outputStream.WriteLine("Content-Type: text/html;charset=utf-8");

outputStream.WriteLine("Connection: close");

outputStream.WriteLine("");

}

public void writeFailure()

{

outputStream.WriteLine("HTTP/1.0 404 File not found");

outputStream.WriteLine("Connection: close");

outputStream.WriteLine("");

}

}

public abstract class HttpServer

{

protected int port;

TcpListener listener;

bool is_active = true;

public HttpServer(int port)

{

this.port = port;

}

public void listen()

{

listener = new TcpListener(port); //TcpListener(IPAddress localaddr, int port);

listener.Start();

while (is_active)

{

TcpClient s = listener.AcceptTcpClient();

HttpProcessor processor = new HttpProcessor(s, this);

Thread thread = new Thread(new ThreadStart(processor.process));

thread.Start();

Thread.Sleep(1);

}

}

public abstract void handleGETRequest(HttpProcessor p);

public abstract void handlePOSTRequest(HttpProcessor p, StreamReader inputData);

}

public class MyHttpServer : HttpServer

{

public MyHttpServer(int port) : base(port)

{

}

public override void handleGETRequest(HttpProcessor p)

{

Console.WriteLine("request: {0}", p.http_url);

p.writeSuccess();

string jsonstr = "{\"message\":\"ok\",\"nu\":\"367847964498\",\"ischeck\":\"1\",\"com\":\"shunfeng\",\"status\":\"200\",\"condition\":\"F00\",\"state\":\"3\",\"data\":[{\"time\":\"2020-02-18 16:03:48\",\"context\":\"查无结果\",\"ftime\":\"2020-02-18 16:03:48\"}]}";

p.outputStream.WriteLine("这是一个json数据");

p.outputStream.WriteLine(jsonstr);

//p.outputStream.WriteLine("

test server

");

//p.outputStream.WriteLine("Current Time: " + DateTime.Now.ToString());

//p.outputStream.WriteLine("url : {0}", p.http_url);

//

//p.outputStream.WriteLine("

");

//p.outputStream.WriteLine("");

//p.outputStream.WriteLine("");

//p.outputStream.WriteLine("

");

}

public override void handlePOSTRequest(HttpProcessor p, StreamReader inputData)

{

Console.WriteLine("POST request: {0}", p.http_url);

string data = inputData.ReadToEnd();

p.outputStream.WriteLine("

test server

");

p.outputStream.WriteLine("return

");

p.outputStream.WriteLine("postbody:

{0}
", data);

}

}

class Program

{

static void Main(string[] args)

{

HttpServer httpServer;

if (args.GetLength(0) > 0)

{

httpServer = new MyHttpServer(Convert.ToInt16(args[0]));

}

else

{

httpServer = new MyHttpServer(8888);

}

Thread thread = new Thread(new ThreadStart(httpServer.listen));

thread.Start();

}

}

}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值