2016-11-09 35 views
1

我建立GPS應用程序,其中GPS設備通過TCP端口 發送位置我建立一個服務來閱讀這些信息,並保存到數據庫TCP聽者隨着線程性能

static void Main(string[] args) 
    { 
     TcpListener serverSocket = new TcpListener(8889); 
     TcpClient clientSocket = default(TcpClient); 
     int counter = 0; 

     serverSocket.Start(); 
     // Console.WriteLine(" >> " + "Server Started"); 

     counter = 0; 
     while (true) 
     { 
      counter += 1; 
      clientSocket = serverSocket.AcceptTcpClient(); 
      // Console.WriteLine(" >> " + "Client No:" + Convert.ToString(counter) + " started!"); 
      handleClinet client = new handleClinet(); 
      client.startClient(clientSocket, Convert.ToString(counter)); 
     } 

     clientSocket.Close(); 
     serverSocket.Stop(); 
     // Console.WriteLine(" >> " + "exit"); 
     Console.ReadLine(); 
    } 
} 

//Class to handle each client request separatly 
public class handleClinet 
{ 

    static void WriteLog(string message, EventLogEntryType type) 
    { 

     using (EventLog eventLog = new EventLog("Application")) 
     { 
      eventLog.Source = "Application"; 
      eventLog.WriteEntry(message, type, 101, 1); 
     } 
    } 
    static int InsideDangerArea(double Lat, double Lng) 
    { 

     string point = "POINT(" + Lng + " " + Lat + ")"; 

     string ConnStr = "Data Source =.; Initial Catalog = GPS_Tracking;Integrated Security = True"; 
     using (SqlConnection conn = new SqlConnection(ConnStr)) 
     { 
      conn.Open(); 
      using (SqlCommand comm = new SqlCommand("Select id from T_Geofncies", conn)) 
      { 
       DataTable dt = new DataTable(); 
       dt.Load(comm.ExecuteReader()); 

       foreach (DataRow dr in dt.Rows) 
       { 
        string Query = " DECLARE @g geometry; DECLARE @h geometry; SET @g = (select(points) from T_Geofncies where id=" + dr["id"].ToString() + ");"; 
        Query += " SET @h = geometry::STGeomFromText('" + point + "', 4326); SELECT @g.STContains(@h);"; 
        comm.CommandText = Query; 
        int Val = Convert.ToInt32(comm.ExecuteScalar()); 
        if (Val == 1) 
        { 
         conn.Close(); 
         conn.Dispose(); 
         return Convert.ToInt32(dr["id"]); 
        } 

       } 
      } 
      conn.Close(); 
      conn.Dispose(); 
     } 
     return 0; 
    } 

    static int OutsideSafeArea(double Lat, double Lng) 
    { 

     string point = "POINT(" + Lng + " " + Lat + ")"; 

     string ConnStr = "Data Source =.; Initial Catalog = GPS_Tracking;Integrated Security = True"; 
     using (SqlConnection conn = new SqlConnection(ConnStr)) 
     { 
      conn.Open(); 
      using (SqlCommand comm = new SqlCommand("Select id from T_SafeArea", conn)) 
      { 
       DataTable dt = new DataTable(); 
       dt.Load(comm.ExecuteReader()); 

       foreach (DataRow dr in dt.Rows) 
       { 
        string Query = " DECLARE @g geometry; DECLARE @h geometry; SET @g = (select(points) from T_SafeArea where id=" + dr["id"].ToString() + ");"; 
        Query += " SET @h = geometry::STGeomFromText('" + point + "', 4326); SELECT @g.STContains(@h);"; 
        comm.CommandText = Query; 
        int Val = Convert.ToInt32(comm.ExecuteScalar()); 
        if (Val == 1) 
        { 
         conn.Close(); 
         conn.Dispose(); 
         return Convert.ToInt32(dr["id"]); 
        } 

       } 
      } 
      conn.Close(); 
      conn.Dispose(); 
     } 
     return 0; 
    } 
    static SqlGeography GetGeographyFromText(String pText) 
    { 
     SqlString ss = new SqlString(pText); 
     SqlChars sc = new SqlChars(ss); 
     try 
     { 
      return SqlGeography.STPointFromText(sc, 4326); 
     } 
     catch (Exception ex) 
     { 
      throw ex; 
     } 
    } 
    TcpClient clientSocket; 
    string clNo; 
    public void startClient(TcpClient inClientSocket, string clineNo) 
    { 
     this.clientSocket = inClientSocket; 
     this.clNo = clineNo; 
     Thread ctThread = new Thread(doChat); 
     ctThread.Start(); 
    } 
    private void doChat() 
    { 
     string ConnStr = "Data Source =.; Initial Catalog = GPS_Tracking;Integrated Security = True"; 

     int requestCount = 0; 
     // byte[] bytesFrom = new byte[10025]; 
     string dataFromClient = null; 
     Byte[] sendBytes = null; 
     string serverResponse = null; 
     string rCount = null; 
     requestCount = 0; 

     while ((true)) 
     { 
      try 
      { 
       requestCount = requestCount + 1; 
       NetworkStream networkStream = clientSocket.GetStream(); 
       int i; 
       int size = (int)clientSocket.ReceiveBufferSize; 
       // Loop to receive all the data sent by the client. 
       Byte[] bytes = new Byte[size]; 
       string data = ""; 
       string IMEI; 
       while ((i = networkStream.Read(bytes, 0, bytes.Length)) != 0) 
       { 

        try 
        { 
         data = System.Text.Encoding.ASCII.GetString(bytes, 0, i); 

         string[] tokens = data.Split(new[] { "GPRMC" }, StringSplitOptions.None); 
         var longest = Regex.Matches(data, @"\d+").Cast<Match>().OrderByDescending(m => m.Length).First(); 


         IMEI = longest.ToString(); 
         if (IMEI.Length > 15) 
          IMEI = IMEI.Substring(1); 



         foreach (string item in tokens) 
         { 
          try 
          { 
           string[] Values = item.Split(',');         // Console.WriteLine("Received: {0}", data); 
           string time = Values[1]; 
           // Console.WriteLine("Time= " + time); 
           string lat; 
           string lng; 
           string speed; 
           string date; 

           lat = Values[3]; 
           lng = Values[5]; 
           speed = Values[7]; 
           date = Values[9]; 

           string NewDString = date.Substring(2, 2) + date.Substring(0, 2) + date.Substring(4, 2); 

           // Console.WriteLine("IMEI= " + IMEI); 

           // Alternate choice: If the string has been input by an end user, you might 
           // want to format it according to the current culture: 
           // IFormatProvider culture = System.Threading.Thread.CurrentThread.CurrentCulture; 
           string myDate = (NewDString + time).Insert(2, "-").Insert(5, "-").Insert(8, " ").Insert(11, ":").Insert(14, ":"); 


           double latDeg = Convert.ToDouble(Convert.ToDouble(lat).ToString().Substring(0, 2)); 
           double latMin = Convert.ToDouble(Convert.ToDouble(lat).ToString().Substring(2)); 

           double lngDeg = Convert.ToDouble(Convert.ToDouble(lng).ToString().Substring(0, 2)); 
           double lngmin = Convert.ToDouble(Convert.ToDouble(lng).ToString().Substring(2)); 

           double latmap = latDeg + (latMin/60); 
           // OldLat= 
           double lngmap = lngDeg + (lngmin/60); 
           //if ((Math.Round(latmap, 3) != Math.Round(OldLat, 3) && Math.Round(lngmap, 3) != Math.Round(OldLng, 3)) || idleRecord > 30) 
           //{ 
           using (SqlConnection conn = new SqlConnection(ConnStr)) 
           { 
            conn.Open(); 
            using (SqlCommand cmd = conn.CreateCommand()) 
            { 
             // DbCommand also implements IDisposable 

             // create command with placeholders 
             cmd.CommandText = 
              "INSERT INTO T_Tracking " + 
              "([IMEI], [TrackTime], [Longitude], [Lattitude], [speed],[MapPoint],[SafeAreaID],[GeoFenceID]) " + 
              "VALUES(@IMEI, @TrackTime, @Longitude, @Lattitude, @speed,@MapPoint,@SafeAreaID,@GeoFenceID)"; 


             SqlParameter p_IMEI = new SqlParameter("@IMEI", IMEI); 
             cmd.Parameters.Add(p_IMEI); 

             SqlParameter p_TrackTime = new SqlParameter("@TrackTime", myDate); 
             cmd.Parameters.Add(p_TrackTime); 

             SqlParameter p_Longitude = new SqlParameter("@Longitude", lngmap); 
             cmd.Parameters.Add(p_Longitude); 

             SqlParameter p_Lattitude = new SqlParameter("@Lattitude", latmap); 
             cmd.Parameters.Add(p_Lattitude); 

             SqlParameter p_Speed = new SqlParameter("@speed", speed); 
             cmd.Parameters.Add(p_Speed); 
             SqlParameter p_Points = new SqlParameter("@MapPoint", System.Data.SqlDbType.Udt); 
             p_Points.UdtTypeName = "geometry"; 
             p_Points.Value = GetGeographyFromText("Point(" + lngmap + " " + latmap + ") "); 
             cmd.Parameters.Add(p_Points); 
             SqlParameter P_Safe = new SqlParameter("@SafeAreaID", OutsideSafeArea(latmap, lngmap)); 
             cmd.Parameters.Add(P_Safe); 
             SqlParameter P_GeoFence = new SqlParameter("@GeoFenceID", InsideDangerArea(latmap, lngmap)); 
             cmd.Parameters.Add(P_GeoFence); 
             // execute 
             cmd.ExecuteNonQuery(); 

            } 
            //} 
            //else 
            // idleRecord = idleRecord + 1; 

           } 
          } 
          catch (Exception exp) { WriteLog(exp.ToString(), EventLogEntryType.Error); } 
         } 


        } 
        catch { } 
       } 

      } 
      catch (Exception ex) 
      { 
       // Console.WriteLine(" >> " + ex.ToString()); 
      } 
     } 
    } 
} 

}

它工作正常,但問題是性能 它是測試系統5個設備 它消耗服務器上的95%的內存僅需10分鐘便可 可以做些什麼來優化代碼

謝謝

+1

即將面臨的一個問題是半包/雙包。因爲,TCP是一個流,並且您假設您每次接收呼叫都讀取一條完整的消息。 –

+0

我現在的問題是不是我可以忽略不完整或損壞我的問題是發送/接收的性能 –

+0

這就是爲什麼它是一個評論,而不是一個答案。 ;-) –

回答

0

這裏的問題是,每次有新的套接字連接進來時,都會創建一個即使關閉底層連接也不會結束的新線程。線程過程在while (true)循環中被一個catch-all異常處理程序包裝,所以當套接字連接關閉並拋出一個SocketException時,會被捕獲並忽略,並且線程過程再次循環。這也會阻止套接字對象的垃圾收集,並且可能也是CPU密集型的。同樣,main函數末尾的清理代碼也不會被調用,因爲那裏的while(true)實際上只會關閉最後一個客戶機連接。

您的線程過程應該正確處理異常並在底層套接字連接關閉時停止循環。

+0

謝謝你能指出究竟應該做什麼 –

+0

我補充說它得到的錯誤消息無法訪問處置對象system.net.sockets.socket然後我添加networkStream.close和clientsocket.close但仍然CPU 92 %20Min後掛我做了什麼,我補充說的是正確的,還有一些其他事情需要做,如果它使用異步服務器套接字?等待回答謝謝https://msdn.microsoft.com/en-us/library/fx6588te.aspx –