草庐IT

c# - 具有线程性能的 tcp 监听器

coder 2023-09-19 原文

我正在构建 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% 的内存 可以做什么来优化该代码

谢谢

最佳答案

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

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

关于c# - 具有线程性能的 tcp 监听器,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/40504627/

有关c# - 具有线程性能的 tcp 监听器的更多相关文章

  1. ruby - 具有身份验证的私有(private) Ruby Gem 服务器 - 2

    我想安装一个带有一些身份验证的私有(private)Rubygem服务器。我希望能够使用公共(public)Ubuntu服务器托管内部gem。我读到了http://docs.rubygems.org/read/chapter/18.但是那个没有身份验证-如我所见。然后我读到了https://github.com/cwninja/geminabox.但是当我使用基本身份验证(他们在他们的Wiki中有)时,它会提示从我的服务器获取源。所以。如何制作带有身份验证的私有(private)Rubygem服务器?这是不可能的吗?谢谢。编辑:Geminabox问题。我尝试“捆绑”以安装新的gem..

  2. ruby - RuntimeError(自动加载常量 Apps 多线程时检测到循环依赖 - 2

    我收到这个错误:RuntimeError(自动加载常量Apps时检测到循环依赖当我使用多线程时。下面是我的代码。为什么会这样?我尝试多线程的原因是因为我正在编写一个HTML抓取应用程序。对Nokogiri::HTML(open())的调用是一个同步阻塞调用,需要1秒才能返回,我有100,000多个页面要访问,所以我试图运行多个线程来解决这个问题。有更好的方法吗?classToolsController0)app.website=array.join(',')putsapp.websiteelseapp.website="NONE"endapp.saveapps=Apps.order("

  3. c# - 如何在 ruby​​ 中调用 C# dll? - 2

    如何在ruby​​中调用C#dll? 最佳答案 我能想到几种可能性:为您的DLL编写(或找人编写)一个COM包装器,如果它还没有,则使用Ruby的WIN32OLE库来调用它;看看RubyCLR,其中一位作者是JohnLam,他继续在Microsoft从事IronRuby方面的工作。(估计不会再维护了,可能不支持.Net2.0以上的版本);正如其他地方已经提到的,看看使用IronRuby,如果这是您的技术选择。有一个主题是here.请注意,最后一篇文章实际上来自JohnLam(看起来像是2009年3月),他似乎很自在地断言RubyCL

  4. C# 到 Ruby sha1 base64 编码 - 2

    我正在尝试在Ruby中复制Convert.ToBase64String()行为。这是我的C#代码:varsha1=newSHA1CryptoServiceProvider();varpasswordBytes=Encoding.UTF8.GetBytes("password");varpasswordHash=sha1.ComputeHash(passwordBytes);returnConvert.ToBase64String(passwordHash);//returns"W6ph5Mm5Pz8GgiULbPgzG37mj9g="当我在Ruby中尝试同样的事情时,我得到了相同sha

  5. ruby-on-rails - Rails 3.1 中具有相同形式的多个模型? - 2

    我正在使用Rails3.1并在一个论坛上工作。我有一个名为Topic的模型,每个模型都有许多Post。当用户创建新主题时,他们也应该创建第一个Post。但是,我不确定如何以相同的形式执行此操作。这是我的代码:classTopic:destroyaccepts_nested_attributes_for:postsvalidates_presence_of:titleendclassPost...但这似乎不起作用。有什么想法吗?谢谢! 最佳答案 @Pablo的回答似乎有你需要的一切。但更具体地说...首先改变你View中的这一行对此#

  6. 基于C#实现简易绘图工具【100010177】 - 2

    C#实现简易绘图工具一.引言实验目的:通过制作窗体应用程序(C#画图软件),熟悉基本的窗体设计过程以及控件设计,事件处理等,熟悉使用C#的winform窗体进行绘图的基本步骤,对于面向对象编程有更加深刻的体会.Tutorial任务设计一个具有基本功能的画图软件**·包括简单的新建文件,保存,重新绘图等功能**·实现一些基本图形的绘制,包括铅笔和基本形状等,学习橡皮工具的创建**·设计一个合理舒适的UI界面**注明:你可能需要先了解一些关于winform窗体应用程序绘图的基本知识,以及关于GDI+类和结构的知识二.实验环境Windows系统下的visualstudio2017C#窗体应用程序三.

  7. ruby - 如何让Ruby捕获线程中的语法错误 - 2

    我正在尝试使用ruby​​编写一个双线程客户端,一个线程从套接字读取数据并将其打印出来,另一个线程读取本地数据并将其发送到远程服务器。我发现的问题是Ruby似乎无法捕获线程内的错误,这是一个示例:#!/usr/bin/rubyThread.new{loop{$stdout.puts"hi"abc.putsefsleep1}}loop{sleep1}显然,如果我在线程外键入abc.putsef,代码将永远不会运行,因为Ruby将报告“undefinedvariableabc”。但是,如果它在一个线程内,则没有错误报告。我的问题是,如何让Ruby捕获这样的错误?或者至少,报告线程中的错误?

  8. ruby - 如何在 ruby​​ 中运行后台线程? - 2

    我是ruby​​的新手,我认为重新构建一个我用C#编写的简单聊天程序是个好主意。我正在使用Ruby2.0.0MRI(Matz的Ruby实现)。问题是我想在服务器运行时为简单的服务器命令提供I/O。这是从示例中获取的服务器。我添加了使用gets()获取输入的命令方法。我希望此方法在后台作为线程运行,但该线程正在阻塞另一个线程。require'socket'#Getsocketsfromstdlibserver=TCPServer.open(2000)#Sockettolistenonport2000defcommandsx=1whilex==1exitProgram=gets.chomp

  9. ruby - 具有两个参数的 block - 2

    我从用户Hirolau那里找到了这段代码:defsum_to_n?(a,n)a.combination(2).find{|x,y|x+y==n}enda=[1,2,3,4,5]sum_to_n?(a,9)#=>[4,5]sum_to_n?(a,11)#=>nil我如何知道何时可以将两个参数发送到预定义方法(如find)?我不清楚,因为有时它不起作用。这是重新定义的东西吗? 最佳答案 如果您查看Enumerable#find的文档,您会发现它只接受一个block参数。您可以将它发送两次的原因是因为Ruby可以方便地让您根据它的“并行赋

  10. ruby-on-rails - 在 RSpec 中,如何以任意顺序期望具有不同参数的多条消息? - 2

    RSpec似乎按顺序匹配方法接收的消息。我不确定如何使以下代码工作:allow(a).toreceive(:f)expect(a).toreceive(:f).with(2)a.f(1)a.f(2)a.f(3)我问的原因是a.f的一些调用是由我的代码的上层控制的,所以我不能对这些方法调用添加期望。 最佳答案 RSpecspy是测试这种情况的一种方式。要监视一个方法,用allowstub,除了方法名称之外没有任何约束,调用该方法,然后expect确切的方法调用。例如:allow(a).toreceive(:f)a.f(2)a.f(1)

随机推荐