6 Replies Latest reply on Jan 20, 2018 12:12 AM by ChewCheeLim

    PI WEB API Call erred out : Only one usage of each socket address (protocol/network address/port) is normally permitted  XX.XX.XX.XX:443

    ChewCheeLim

      I received this error message from PI WEB API call when I am trying to retrieve historical data with many tight calls in a loop.

       

      System.AggregateException: One or more errors occurred. ---> System.Net.Http.HttpRequestException: An error occurred while sending the request. ---> System.Net.WebException: Unable to connect to the remote server ---> System.Net.Sockets.SocketException: Only one usage of each socket address (protocol/network address/port) is normally permitted xxxxxxxxx 443 

       

       

      Did some googling.. it says that "exhausting the ~ x number of ports available limit". and there are options to fix this by monkey around with registry settings.  (see below url)

      We are not comfortable in changing the registry settings.. and tot to ask if anyone'd encountered this issue ? Any ideas on how to fix it? Any advice is much appreciated.

      https://blogs.msdn.microsoft.com/dgorti/2005/09/18/only-one-usage-of-each-socket-address-protocolnetwork-addressport-is-…

       

      thanks!

        • Re: PI WEB API Call erred out : Only one usage of each socket address (protocol/network address/port) is normally permitted  XX.XX.XX.XX:443
          vkaufmann

          I don't see any record of this error in our database. Can you provide the bit of code that is making the call that causes this error? What version of Web API? Are you using the Websockets feature of the Web API?

           

          --Vince

          1 of 1 people found this helpful
            • Re: PI WEB API Call erred out : Only one usage of each socket address (protocol/network address/port) is normally permitted  XX.XX.XX.XX:443
              ChewCheeLim

              Thanks Vincent for ur reply. Ur comment confirmed my speculation that something is going on our end. Our job is running in Azure.. hence I found this.. fixed the incorrect settings in Azure.. and re-testing my long running job now. so far so good..

               

                • Re: PI WEB API Call erred out : Only one usage of each socket address (protocol/network address/port) is normally permitted  XX.XX.XX.XX:443
                  gregor

                  Hello Chew Chee,

                   

                  I once ran into the exact same issue when working on a PI Web API Client application which was firing queries frequently. The cause and options to address the problem are very well explained here. Because the issue is more related to System.Net rather than a PI Web API issue, I didn't log a Tech Support case.

                   

                  Decreasing the TcpTimedWaitDelay turned out to be a lame duck, at least I didn't recognize any improvement while increasing MaxUserPort really improved the situation. I was careful though to not set it to its maximum.

                   

                  The error details you posted, indicate you are using System.Net.Http.HttpClient and I assume you are creating an instance with every query you execute. The better option to address the issue of Windows running out of ports is using a single global HttpClient object. You may wonder if this will allow you parallel query execution. Yes, it does. This morning, I have created a test application which I initially planned to share here but it has quickly grown large and hence I am hesitating to post it. Please stay tuned for a simple example illustrating how you could use a single HttpClient instance.

                    • Re: PI WEB API Call erred out : Only one usage of each socket address (protocol/network address/port) is normally permitted  XX.XX.XX.XX:443
                      ChewCheeLim

                      Thanks Gregor. you are correct! Initial tot was WEB API issue.. then with more looking.. it's the client issue.

                      We were about to mess around with REG settings.. good thing to check with the PI WEB API experts to make sure. Certain enough that, we didn't have to go with REG setting route.

                       

                      Our code indeed is using 1 global instance for all web api calls to simplify the authentication.

                       

                      But the Azure Settings.. messed things up a little. Glad that it's working now.

                       

                      Appreciate all timely feedback from the team! Awesome!

                        • Re: PI WEB API Call erred out : Only one usage of each socket address (protocol/network address/port) is normally permitted  XX.XX.XX.XX:443
                          gregor

                          Hello Chew Chee,

                           

                          What Azure settings are those? Do you like to document what you've changed so others could benefit from your findings?

                           

                          Honestly, I am not that certain anymore that using a global HttpClient object will avoid running out of ports but doing so definitely results into applications with a way smaller memory footprint. Because my example is ready, please allow me to share it here just in case someone finds it useful.

                           

                          using System;
                          using System.Collections.Generic;
                          using System.Threading.Tasks;
                          using System.Net;
                          using System.Net.Http;
                          using System.Threading;
                          namespace GlobalHttpClient
                          {
                              class Program
                              {
                                  static HttpClient globalClient;
                                  static HttpClientHandler globalHandler;
                                  static string username = "webapiuser";
                                  static string passphrase = "!try3.14webapi!";
                                  static string baseUri = "https://devdata.osisoft.com/piwebapi/";
                                  static int queryCount = 0;
                                  static int badCount = 0;
                                  static int excCount = 0;
                                  static string sMessage = string.Empty;
                                  static int pauseMS = 200;
                                  static void Main(string[] args)
                                  {
                                      // Ensure we can capture the complete Console output
                                      Console.BufferHeight = 9000;
                                      Console.ForegroundColor = ConsoleColor.White;
                                      Console.WriteLine("Starting .. ");
                                      // Build the Query List
                                      List<string> queries = new List<string>();
                                      queries.Add(string.Empty);
                                      queries.Add("assetservers");
                                      queries.Add("dataservers");
                                      queries.Add("points/P0W6Wlk0_Utku9vWTvxg45oAAQAAAAUElTUlYxXFNJTlVTT0lE");
                                      queries.Add("streams/P0W6Wlk0_Utku9vWTvxg45oAAQAAAAUElTUlYxXFNJTlVTT0lE/recorded");
                                      // Let's execute the set of queries in parallel 10 times
                                      for (int i=0; i < 10; i++)
                                      {
                                          Parallel.ForEach(queries, (Query) =>
                                          {
                                              ExecQuery(Query);
                                          });
                                          // Report statistics but avoid concurrent access to Console
                                          lock (sMessage)
                                          {
                                              sMessage = "\r\n ----------------- Statistics ----------------- \r\n";
                                              sMessage += string.Format("Active queries:  {0} \r\n", queryCount);
                                              sMessage += string.Format("Bad Status Count: {0} \r\n", badCount);
                                              sMessage += string.Format("Exception count:  {0} \r\n", excCount);
                                              sMessage += "----------------- Statistics ----------------- \r\n";
                                              Console.ForegroundColor = ConsoleColor.Gray;
                                              Console.WriteLine(sMessage);
                                          }
                                          
                                          // Have a little break
                                          Thread.Sleep(pauseMS);
                                      }
                                      
                                      // Let's wait until all queries are completed
                                      while (queryCount > 0)
                                      {
                                          lock (sMessage)
                                          {
                                              sMessage = "\r\n All queries have been fired but not completed. \r\n";
                                              sMessage += string.Format("Current amount of active queries: {0} \r\n", queryCount);
                                              Console.ForegroundColor = ConsoleColor.Gray;
                                              Console.WriteLine(sMessage);
                                          }
                                          Thread.Sleep(pauseMS);
                                      }
                                      Console.ForegroundColor = ConsoleColor.White;
                                      Console.WriteLine();
                                      Console.Write("Done. Press any key to quit .. ");
                                      Console.ReadKey();
                                  }
                                  static async void ExecQuery(string query)
                                  {
                                      // Instantiate the HttpClient and HttpClientHandler if necessary.
                                      if (globalClient == null)
                                      {
                                          if (globalHandler == null)
                                          {
                                              NetworkCredential credentials = new NetworkCredential(username, passphrase);
                                              globalHandler = new HttpClientHandler();
                                              globalHandler.Credentials = credentials;
                                              globalHandler.PreAuthenticate = true;
                                          }
                                          globalClient = new HttpClient(globalHandler);
                                      }
                                      // Build the complete query Uri using the base Uri and the actual query piece
                                      string uri = string.Concat(baseUri, query);
                                      queryCount++;
                                      try
                                      {
                                          // Execute the query
                                          HttpResponseMessage response = await globalClient.GetAsync(uri);
                                          if (response.IsSuccessStatusCode)
                                          {
                                              // Report success but avoid concurrent writes to console
                                              lock (sMessage)
                                              {
                                                  sMessage = string.Format("{0} => Ok", query);
                                                  Console.ForegroundColor = ConsoleColor.Green;
                                                  Console.WriteLine(sMessage);
                                              }
                                          }
                                          else
                                          {
                                              // Report bad status but avoid concurrent writes to console
                                              lock (sMessage)
                                              {
                                                  sMessage = string.Format("{0} ==> {1}", query, (int)response.StatusCode);
                                                  Console.ForegroundColor = ConsoleColor.Yellow;
                                                  Console.WriteLine(sMessage);
                                                  badCount++;
                                              }
                                          }
                                      }
                                      catch (Exception ex)
                                      {
                                          // Report Exception but avoid concurrent writes to console
                                          lock (sMessage)
                                          {
                                              sMessage = string.Format("{0} =E=> {1}", query, ex.InnerException);
                                              Console.ForegroundColor = ConsoleColor.Red;
                                              Console.WriteLine(sMessage);
                                              excCount++;
                                          }
                                      }
                                      finally
                                      {
                                          queryCount--;
                                      }
                                  }
                              }
                          }