2016-05-15 4 views
1

Der Load Balancer akzeptiert eingehende Anforderungen, sendet sie erneut an mehrere Server und gibt die Antworten von den Servern an die wartenden Clients zurück.C# Server Load Balancer funktioniert nur, wenn im VS-Debugger der Haltepunkt gesetzt ist?

// Dispatcher.cs 
using System; 
using System.Collections.Generic; 
using System.Net; 
using System.Net.Sockets; 
using System.Threading; 

namespace LoadBallancer { 
    public class Dispatcher 
    { 
     // set the TcpListener on port 8890 
     int port = 8890; 
     TcpListener server; 
     List<CoreComm> processors = new List<CoreComm>(); 

     static void Main() 
     { 
      var dispatcher = new Dispatcher(); 
      dispatcher.ListenForRequests(); 
     } 

     public Dispatcher() 
     { 
      server = new TcpListener(IPAddress.Any, port); 
     } 

     public void ListenForRequests() 
     { 
      server.Start(); 
      while (true) 
      { 
       try 
       { 
        // Start listening for client requests 
        // Enter the listening loop 

        Console.Write("Waiting for a connection... "); 

        lock(server) 
        { 
         // Perform a blocking call to accept requests. 
         TcpClient client = server.AcceptTcpClient(); 

         Console.WriteLine("Connected."); 

         ThreadPool.QueueUserWorkItem(ThreadProc, client); 
        } 
       } 
       catch (Exception e) 
       { 
        Console.WriteLine("Exception: {0}", e); 
       } 
      } 
     } 
     private static void ThreadProc(object obj) 
     { 
      var processor = new CoreComm((TcpClient)obj); 
      processor.ReSendRequest(null); 
     } 
    } 
} 

// CoreComm.cs

using System; 
using System.Collections.Generic; 
using System.Linq; 
using System.Net.Sockets; 

using System.Configuration; 
using System.Threading; 

namespace LoadBallancer 
{ 
    public class IamServer 
    { 
     public string Url { get; set; } 
     public int  Port { get; set; } 
     public string Type { get; set; } 
    } 

    public class CoreComm 
    { 
     // Buffer for reading data 
     int bufSize = 1024; 
     static List<IamServer> servers = new List<IamServer>(); 

     protected TcpClient acceptorSocket; 
     NetworkStream acceptorStream; 

     protected TcpClient clientSocket; 

     protected List<KeyValuePair<int, byte[]>> requestPackets = new List<KeyValuePair<int, byte[]>>(); 

     static CoreComm() 
     { 
      // reading config for servers' parameters 
     } 

     public CoreComm(TcpClient socket) 
     { 
      acceptorSocket = socket; 
      // Get a stream object for reading and writing 
      acceptorStream = acceptorSocket.GetStream(); 
     } 

     private void ReadFromAcceptorStream() 
     { 
      // Loop to receive all the data sent by the client. 
      while (acceptorStream.DataAvailable) 
      { 
       byte[] requestBuffer = new byte[bufSize]; 
       int i = acceptorStream.Read(requestBuffer, 0, requestBuffer.Length); 
       requestPackets.Add(new KeyValuePair<int, byte[]>(i, requestBuffer)); 
      } 
     } 

     public void ReSendRequest(Object threadContext) 
     { 
      ReadFromAcceptorStream(); 

      var servers = GetDestinationServers(null); 

      if (servers.Count == 0) 
       acceptorStream.Write(ErrMessage, 0, ErrMessage.Length); 
      else 
       // for debug only send the first in the list 
       SendRequestToServer(servers[0]); 

      // Shutdown and end connection 
      acceptorSocket.Close(); 
     } 

     public void SendRequestToServer(IamServer server) 
     { 
      clientSocket = new TcpClient(); 
      clientSocket.Connect(server.Url, server.Port); 
      NetworkStream clientStream = clientSocket.GetStream(); 

      foreach (var packet in requestPackets) 
       clientStream.Write(packet.Value, 0, packet.Key); 

      var requestBuffer = new byte[bufSize]; 

      while (clientStream.DataAvailable) 
      { 
       int i = clientStream.Read(requestBuffer, 0, requestBuffer.Length); 
       acceptorStream.Write(requestBuffer, 0, i); 
      } 

      clientSocket.Close(); 
     } 

     // Mock up of the real load balancing algorithm 
     static int lastServerAnswered = 0; 

     public List<IamServer> GetDestinationServers(string requestData) 
     { 
      // processing to determine the query destinations 
      lock(servers) 
      { 
       // patch 
       int currentServerNum = lastServerAnswered; 
       lastServerAnswered ++ ; 
       if (lastServerAnswered > servers.Count - 1) 
        lastServerAnswered = 0; 

       return new List<IamServer> { servers[currentServerNum] }; 
      } 
     } 

    } 
} 

So funktioniert es richtig, wenn ich in den Code brechen-Punkt gesetzt und nicht anders arbeiten. Irgendwelche Ideen?

Antwort

0

Das Problem in dem Code befunden wurde:

while (clientStream.DataAvailable) 
{ 
     int i = clientStream.Read(requestBuffer, 0, requestBuffer.Length); 
     acceptorStream.Write(requestBuffer, 0, i); 
} 

Eigentlich geschah es, daß, wenn es für einige Pakete clientStream.DataAvailable falsch war sogar noch Daten wurden noch empfangen werden. Die Lösung basiert auf der Anwendungsebene-Protokoll, für die der Load Balancer entwickelt worden war, dass die Anzahl der Gesamtzahl der Bytes in den ersten 4 Bytes des Stroms sendet, die sent.The Code wird wie folgt:

var responseBuffer = new byte[bufSize]; 

int numTotalBytesStreamed = clientStream.Read(responseBuffer, 0, responseBuffer.Length); 
int numBytesToStream = GetNumBytesInTheStream(responseBuffer); 

acceptorStream.Write(responseBuffer, 0, numTotalBytesStreamed); 

while (numBytesToStream > numTotalBytesStreamed) 
{ 
    while (!clientStream.DataAvailable) 
     Thread.Sleep(1); 

     int numMoreBytesStreamed = clientStream.Read(responseBuffer, 0, responseBuffer.Length); 
     acceptorStream.Write(responseBuffer, 0, numMoreBytesStreamed); 
     numTotalBytesStreamed += numMoreBytesStreamed; 
} 
acceptorStream.Flush(); 
clientSocket.Close(); 

Die Lösung funktioniert und ist extrem stabil für kontinuierliche Lasten von Hunderten von Anfragen pro Sekunde.

Verwandte Themen