0

I have used the following code:

var tuple = Tuple.Create("xxx.xx.xx.xxx", 6102, "109", "Metrix1", 1);
var tuple1 = Tuple.Create("xxx.xx.xx.xxx", 6102, "110", "Metrix2", 1);
var tuple2 = Tuple.Create("xxx.xx.xx.xxx", 6102, "111", "Metrix3", 1);
var tuple3 = Tuple.Create("xxx.xx.xx.xxx", 6103, "106", "Metrix4", 2);

gateways.Add(tuple);
gateways.Add(tuple1);
gateways.Add(tuple2);
gateways.Add(tuple3);

foreach (var gatewayId in gateways)
{
    Task.Factory.StartNew(
        () => GetJobs(
            gatewayId.Item1,
            gatewayId.Item2,
            gatewayId.Item3,
            gatewayId.Item4,
            gatewayId.Item5));
}

This then calls GetJobs which calls CallGateway and if required ProcessMessageNew

private string GetJobs(string Url , int portNumber, string Engineer , string mEngineer , int GatewayId)
{
    ConfigLogger.Instance.LogInfo("info", "Calling Gateway Start: " + DateTime.Now.ToString("HH:mm:ss.ffff") + " for engineer: " + Engineer);
    string gatewayResult = CallGateway(Engineer, Url, portNumber);
    ConfigLogger.Instance.LogInfo("info", "Calling Gateway End: " + DateTime.Now.ToString("HH:mm:ss.ffff") + " for engineer: " + Engineer);
    if (gatewayResult != null)
    {
        ConfigLogger.Instance.LogInfo("info", "Processing Request Message: " + DateTime.Now.ToString("HH:mm:ss.ffff") + " for engineer: " + Engineer);
        ProcessMessageNew(gatewayResult, Engineer, Url, portNumber , MEngineer ,PGatewayId);
    }
    return gatewayResult;
}

CallGateway:

public string CallGateway(string gatewayUrl, int portNumber , string engineer)
{
     string result = null;
     int streamBufferSize = 1000;

     IPHostEntry ipHostInfo = Dns.Resolve(gatewayUrl.ToString());
     IPAddress ipAddress = ipHostInfo.AddressList[0];
     IPEndPoint remoteEP = new IPEndPoint(ipAddress, portNumber);

     // Create a TCP/IP  socket.
     Socket clientSocket = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
     clientSocket.Connect(ipAddress, portNumber);

     // Set these on app param
     clientSocket.ReceiveTimeout = 300000;
     clientSocket.SendTimeout = 60000;
     // build message string to send to gateway
     string message = BuildMessageGetJobsFromGateway(engineer, SendTypeIn);

     // Create a NetworkStream that owns clientSocket and 
     // then create a BufferedStream on top of the NetworkStream. 
     // Both streams are disposed when execution exits the 
     // using statement. 
     using (var netStream = new NetworkStream(clientSocket, true),
            var bufStream = new BufferedStream(netStream, streamBufferSize))
     {
          // Check whether the underlying stream supports seeking.
          Console.WriteLine("NetworkStream {0} seeking.\n", bufStream.CanSeek ? "supports" : "does not support");

          //variable used to only close once
          bool doClose = true;

          // Send and receive data. 
          if (bufStream.CanWrite)
          {
              try
              {
                  SendData(netStream, bufStream, SendTypeIn, message);
              }
              catch (Exception exSend)
              {
                  Console.WriteLine(exSend.Message.ToString());
              }
           }
           if (bufStream.CanRead)
           {
                try
                {
                     result = ReceiveData(netStream, bufStream, clientSocket);
                }
                catch (Exception exRecieve)
                {
                    //
                }
                finally
                {
                    Console.WriteLine("Closing Stream");
                    doClose = false;
                    bufStream.Close();
                    clientSocket.Close();
                }
            }

            // When bufStream is closed, netStream is in turn 
            // closed, which in turn shuts down the connection 
            // and closes clientSocket.
            Console.WriteLine("\nShutting down the connection.");

            // only close if no exception is raised
            if (doClose)
            {
                bufStream.Close();
                clientSocket.Close();
            }
        }
        return result;
    }
}

However, I get this in the log file 4 calls to the call gateway method and only one return for engineer 106, the call to gateway creates a Socket Client which then receive data but it is only happening for one out of the 4 calls :

[MobileGateway.exe] - [Info] - [25/09/2015 16:47:19] - Calling Gateway Start: 16:47:19.6574 for engineer: 109
[MobileGateway.exe] - [Info] - [25/09/2015 16:47:19] - Processing Call Mobile Gateway: 16:47:19.6624
[MobileGateway.exe] - [Info] - [25/09/2015 16:47:20] - Calling Gateway Start: 16:47:20.6685 for engineer: 110
[MobileGateway.exe] - [Info] - [25/09/2015 16:47:20] - Processing Call Mobile Gateway: 16:47:20.6875
[MobileGateway.exe] - [Info] - [25/09/2015 16:47:21] - Calling Gateway Start: 16:47:21.6696 for engineer: 111
[MobileGateway.exe] - [Info] - [25/09/2015 16:47:21] - Processing Call Mobile Gateway: 16:47:21.6716
[MobileGateway.exe] - [Info] - [25/09/2015 16:47:22] - Calling Gateway Start: 16:47:22.6686 for engineer: 106
[MobileGateway.exe] - [Info] - [25/09/2015 16:47:22] - Processing Call Mobile Gateway: 16:47:22.6706
[MobileGateway.exe] - [Info] - [25/09/2015 16:47:23] - Processing Call Mobile Ended: 16:47:23.0476
[MobileGateway.exe] - [Info] - [25/09/2015 16:47:23] - Calling Gateway End: 16:47:23.0486 for engineer: 106
[MobileGateway.exe] - [Info] - [25/09/2015 16:47:23] - Processing Request Message: 16:47:23.0486 for engineer: 106
[MobileGateway.exe] - [Info] - [25/09/2015 16:47:23] - Message Recieved From Gateway: 16:47:23.0496

The calls should be processed in Parallel or Asyncronously as there is a requirement to call this method simultaneously over 1000 times and they are long running processes so I need to process multiple at a time.

Any ideas why I am getting 1 response instead of 4 ?

abatishchev
  • 98,240
  • 88
  • 296
  • 433
  • Without knowing what `CallGateway` does, it's very hard to tell... – Jon Skeet Sep 25 '15 at 16:48
  • Okay, well I'd start by adding some logging in there... (Also, please put a bit more care into the code that you post - the indentation is all over the place, and you've got whole commented out sections that do nothing - so are just noise, basically.) Ideally, come up with a *short* but complete example demonstrating what's going on. – Jon Skeet Sep 25 '15 at 17:40
  • Research more on `Task.WaitAll(tasks)` and `Task.WhenAll(tasks)` – abatishchev Sep 25 '15 at 18:00
  • After launching all these tasks what does your EXE do? Does it wait for you to stop it or does it just exit? You may be better off using a `Parallel.ForEach` than launching the tasks yourself. – Ian Mercer Sep 25 '15 at 18:11
  • What version of C# (visual studio version) are you using to compile? The behavior of `foreach` and lambda's changed in C#5 (VS 2013) and newer. If you are using a older version you may be passing the same variable in 4 times due to how variable capture works. – Scott Chamberlain Sep 25 '15 at 19:00
  • Thanks @JonSkeet for your input, I will clean up my code as an edit. – user3262640 Sep 25 '15 at 19:18
  • @abatishchev I will research the mentioned items. – user3262640 Sep 25 '15 at 19:22
  • @Ian Mercer I will find out what they are doing and feedback. – user3262640 Sep 25 '15 at 19:22
  • @Scott Chamberlain using VS2012 C# 4 – user3262640 Sep 25 '15 at 19:22
  • possible duplicate of [Access to Modified Closure (2)](http://stackoverflow.com/questions/304258/access-to-modified-closure-2), You are running in to the closure issue. Read the other question for details, in summary you need to do `var tmp = gatewayId;` inside the `foreach` loop then do `...GetJobs(tmp.Item1, tmp.Item2, ...` inside the lambada. – Scott Chamberlain Sep 25 '15 at 20:54

1 Answers1

0

Since you have xxxed the addresses in your code, I can't say assuredly but it is probably happening because you have the same port number 6102 for the previous three gateways. So you are closing and opening stream for same address three times in parallel and that is throwing exceptions only to be caught silently later.

Further, you can improve readability and maintainability of your code by passing the gateway objects in single piece like following:

foreach (var gatewayId in gateways) 
{
    Task.Factory.StartNew(() => GetJobs(gatewayId)); 
}

and modify your GetJobs method too as:

private string GetJobs(Gateway gateway)
{
    ConfigLogger.Instance.LogInfo("info", "Calling Gateway Start: " + DateTime.Now.ToString("HH:mm:ss.ffff") + " for engineer: " + gateway.Engineer);
    string gatewayResult = CallGateway(gateway);
    ConfigLogger.Instance.LogInfo("info", "Calling Gateway End: " + DateTime.Now.ToString("HH:mm:ss.ffff") + " for engineer: " + gateway.Engineer);
    if (gatewayResult != null)
    {
        ConfigLogger.Instance.LogInfo("info", "Processing Request Message: " + DateTime.Now.ToString("HH:mm:ss.ffff") + " for engineer: " + gateway.Engineer);
        ProcessMessageNew(gatewayResult, gateway);
    }
    return gatewayResult;
}

Also, going down further, change your ProcessMessageNew and CallGateway too, to match with the new definition in the code above.

displayName
  • 13,888
  • 8
  • 60
  • 75
  • I think thats is correct what is happening. So all Socket calls to the same IP and Port should be done in one connection ? – user3262640 Sep 25 '15 at 19:27
  • @user3262640: Probably just providing different port number for each `CallGateway` should work for you. See that the new port numbers don't clash with any other application on your machine. – displayName Sep 25 '15 at 19:29
  • I can't provide a different port number as I need to make 3 calls to the same IP and portNumber with different variables. The IP and port number is a server I am making calls to, my machine is the client. – user3262640 Sep 25 '15 at 19:34
  • @user3262640: In that case, is your server up and running? – displayName Sep 25 '15 at 19:35
  • Yes it is up and running – user3262640 Sep 25 '15 at 19:42
  • @user3262640: Well, my guess is probably wrong then. Start with keeping only one gateway with info about your server and debugging your CallGateway(). – displayName Sep 25 '15 at 19:48
  • CallGateway was fine until I added the foreach and Task.Factory.StartNew(() so calling it once is fine it is when you call it several times simultaneously that it responds once. – user3262640 Sep 25 '15 at 19:56
  • @user3262640: Does it work fine when you call it providing only `Tuple.Create("xxx.xx.xx.xxx", 6102, "109", "Metrix1", 1);`. If it does, we can be sure that it's not this particular server based connections that are having the problem.. – displayName Sep 25 '15 at 19:59
  • I can confirm that it works when just having a single Tuple – user3262640 Sep 25 '15 at 20:10
  • @user3262640: Is this - http://stackoverflow.com/questions/3474344/can-i-open-multiple-connections-to-a-http-server - the reason for failure? – displayName Sep 25 '15 at 20:16
  • @user3262640: Please try it also once with foreach, providing only `tuple` and `tuple3` values in your code.. – displayName Sep 25 '15 at 20:29
  • that also works so I am thinking like has already been mentioned an issue in CallGateway just need to find it so I will tidy up the code and try and find the issue and keep you and everyone posted. – user3262640 Sep 25 '15 at 20:39
  • @user3262640: The problem is with opening sockets improperly to the same address. For one: server is refusing multiple connections from same machine. But that's just a guess. In very high likeliness, it has to do with sockets... – displayName Sep 25 '15 at 20:41
  • @displayName http://stackoverflow.com/questions/304258/access-to-modified-closure-2 is the reason his program is not working. He is using VS2012 and is connecting to the same site 4 times due to variable closure. – Scott Chamberlain Sep 25 '15 at 20:57
  • @ScottChamberlain: If that is the case indeed then why is he able to connect with two different servers using the same code? The problem is arising when he is trying to connect with exactly same server. (Refer the last comment I've addressed to him and OP's reply to that.) – displayName Sep 25 '15 at 21:05
  • Yes, and the question I linked to explains what is causing him to connect to `tuple3` 4 times. The reason it likely worked when he tried only 2 is if he stepped through using the debugger it may have let the thread start in time and capture the old value. – Scott Chamberlain Sep 25 '15 at 21:11
  • @ScottChamberlain: OP is not connecting to tuple3 multiple times. When passed tuple and tuple3, the code works fine. The problem is that tuple, tuple1 and tuple2 have the same address and port. This is why (I think) any combination of tuple3 and one of tuple, tuple1 and tuple2 will work because it'll not open multiple connections to the server mentioned in tuple. – displayName Sep 25 '15 at 21:14
  • Thanks everyone, the issue has now been resolved. The method ReceiveData in CallGateway for some engineers returned an unexpected string so it was never returning any data. I have now resolved this issue. – user3262640 Sep 26 '15 at 08:13