Skip to content
  • Categories
  • Recent
  • Tags
  • Popular
  • World
  • Users
  • Groups
Skins
  • Light
  • Cerulean
  • Cosmo
  • Flatly
  • Journal
  • Litera
  • Lumen
  • Lux
  • Materia
  • Minty
  • Morph
  • Pulse
  • Sandstone
  • Simplex
  • Sketchy
  • Spacelab
  • United
  • Yeti
  • Zephyr
  • Dark
  • Cyborg
  • Darkly
  • Quartz
  • Slate
  • Solar
  • Superhero
  • Vapor

  • Default (No Skin)
  • No Skin
Collapse
Code Project
  1. Home
  2. General Programming
  3. C#
  4. A simple proxy server in C#

A simple proxy server in C#

Scheduled Pinned Locked Moved C#
csharpsysadmindebugginghelp
7 Posts 2 Posters 0 Views 1 Watching
  • Oldest to Newest
  • Newest to Oldest
  • Most Votes
Reply
  • Reply as topic
Log in to reply
This topic has been deleted. Only users with topic management privileges can see it.
  • P Offline
    P Offline
    Prahlad Yeri
    wrote on last edited by
    #1

    I have written a simple and minimalist HTTP proxy server that runs on command line. In the Start() method, a TcpListener blocks until it gets a client request and creates a new thread (ThreadHandleClient method) that processes this client, fetches its url and relays data. The trouble is in the relay logic that I want to refine. In the first inner loop, I receive all webserver data and send it to client until zero bytes are left. In second inner loop, I do vice-versa: receive all client data and send to web-server until zero bytes left. However, the code gets blocked in the beginning of second inner-loop at client.receive(). This is what I'm basically doing: Any help will be truly appreciated. Thanks in advance.

    public void Start(IPAddress ip, int port)
    {
    try
    {
    TcpListener listener = new TcpListener(ip, port);
    listener.Start(100);
    while (!stopFlag)
    {
    Socket client = listener.AcceptSocket();
    IPEndPoint rep = (IPEndPoint)client.RemoteEndPoint;
    Thread th = new Thread(ThreadHandleClient);
    th.Start(client);
    }
    listener.Stop();
    }
    catch (Exception ex)
    {
    Debug.Print("START: " + ex.Message);
    }
    }
    public void ThreadHandleClient(object o)
    {
    try
    {
    Socket client = (Socket)o;
    NetworkStream ns = new NetworkStream(client);
    //RECEIVE CLIENT DATA
    byte[] buffer = new byte[2048];
    int rec = 0, sent = 0, transferred = 0, rport = 0;
    string data = "";
    do
    {
    rec = ns.Read(buffer, 0, buffer.Length);
    data += Encoding.ASCII.GetString(buffer, 0, rec);
    } while (rec == buffer.Length);
    //PARSE DESTINATION AND SEND REQUEST
    string line = data.Replace("\r\n", "\n").Split(new string[] { "\n" }, StringSplitOptions.None)[0];
    Uri uri = new Uri(line.Split(new string[] { " " }, StringSplitOptions.None)[1]);
    Debug.Print("CLIENT REQUEST RECEIVED: " + uri.OriginalString);
    if (uri.Scheme == "https")
    {
    rport = 443;
    Debug.Print("HTTPS - 443");
    }
    else
    {
    rport = 80;
    Debug.Print("HTTP - 443");
    }
    IPHostEntry rh = Dns.GetHostEntry(uri.Host);
    Socket webserver = new Socket(rh.AddressList[0].AddressFamily, SocketType.Stream, ProtocolType.IP);
    webserver.Connect(new IPEndPoint(rh.AddressList[0], rport));
    byte[] databytes = Encoding.ASCII.GetBytes(data);
    webserver.Send(databytes, databytes.Length, SocketFlags.None);
    Debug.Print("SENT TO SERVER. WILL NOW RELAY: " + data);
    //STA

    Richard Andrew x64R 1 Reply Last reply
    0
    • P Prahlad Yeri

      I have written a simple and minimalist HTTP proxy server that runs on command line. In the Start() method, a TcpListener blocks until it gets a client request and creates a new thread (ThreadHandleClient method) that processes this client, fetches its url and relays data. The trouble is in the relay logic that I want to refine. In the first inner loop, I receive all webserver data and send it to client until zero bytes are left. In second inner loop, I do vice-versa: receive all client data and send to web-server until zero bytes left. However, the code gets blocked in the beginning of second inner-loop at client.receive(). This is what I'm basically doing: Any help will be truly appreciated. Thanks in advance.

      public void Start(IPAddress ip, int port)
      {
      try
      {
      TcpListener listener = new TcpListener(ip, port);
      listener.Start(100);
      while (!stopFlag)
      {
      Socket client = listener.AcceptSocket();
      IPEndPoint rep = (IPEndPoint)client.RemoteEndPoint;
      Thread th = new Thread(ThreadHandleClient);
      th.Start(client);
      }
      listener.Stop();
      }
      catch (Exception ex)
      {
      Debug.Print("START: " + ex.Message);
      }
      }
      public void ThreadHandleClient(object o)
      {
      try
      {
      Socket client = (Socket)o;
      NetworkStream ns = new NetworkStream(client);
      //RECEIVE CLIENT DATA
      byte[] buffer = new byte[2048];
      int rec = 0, sent = 0, transferred = 0, rport = 0;
      string data = "";
      do
      {
      rec = ns.Read(buffer, 0, buffer.Length);
      data += Encoding.ASCII.GetString(buffer, 0, rec);
      } while (rec == buffer.Length);
      //PARSE DESTINATION AND SEND REQUEST
      string line = data.Replace("\r\n", "\n").Split(new string[] { "\n" }, StringSplitOptions.None)[0];
      Uri uri = new Uri(line.Split(new string[] { " " }, StringSplitOptions.None)[1]);
      Debug.Print("CLIENT REQUEST RECEIVED: " + uri.OriginalString);
      if (uri.Scheme == "https")
      {
      rport = 443;
      Debug.Print("HTTPS - 443");
      }
      else
      {
      rport = 80;
      Debug.Print("HTTP - 443");
      }
      IPHostEntry rh = Dns.GetHostEntry(uri.Host);
      Socket webserver = new Socket(rh.AddressList[0].AddressFamily, SocketType.Stream, ProtocolType.IP);
      webserver.Connect(new IPEndPoint(rh.AddressList[0], rport));
      byte[] databytes = Encoding.ASCII.GetBytes(data);
      webserver.Send(databytes, databytes.Length, SocketFlags.None);
      Debug.Print("SENT TO SERVER. WILL NOW RELAY: " + data);
      //STA

      Richard Andrew x64R Offline
      Richard Andrew x64R Offline
      Richard Andrew x64
      wrote on last edited by
      #2

      If no data has arrived, then Receive is going to block. If this is not what you want, then use BeginReceive.

      The difficult we do right away... ...the impossible takes slightly longer.

      P 1 Reply Last reply
      0
      • Richard Andrew x64R Richard Andrew x64

        If no data has arrived, then Receive is going to block. If this is not what you want, then use BeginReceive.

        The difficult we do right away... ...the impossible takes slightly longer.

        P Offline
        P Offline
        Prahlad Yeri
        wrote on last edited by
        #3

        Thanks Richard. For reasons of simplicity, I don't want to create anync calls and handle everything in thant one thread only. Is there no way to do this using the sync Receive() method ?

        Richard Andrew x64R 1 Reply Last reply
        0
        • P Prahlad Yeri

          Thanks Richard. For reasons of simplicity, I don't want to create anync calls and handle everything in thant one thread only. Is there no way to do this using the sync Receive() method ?

          Richard Andrew x64R Offline
          Richard Andrew x64R Offline
          Richard Andrew x64
          wrote on last edited by
          #4

          If you want, you could call Receive on a background worker thread, but that would entail multiple threads. The bottom line is that Receive will behave synchronously, meaning it will block when there is no data.

          The difficult we do right away... ...the impossible takes slightly longer.

          P 1 Reply Last reply
          0
          • Richard Andrew x64R Richard Andrew x64

            If you want, you could call Receive on a background worker thread, but that would entail multiple threads. The bottom line is that Receive will behave synchronously, meaning it will block when there is no data.

            The difficult we do right away... ...the impossible takes slightly longer.

            P Offline
            P Offline
            Prahlad Yeri
            wrote on last edited by
            #5

            Is there a way to check the data in the socket and call Receive() only when data is available for receiving. This way it should not block, right?

            Richard Andrew x64R 1 Reply Last reply
            0
            • P Prahlad Yeri

              Is there a way to check the data in the socket and call Receive() only when data is available for receiving. This way it should not block, right?

              Richard Andrew x64R Offline
              Richard Andrew x64R Offline
              Richard Andrew x64
              wrote on last edited by
              #6

              I see that Socket has a method called Poll. Take a look: Socket.Poll[^]

              The difficult we do right away... ...the impossible takes slightly longer.

              P 1 Reply Last reply
              0
              • Richard Andrew x64R Richard Andrew x64

                I see that Socket has a method called Poll. Take a look: Socket.Poll[^]

                The difficult we do right away... ...the impossible takes slightly longer.

                P Offline
                P Offline
                Prahlad Yeri
                wrote on last edited by
                #7

                Thanks. The Poll() method really helped. I'm now polling for three seconds before receiving for both client and the server. However, there is still some logical issue with my code:

                                    if (client.Poll(3000 \* 1000, SelectMode.SelectRead))
                                    {
                                        rec = client.Receive(buffer, buffer.Length, SocketFlags.None);
                                        Debug.Print("RECEIVED FROM CLIENT: " + Encoding.ASCII.GetString(buffer, 0, rec));
                
                                        sent = webserver.Send(buffer, rec, SocketFlags.None);
                                        Debug.Print("SENT TO WEBSERVER\[" + sent.ToString() + "\]: " + Encoding.ASCII.GetString(buffer, 0, rec));
                                        transferred += rec;
                                    }
                                    else
                                    {
                                        Debug.Print("No data polled from client");
                                    }
                

                As I said, one logical fault still remains. In the proxy client machine, I'm able to open google.com. Then performed a search that also went fine. However, when I click on a search result, the proxy again gives me google.com!! What am I missing?

                1 Reply Last reply
                0
                Reply
                • Reply as topic
                Log in to reply
                • Oldest to Newest
                • Newest to Oldest
                • Most Votes


                • Login

                • Don't have an account? Register

                • Login or register to search.
                • First post
                  Last post
                0
                • Categories
                • Recent
                • Tags
                • Popular
                • World
                • Users
                • Groups