【问题标题】:tcp listner With Threading performancetcp listener 具有线程性能
【发布时间】:2016-11-09 10:21:27
【问题描述】:

我正在构建 GPS 应用程序,其中 GPS 设备通过 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 个设备的测试系统 它在 10 分钟内消耗服务器上 95% 的内存 可以做些什么来优化该代码

谢谢

【问题讨论】:

  • 您很快将面临的一个问题是,半包/双包。因为,TCP 是一个流,并且您假设您在每个 Receive 调用中读取一个完整的消息。
  • 我现在的问题不是我可以忽略不完整或损坏我的问题是发送/接收的性能
  • 这就是为什么它是评论而不是答案。 ;-)

标签: c# multithreading tcp


【解决方案1】:

这里的问题是,每次新的套接字连接进入时,您都在创建一个新线程,即使底层连接关闭,也永远不会结束。线程过程在while (true) 循环内用一个捕获所有异常处理程序包装,因此当套接字连接关闭并抛出 SocketException 时,它会被捕获并忽略,并且线程过程再次循环。这也将防止套接字对象的垃圾收集,并且可能也是高度 CPU 密集型的。此外,main 末尾的清理代码永远不会因为 while(true) 而被调用,并且确实只会关闭最后一个客户端连接。

当底层套接字连接关闭时,您的线程过程应该正确处理异常并停止循环。

【讨论】:

  • 我添加了 catch 它得到错误消息无法访问已处理的对象 system.net.sockets.socket 然后我添加了 networkStream.close 和 clientsocket.close 但 CPU 92% 在 20 分钟后仍挂起我添加的内容是正确的还是需要做其他事情我应该使用异步服务器套接字(如果它工作的话)?等待答复谢谢msdn.microsoft.com/en-us/library/fx6588te.aspx
猜你喜欢
  • 2023-03-08
  • 1970-01-01
  • 2021-09-16
  • 2012-09-03
  • 1970-01-01
  • 2011-02-16
  • 1970-01-01
  • 1970-01-01
  • 2016-06-17
相关资源
最近更新 更多