webProxy Example in C#

45 篇文章 0 订阅
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Net;
using System.Net.Sockets;
using System.IO;
using System.Threading;

namespace webProxyServer
{
    class Program
    {
        private Socket clientSocket;
        private byte[] read = new byte[1024];
        private byte[] buffer = null;
        private Encoding ASCII = Encoding.ASCII;
        private String HTTP_VERSION = "HTTP/1.0";
        private String CRLF = "\r\n";
        private byte[] recvBytes = new byte[4096];

        public void setSocket (Socket socket)
        {
            this.clientSocket = socket;
        }

        public void run()
        {
            String clientMessage = "";
            String sURL = "";
            
            String m = readMessage(read,clientSocket,clientMessage);
            int bytes = m.Length;

            if (bytes != 0)
            {
                int index1 = clientMessage.IndexOf(" ");
                int index2 = clientMessage.IndexOf(" ", index1 + 1);

                if (index1 == -1 || index2 == -1)
                {
                    Console.WriteLine("Error at beginning");
                }
                else
                {
                   Console.WriteLine("Connecting to Site: {0}", clientMessage.Substring(index1 + 1, index2 - index1));
                   Console.WriteLine("Connection from {0}", clientSocket.RemoteEndPoint);

                   String part1 = clientMessage.Substring(index1 + 1, index2 - index1);
                   int index3 = part1.IndexOf("/", index1 + 8);
                   int index4 = part1.IndexOf(" ", index1 + 8);
                   int index5 = index4 - index3;

                    sURL = part1.Substring(index1 + 4, part1.Length - index5 - 8);

                //sURL = m.Trim();
                //sURL = sURL.Replace("\0", "");
                //String ipaddresss = sURL;
                    try
                    {
                        IPHostEntry IPHost = Dns.GetHostEntry(sURL); //Dns.Resolve(sURL);
                        Console.WriteLine("Request resolved: ", IPHost.HostName);
                        String[] aliases = IPHost.Aliases;
                        IPAddress[] address = IPHost.AddressList;
                        //IPAddress address = IPAddress.Parse(ipaddresss);
                        Console.WriteLine(address[0]);
                        //Console.WriteLine(address);
                        //IPEndPoint sEndpoint = new IPEndPoint(address[0], 80);
                        IPEndPoint sEndpoint = new IPEndPoint(address, 80);
                        Socket IPsocket = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
                        IPsocket.Connect(sEndpoint);
                        if (IPsocket.Connected)
                        {
                            Console.WriteLine("Socket connect OK");

                            String GET = clientMessage;
                            Byte[] ByteGet = ASCII.GetBytes(GET);
                            IPsocket.Send(ByteGet, ByteGet.Length, 0);
                            
                            Int32 rBytes = IPsocket.Receive(recvBytes, recvBytes.Length, 0);
                            Console.WriteLine("Recieved {0}", +rBytes);

                            String strRetPage = "";
                            strRetPage = strRetPage + ASCII.GetString(recvBytes, 0, rBytes);
                            while (rBytes > 0)
                            {
                                rBytes = IPsocket.Receive(recvBytes, recvBytes.Length, 0);
                                strRetPage = strRetPage + ASCII.GetString(recvBytes, 0, rBytes);
                            }

                            IPsocket.Shutdown(SocketShutdown.Both);
                            IPsocket.Close();
                            sendMessage(clientSocket, strRetPage);
                        }
                        else
                        {
                            Console.WriteLine("Socket connect Error");
                        }
                    }
                    catch (Exception ex)
                    {
                        Console.WriteLine(ex.ToString());
                    }
                }

            }
            else
            {
                Console.WriteLine("No incoming bytes.");
            }
        }

        private string readMessage(byte[] byteArray, Socket s, String clientMessage)
        {
            int bytes = s.Receive(byteArray, 1024, 0);
            String messageFromClient = Encoding.ASCII.GetString(byteArray);
            return messageFromClient;
            //clientMessage = messageFromClient;

            //return bytes;
        }

        // bool
        private void sendMessage(Socket s, String message)
        {
            this.buffer = new Byte[message.Length + 1];
            int length = ASCII.GetBytes(message, 0, message.Length, buffer, 0);
            s.Send(buffer, length, 0);
        }




        static void Main(string[] args)
        {
            Console.WriteLine("halloworld");
            Console.In.Read();

            int port = 8889;
            IPAddress localAddr = IPAddress.Parse("127.0.0.1");
            TcpListener tcplistener = new TcpListener(localAddr,port);

            Console.WriteLine("Listening on port {0}", port);

            tcplistener.Start();

            while (true)
            {
                Socket socket = tcplistener.AcceptSocket();
                Program webProxy = new Program();

                webProxy.setSocket(socket);
                Thread t = new Thread(new ThreadStart(webProxy.run));

                t.Start();
            }
        }
    }
}


  // example: send request via port 

            TcpClient client = new TcpClient("localhost", port);

            byte[] data = ASCIIEncoding.ASCII.GetBytes("132.230.49.113");

            NetworkStream stream = client.GetStream();

            stream.Write(data, 0, data.Length);

            stream.Close();

Example session

Below is a sample conversation between an HTTP client and an HTTP server running onwww.example.com, port 80.

Client request

 GET /index.html HTTP/1.1
 Host: www.example.com

A client request (consisting in this case of the request line and only one header) is followed by a blank line, so that the request ends with a doublenewline, each in the form of acarriage return followed by aline feed. The "Host" header distinguishes between variousDNS names sharing a single IP address, allowing name-based virtual hosting. While optional in HTTP/1.0, it is mandatory in HTTP/1.1.

Server response

 HTTP/1.1 200 OK
 Date: Mon, 23 May 2005 22:38:34 GMT
 Server: Apache/1.3.3.7 (Unix) (Red-Hat/Linux)
 Last-Modified: Wed, 08 Jan 2003 23:11:55 GMT
 Etag: "3f80f-1b6-3e1cb03b"
 Accept-Ranges: bytes
 Content-Length: 438
 Connection: close
 Content-Type: text/html; charset=UTF-8

A server response is followed by a blank line and text of the requested page. TheETag (entity tag) header is used to determine if a cached version of the requested resource is identical to the current version of the resource on the server.Content-Type specifies theInternet media type of the data conveyed by the http message, whileContent-Length indicates its length in bytes. The HTTP/1.1webserver publishes its ability to respond to requests for certain byte ranges of the document by setting the headerAccept-Ranges: bytes. This is useful, if the client needs to have only certain portions[17] of a resource sent by the server, which is called byte serving. When Connection: close is sent in a header, it means that theweb server will close theTCP connection immediately after the transfer of this response.

Most of the header lines are optional. When Content-Length is missing the length is determined with other ways. Chunked transfer encoding uses a chunk size of 0 to mark the end of the content.Identity encoding withoutContent-Length reads content until the socket is closed.

A Content-Encoding like gzip can be used to reduce the amount of data.



Argumentübertragung

Häufig will der Nutzer einer Website spezielle Informationen senden. Dazu stellt HTTP prinzipiell zwei Möglichkeiten zur Verfügung:

  1. HTTP-GET: Die Daten sind Teil der URL und bleiben deshalb beim Speichern oder der Weitergabe des Links erhalten.
  2. HTTP-POST: Übertragung der Daten mit einer speziell dazu vorgesehenen Anfrageart im HTTP-Body, so dass sie in der URL nicht sichtbar sind.

Die zu übertragenden Daten müssen ggf. URL-kodiert werden, d. h. reservierte Zeichen müssen mit „%<Hex-Wert>“ und Leerzeichen mit „+“ dargestellt werden.

HTTP GET 

Hier werden die Parameter-Wertepaare durch das Zeichen ? in der URL eingeleitet. Oft wird diese Vorgehensweise gewählt, um eine Liste von Parametern zu übertragen, die die Gegenstelle bei der Bearbeitung einer Anfrage berücksichtigen soll. Häufig besteht diese Liste aus Wertepaaren, welche durch das&-Zeichen voneinander getrennt sind. Die jeweiligen Wertepaare sind in der FormParametername=Parameterwert aufgebaut. Seltener wird das Zeichen; zur Trennung von Einträgen der Liste benutzt.[3]

Ein Beispiel: Auf der Startseite von Wikipedia wird in das Eingabefeld der Suche „Katzen“ eingegeben und auf die Schaltfläche „Artikel“ geklickt. Der Browser sendet folgende oder ähnliche Anfrage an den Server:

GET /wiki/Spezial:Search?search=Katzen&go=Artikel HTTP/1.1
Host: de.wikipedia.org
…

Dem Wikipedia-Server werden zwei Wertepaare übergeben:

ArgumentWert
searchKatzen
goArtikel

Diese Wertepaare werden in der Form

Argument1=Wert1&Argument2=Wert2

mit vorangestelltem ? an die geforderte Seite angehängt.

Dadurch „weiß“ der Server, dass der Nutzer den Artikel Katzen betrachten will. Der Server verarbeitet die Anfrage, sendet aber keine Datei, sondern leitet den Browser mit einem Location-Header zur richtigen Seite weiter, etwa mit:

HTTP/1.0 302 Moved Temporarily
Date: Fri, 13 Jan 2006 15:12:44 GMT
Location: http://de.wikipedia.org/wiki/Katzen
…

Der Browser befolgt diese Anweisung und sendet aufgrund der neuen Informationen eine neue Anfrage, etwa:

GET /wiki/Katzen HTTP/1.1
Host: de.wikipedia.org
…

Und der Server antwortet und gibt den Artikel Katzen aus, etwa:

HTTP/1.0 200 OK
Date: Fri, 13 Jan 2006 15:12:48 GMT
Last-Modified: Tue, 10 Jan 2006 11:18:20 GMT
Content-Language: de
Content-Type: text/html; charset=utf-8

Die Katzen (Felidae) sind eine Familie aus der Ordnung der Raubtiere (Carnivora)
innerhalb der Überfamilie der Katzenartigen (Feloidea).
…

Der Datenteil ist meist länger, hier soll nur das Protokoll betrachtet werden.

HTTP POST

Da sich die Daten nicht in der URL befinden, können per POST große Datenmengen, z. B. Bilder, übertragen werden.

Im folgenden Beispiel wird wieder der Artikel Katzen angefordert, doch diesmal verwendet der Browser aufgrund eines modifizierten HTML-Codes (method="POST") eine POST-Anfrage. Die Variablen stehen dabei nicht in der URL, sondern gesondert im Body-Teil, etwa:

POST /wiki/Spezial:Search HTTP/1.1
Host: de.wikipedia.org
Content-Type: application/x-www-form-urlencoded
Content-Length: 24

search=Katzen&go=Artikel

Auch das versteht der Server und antwortet wieder mit beispielsweise folgendem Text:

HTTP/1.0 302 Moved Temporarily
Date: Fri, 13 Jan 2006 15:32:43 GMT
Location: http://de.wikipedia.org/wiki/Katzen
…

HTTP-Statuscodes 

Hauptartikel:HTTP-Statuscode

Jede HTTP-Anfrage wird vom Server mit einem HTTP-Statuscode beantwortet. Er gibt zum Beispiel Informationen darüber, ob die Anfrage erfolgreich bearbeitet wurde, oder teilt dem Client, also etwa dem Browser, im Fehlerfall mit, wo (z. B. Umleitung) bzw. wie (z. B. mit Authentifizierung) er die gewünschten Informationen (wenn möglich) erhalten kann.

1xxInformationen
Die Bearbeitung der Anfrage dauert trotz der Rückmeldung noch an. Eine solche Zwischenantwort ist manchmal notwendig, da viele Clients nach einer bestimmten Zeitspanne (Timeout) automatisch annehmen, dass ein Fehler bei der Übertragung oder Verarbeitung der Anfrage aufgetreten ist, und mit einer Fehlermeldung abbrechen.
2xxErfolgreiche Operation

Die Anfrage wurde bearbeitet und die Antwort wird an den Anfragesteller zurückgesendet.

3xxUmleitung
Um eine erfolgreiche Bearbeitung der Anfrage sicherzustellen, sind weitere Schritte seitens des Clients erforderlich. Das ist zum Beispiel der Fall, wenn eine Webseite vom Betreiber umgestaltet wurde, so dass sich eine gewünschte Datei nun an einem anderen Platz befindet. Mit der Antwort des Servers erfährt der Client im Location-Header, wo sich die Datei jetzt befindet.
4xxClient-Fehler
Bei der Bearbeitung der Anfrage ist ein Fehler aufgetreten, der im Verantwortungsbereich des Clients liegt. Ein 404 tritt beispielsweise ein, wenn ein Dokument angefragt wurde, das auf dem Server nicht existiert. Ein 403 weist den Client darauf hin, dass es ihm nicht erlaubt ist, das jeweilige Dokument abzurufen. Es kann sich zum Beispiel um ein vertrauliches oder nur perHTTPS zugängliches Dokument handeln.
5xxServer-Fehler
Es ist ein Fehler aufgetreten, dessen Ursache beim Server liegt. Zum Beispiel bedeutet 501, dass der Server nicht über die erforderlichen Funktionen (d. h. zum Beispiel Programme oder andere Dateien) verfügt, um die Anfrage zu bearbeiten.

Zusätzlich zum Statuscode enthält der Header der Server-Antwort eine Beschreibung des Fehlers inenglischsprachigem Klartext. Zum Beispiel ist einFehler 404 an folgendem Header zu erkennen:

HTTP/1.1 404 Not Found
…


using System;
using System.IO;
using System.Net;
using System.Net.Sockets;
using System.Text;

class MyTcpListener
{
  public static void Main()
  { 
    TcpListener server=null;   
    try
    {
      // Set the TcpListener on port 13000.
      Int32 port = 13000;
      IPAddress localAddr = IPAddress.Parse("127.0.0.1");
      
      // TcpListener server = new TcpListener(port);
      server = new TcpListener(localAddr, port);

      // Start listening for client requests.
      server.Start();
         
      // Buffer for reading data
      Byte[] bytes = new Byte[256];
      String data = null;

      // Enter the listening loop.
      while(true) 
      {
        Console.Write("Waiting for a connection... ");
        
        // Perform a blocking call to accept requests.
        // You could also user server.AcceptSocket() here.
        TcpClient client = server.AcceptTcpClient();            
        Console.WriteLine("Connected!");

        data = null;

        // Get a stream object for reading and writing
        NetworkStream stream = client.GetStream();

        int i;

        // Loop to receive all the data sent by the client.
        while((i = stream.Read(bytes, 0, bytes.Length))!=0) 
        {   
          // Translate data bytes to a ASCII string.
          data = System.Text.Encoding.ASCII.GetString(bytes, 0, i);
          Console.WriteLine("Received: {0}", data);
       
          // Process the data sent by the client.
          data = data.ToUpper();

          byte[] msg = System.Text.Encoding.ASCII.GetBytes(data);

          // Send back a response.
          stream.Write(msg, 0, msg.Length);
          Console.WriteLine("Sent: {0}", data);            
        }
         
        // Shutdown and end connection
        client.Close();
      }
    }
    catch(SocketException e)
    {
      Console.WriteLine("SocketException: {0}", e);
    }
    finally
    {
       // Stop listening for new clients.
       server.Stop();
    }

      
    Console.WriteLine("\nHit enter to continue...");
    Console.Read();
  }   
}



  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值