如何向TCP服务器发出HTTP请求?

4

我想创建一个TCP服务器,监听443端口,以便接收HTTP请求并进行回复。

目前我正在使用Apache和PHP以正常方式完成此操作,但是否可能在没有Web服务器的情况下完成此操作?

例如,我已经在C# .NET中构建了传统的TCP/IP客户端/服务器应用程序。是否可能使用此实现来处理HTTP请求,而不是使用Web服务器?


1
当然可以。但是,“我是否想要再次自己实现HTTP?”这是另一个问题。 - Jon
这个项目使用TcpListener来处理HTTP请求:http://www.codeproject.com/Articles/1505/Create-your-own-Web-Server-using-C - THX-1138
1
不是这样的。如果您处理HTTP请求,您在技术上拥有一个Web服务器。您是在问“我如何创建自己的Web服务器。”吗? - svick
@svick:这很有道理。我想那就是真正的问题所在。我对这个话题还很新,所以我对所有术语的理解都不足。 - LunchMarble
2个回答

3
在最低级别上,您可以使用HTTP侦听器类来实现。 http://geekswithblogs.net/Nitin/archive/2008/06/22/using-the-http-listener-class.aspx
我曾经写过一个类似的项目,如果您有任何特定的问题,我可以寻找代码。
如果您想提高水平,可以考虑使用Web服务。
这是我的一部分代码……看看您能做些什么:
IPAddress address = IPAddress.Parse("127.0.0.1");
        IPEndPoint port = new IPEndPoint(address, 9999); //port 9999

        TcpListener listener = new TcpListener(port);

        listener.Start();

        Console.WriteLine("--Server loaded--");

        while (true) //loop forever
        {

            Console.WriteLine("Waiting for New Client");
            Socket sock = listener.AcceptSocket();
            byte[] buffer = new byte[32];

            string incomingMessage="";

            //read:
            while (sock.Available > 0)
            {
                int gotBytes = sock.Receive(buffer);
                incomingMessage += Encoding.ASCII.GetString(buffer, 0, gotBytes);

            }

            //debugging:
            //Console.WriteLine(incomingMessage);

            //Now check whether its a GET or a POST

            if (incomingMessage.ToUpper().Contains("POST") && incomingMessage.ToUpper().Contains("/DOSEARCH")) //a search has been asked for
            {

                Console.WriteLine("Query Has Been Received");

                //extracting the post data

                string htmlPostData = incomingMessage.Substring(incomingMessage.IndexOf("songName"));

                string[] parameters = htmlPostData.Split('&');

                string[] inputs = new string[5];

                for (int i=0; i<parameters.Length; i++)
                {
                    inputs[i] = (parameters[i].Split('='))[1];
                    inputs[i] = inputs[i].Replace('+',' ');
                }

...

byte[] outbuffer = Encoding.ASCII.GetBytes(answerPage.ToString());
                sock.Send(outbuffer);

                Console.WriteLine("Results Sent");

                sock.Close();

2
这个项目可以帮助您从头开始创建一个Web服务器:MiniHttpd: an HTTP web server library,使用纯TCP/IP。
但是,与其处理许多不必要的细节,如解析标头、压缩、身份验证、SSL等,我会使用内置的HttpListener类。
这是一个简化(但可工作)的多线程Web服务器。
void CreateWebServer()
{
    HttpListener listener = new HttpListener();
    listener.Prefixes.Add("http://*:8080/");
    listener.Start();

    new Thread(
        () =>
        {
            while (true)
            {
                HttpListenerContext ctx = listener.GetContext();
                ThreadPool.QueueUserWorkItem((_) => ProcessRequest(ctx));
            }
        }
    ).Start();
}

void ProcessRequest(HttpListenerContext ctx)
{
    string responseText = "Hello";
    byte[] buf = Encoding.UTF8.GetBytes(responseText);

    Console.WriteLine(ctx.Request.Url);

    ctx.Response.ContentEncoding = Encoding.UTF8;
    ctx.Response.ContentType = "text/html";
    ctx.Response.ContentLength64 = buf.Length;


    ctx.Response.OutputStream.Write(buf, 0, buf.Length);
    ctx.Response.Close();
}

编辑

我稍微改了一下服务器,使其托管一个RESTful WebServiceMyService)。它返回结果为Json格式。你可以通过http://localhost:8080/?method=Calc&i=5&j=4来调用它(为简单起见,我省略了许多错误检查)。

public class MyService
{
    public Result Calc(int i, int j)
    {
        return new Result() { Addition = i + j, Multiplication = i * j };
    }
}

public class Result
{
    public int Addition { set; get; }
    public int Multiplication { set; get; }
}

void CreateWebServer()
{
    MyService service = new MyService();

    HttpListener listener = new HttpListener();
    listener.Prefixes.Add("http://*:8080/");
    listener.Start();

    new Thread(
        () =>
        {
            while (true)
            {
                HttpListenerContext ctx = listener.GetContext();
                ThreadPool.QueueUserWorkItem((_) => ProcessRequest(ctx,service));
            }

        }
    ).Start();
}

void ProcessRequest(HttpListenerContext ctx,MyService service)
{
    try
    {
        string responseText = Execute(ctx, service);

        byte[] buf = Encoding.UTF8.GetBytes(responseText);

        ctx.Response.ContentEncoding = Encoding.UTF8;
        ctx.Response.ContentType = "application/json";
        ctx.Response.ContentLength64 = buf.Length;


        ctx.Response.OutputStream.Write(buf, 0, buf.Length);
    }
    catch
    {
        ctx.Response.StatusCode = (int) HttpStatusCode.NotFound;
    }

    ctx.Response.Close();
}

string Execute(HttpListenerContext ctx, MyService service)
{
    System.Collections.Specialized.NameValueCollection nv = HttpUtility.ParseQueryString(ctx.Request.Url.Query);

    MethodInfo mi = service.GetType().GetMethod(nv["method"]);
    object[] parameters =  mi.GetParameters()
                             .Select(pi => Convert.ChangeType(nv[pi.Name], pi.ParameterType))
                             .ToArray();

    return JsonConvert.SerializeObject(mi.Invoke(service, parameters));
}

如何使用您的技术从页面请求中获取数据?例如,如果我输入:http://localhost:8080/?name=someName。 - LunchMarble
1
@StormKiernan System.Collections.Specialized.NameValueCollection nv = HttpUtility.ParseQueryString(ctx.Request.Url.Query);@StormKiernan System.Collections.Specialized.NameValueCollection nv = HttpUtility.ParseQueryString(ctx.Request.Url.Query); - L.B
1
@StormKiernan 我更新了答案,使得网络服务器托管了一个Web服务 - L.B

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