主頁 > .NET開發 > 怎樣關閉一個處于阻塞狀態的tcp接收執行緒

怎樣關閉一個處于阻塞狀態的tcp接收執行緒

2020-09-15 08:26:17 .NET開發

如題,阻塞了  不能內部break

uj5u.com熱心網友回復:

增加接收資料超時處理邏輯即可。

uj5u.com熱心網友回復:

參考 1 樓 exception92 的回復:
增加接收資料超時處理邏輯即可。


具體代碼如何實作 請問

uj5u.com熱心網友回復:

參考 1 樓 exception92 的回復:
增加接收資料超時處理邏輯即可。
阻塞接收無法判斷超時啊

uj5u.com熱心網友回復:

俺們不知道你想表達什么。

對,異步阻塞的。有資料來了就讀,沒資料來就自己阻塞。并沒有任何毛病。同時他到底要怎么個break

難道是

where(ture)
{
      異步讀
     
   ///你想在這里break,他卡在上面了?
}

我們說,沒啥問題沒資料自然就卡在上面,如果有資料自然到下面。如果你想強行斷開,把tcpclient.close了,他就自然而然的例外,然后你處理例外就是

uj5u.com熱心網友回復:

 TcpClient xx = new TcpClient();

            while (xx.Connected)
            {
                if (xx.Available > 0)
                {
                    try
                    {
                        await xx.GetStream().ReadAsync( cancellationToken:); //這里其實也有一個帶canceltoken的多載,對,除了tcpclient.close 讓他自己例外,也可以用canceltoken控制是否繼續下去
                    }
                    catch (Exception e)
                    {
                        Console.WriteLine(e);
                        throw;
                    }

                }
            }

uj5u.com熱心網友回復:

參考 4 樓 wanghui0380 的回復:
俺們不知道你想表達什么。

對,異步阻塞的。有資料來了就讀,沒資料來就自己阻塞。并沒有任何毛病。同時他到底要怎么個break

難道是

where(ture)
{
      異步讀
     
   ///你想在這里break,他卡在上面了?
}

我們說,沒啥問題沒資料自然就卡在上面,如果有資料自然到下面。如果你想強行斷開,把tcpclient.close了,他就自然而然的例外,然后你處理例外就是
對啊  就這個意思啊   所以是反問啊

uj5u.com熱心網友回復:

阻塞了不是挺好嗎,不占CPU,一個執行緒用來接收就夠了,不用弄好幾個執行緒都去接收。

uj5u.com熱心網友回復:

參考 7 樓 palhotel 的回復:
阻塞了不是挺好嗎,不占CPU,一個執行緒用來接收就夠了,不用弄好幾個執行緒都去接收。


很多無效的連接過來了,又不發資料, 時間長了 資源會耗盡的

要有一個關斷無效連接的機制

uj5u.com熱心網友回復:

無效連接,簡單處理

既然你說是“很多無效的連接過來了”,說明你是服務器端。那很簡單的

不管你是用所謂的IOCP,還是用其他的手段,開監聽。acceptconnect確認連接以后就可以使用system..runtime.cache 下一個快取依賴(相對過期時間控制)

每次接收資料結束,訪問一下cache

cache失效觸發移除事件,在移除事件里把tcpclient.close掉就好了(即使用那個IOCP的,其實也一樣,你close掉,那個堵塞的自動例外,然后自動例外觸發,歸還入池)

uj5u.com熱心網友回復:

弄個服務器比較復雜,我這里簡單用tcpclient搞個demo,自己看把
  System.Runtime.Caching.MemoryCache cache = new MemoryCache("tcpclientCache");
        private async void button1_Click(object sender, EventArgs e)
        {
            TcpClient tcpClient = new TcpClient();
            await tcpClient.ConnectAsync(IPAddress.Parse("192.168.4.100"), 6800);
            CacheItemPolicy policy = new CacheItemPolicy();
            policy.SlidingExpiration = TimeSpan.FromMinutes(1);

            policy.RemovedCallback = p =>
            {
                MessageBox.Show("快取過期,我準備移除了");
                var temp = (TcpClient)p.CacheItem.Value;
                temp.Client.Shutdown(SocketShutdown.Both);
                temp.Client.Close();
            };
            cache.Add("t1", tcpClient, policy);

            Task.Factory.StartNew(async () =>
            {
                byte[] buffer =new byte[1024];

                while (tcpClient.Connected)
                {
                    if (tcpClient.Available > 0)
                    {
                        try
                        {
                            var i = await tcpClient.Client.ReceiveAsync(new ArraySegment<byte>(buffer), SocketFlags.None);
                            var obj = cache.Get("t1");//此處訪問一下,更新一下快取依賴時間,當然有可能null,我簡單演示就不處理了
                            var b = 0;
                        }
                        catch (Exception exception)
                        {
                            MessageBox.Show("例外了,此處應該處理,tcpclient斷線處理,不管是對方斷的,還是你自己斷的");
                        }
                    }

                }
                   //此處回圈斷了,tcpclient確定沒連了,該處理的處理
            });

        }

uj5u.com熱心網友回復:

上面那個也解釋了,很多人糾結的心跳指令。其實你看到了,我們其實并不是說一定要收到心跳才認為他活著,心跳的目的,只是保證我可以不斷收到資料,去重繪過期時間。

uj5u.com熱心網友回復:

參考 11 樓 wanghui0380 的回復:
上面那個也解釋了,很多人糾結的心跳指令。其實你看到了,我們其實并不是說一定要收到心跳才認為他活著,心跳的目的,只是保證我可以不斷收到資料,去重繪過期時間。

心跳不僅僅是活著, 里面可以帶協議,獲取那些需要定時上傳的引數,同時剔除無效的連接

uj5u.com熱心網友回復:

貼一下你的代碼,我們只在這里猜了。

uj5u.com熱心網友回復:

參考 13 樓 palhotel 的回復:
貼一下你的代碼,我們只在這里猜了。



TCp server  ,等待設備連接,統計流量和丟包率,[] 里面的數字是包序號,0-99, 如果不連續 , 則判定丟包

代碼:


using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Forms;


using System.Net.Sockets;
using System.Threading;
using System.Net;
using System.Data.SqlClient;



namespace tcpServer
{
    public partial class Form_TcpServer : Form
    {
        public Form_TcpServer()
        {
            InitializeComponent();

            txtPort.Text = "9444";

            //初始化允許拖拽
            InitDragInFile();

            //初始化DataGridView
            InitDataGridView();

            timer1.Interval = 1000;
            timer1.Start();


            listBox1.Visible = false;
        }

        /// <summary>
        /// 監聽套接字
        /// </summary>
        private Socket socketWatch = null;

        //監聽執行緒句柄
        private Thread threadWatch = null;
        //通信執行緒套接字串列
        List<Socket> listSocket = new List<Socket>();
        //通信執行緒執行緒串列
        List<Thread> listThread = new List<Thread>();
        //IPEndPoint、幀率串列
        private Dictionary<string, double> dictSps = new Dictionary<string, double>();
        //IPEndpoint、丟包數串列
        private Dictionary<string,int> dictLosePkts = new Dictionary<string,int>();

        /// <summary>
        /// 初始化監聽套接字
        /// </summary>
        private void InitWatchSocket()
        {
            try
            {
                //構建socket物件
                socketWatch = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
                //構建ipaddress 物件
                IPAddress ipaddress = IPAddress.Any;
                //構建endPoint物件
                IPEndPoint endPoint = new IPEndPoint(ipaddress, Convert.ToInt32(txtPort.Text));
                //埠系結
                socketWatch.Bind(endPoint);
                //監聽
                socketWatch.Listen(20);
                //創建監聽執行緒
                threadWatch = new Thread(watchThreadProc);
                //將表單執行緒設定為與后臺同步
                threadWatch.IsBackground = true;
                //開啟執行緒
                threadWatch.Start(socketWatch);

                btnListen.Text = "監聽中..";

                MessageBox.Show("開啟監聽成功");
            }
            catch(Exception er)
            {
                MessageBox.Show(er.Message);
            }
           

        }
        /// <summary>
        /// 等待客戶端的連接,并且創建與之通信的socket
        /// </summary>
        private void watchThreadProc(object obj)
        {
            Socket sckWatch = obj as Socket;

            while (true)
            {
                //阻塞 
                Socket sock = sckWatch.Accept();//socketWatch.Accept()

                //委托
                ParameterizedThreadStart pts = new ParameterizedThreadStart(ThreadRecvProc);

                Thread thr = new Thread(pts);

                thr.IsBackground = true;

                thr.Start(sock);

                listSocket.Add(sock);
                listThread.Add(thr);

            }
        }
        /// <summary>
        /// tcp 接收資料決議
        /// </summary>
        /// <param name="temp"></param>
        /// <param name="state"></param>
        /// <param name="No"></param>
        /// <returns></returns>
        private bool Parse(byte temp, ref byte state, ref int No)
        {
            bool ret = false;

            switch(state)
            {
                case 0:
                    if (temp == '[') state = 1;
                    else state = 0;
                    break;

                case 1://shi
                    state = 2;
                    No = temp - '0';
                    break;

                case 2://ge
                    state = 3;
                    No = No * 10 + temp - '0';
                    break;

                case 3:
                    if (temp == ']')
                    {
                        ret = true;
                    }
                    else
                    {
                        No = 0;
                    }
                    state = 0;
                    break;

                default:
                    state = 0;
                    break;
            }

            return ret;
        }

        /// <summary>
        /// tcp 接收執行緒
        /// </summary>
        /// <param name="obj"></param>
        private void ThreadRecvProc(object obj)
        {
            Socket s = obj as Socket;

            byte[] buffer = new byte[1500];

            long startTime = DateTime.Now.ToUniversalTime().Ticks;

            double sps = 0;

            UInt32 sumRecv = 0;

            int ret = 0;

            string remote = s.RemoteEndPoint.ToString();

            byte state = 0;

            int No = 0, lastNo =-1;

            int losePkts = 0;


            while (true)
            {

                try
                {
                    ret = s.Receive(buffer, 1500, SocketFlags.None);


                    for( int i = 0; i< ret; i++)
                    {
                        if( Parse(buffer[i], ref state, ref No) == true )
                        {
                            if( lastNo  == -1)
                            {
                                lastNo = No;
                                continue;
                            }
                            else
                            {
                                if(No == 0)
                                {
                                    if (lastNo != 99) losePkts++;
                                }
                                else
                                {
                                    if (No - lastNo != 1) losePkts++;
                                }

                            }
                            lastNo = No;

                            dictLosePkts[remote] = losePkts;
                        }
                    }
                }
                catch(Exception er)
                {
                    //MessageBox.Show(er.Message);
                    //錯誤提示一般是: 遠程主機關閉了一個遠程連接
                    Console.WriteLine( er.Message );
                    break;
                }
                
                long endTime = DateTime.Now.ToUniversalTime().Ticks;

                sumRecv += (UInt32)ret;

                if (endTime - startTime >= 10000 * 1000)//1s
                {
                    startTime = DateTime.Now.ToUniversalTime().Ticks;

                    sps = sumRecv * 8.0 / 1024 / 1024;

                    sumRecv = 0;

                    dictSps[remote] = sps;

          
                    //Console.WriteLine("sps is {0}", sps);
                }

                //Console.WriteLine("ret is {0}", ret);
            }
        }

        private delegate void delegate_refresh(double sps);

        /// <summary>
        /// 重繪listBox控制元件
        /// </summary>
        /// <param name="sps"></param>
        private void refreshListBox(double sps)
        {
            if (listBox1.InvokeRequired)
            {
                delegate_refresh d = new delegate_refresh(refreshListBox);

                this.Invoke(d, new object[] { sps });
            }
            else
            {
                listBox1.Items.Add(sps.ToString());
            }
        }


        private void btnListen_Click(object sender, EventArgs e)
        {
            InitWatchSocket();
        }

        /// <summary>
        /// 初始化允許拖拽
        /// </summary>
        private void InitDragInFile()
        {
            this.AllowDrop = true;
        }

        /// <summary>
        /// 列印輸出拖入檔案的路徑
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void Form1_DragEnter(object sender, DragEventArgs e)
        {
            if (e.Data.GetDataPresent(DataFormats.FileDrop))
            {
                string[] content = (string[])e.Data.GetData(DataFormats.FileDrop);

                foreach (var s in content)
                {
                    Console.WriteLine("xx:" + s);
                }
            }
        }


        /// <summary>
        /// 初始化DataGridView控制元件
        /// </summary>
        private void InitDataGridView()
        {
            //設定列數為3列
            dataGridView1.ColumnCount = 3;


            string headers = "地址 速率(Mbps) 丟幀數(個)";
            string[] header = headers.Split(' ');

            //設定列標題和列寬度
            for (int i = 0; i < dataGridView1.ColumnCount; i++)
            {
                dataGridView1.Columns[i].HeaderText = header[i];
                dataGridView1.Columns[i].Width = 150;
            }
            //設定最后一列為自動填充
            dataGridView1.Columns[dataGridView1.ColumnCount - 1].AutoSizeMode = DataGridViewAutoSizeColumnMode.Fill;

            //選擇模式為整行選中
            dataGridView1.SelectionMode = DataGridViewSelectionMode.FullRowSelect;


            //添加第一行
            //DataGridViewRow row = new DataGridViewRow();
            //row.CreateCells(dataGridView1);
            //for (int i = 0; i < 3; i++)
            //{
            //    row.Cells[i].Value = i.ToString();
            //}
            ////添加DataGridViewRow
            //dataGridView1.Rows.Add(row);
        }

        //定義委托型別
        delegate void delegate_refreshDgv(Dictionary<string, double> dic, Dictionary<string, int> dic2);
        private void refreshDataGridView(Dictionary<string, double> dic, Dictionary<string, int> dic2)
        {
            //在執行緒中呼叫
            if(this.InvokeRequired)
            {
                delegate_refreshDgv d = new delegate_refreshDgv(refreshDataGridView);
                this.Invoke(d, new object[] { dic, dic2 });
            }
            else
            {
                dataGridView1.Rows.Clear();

                try
                {
                    foreach (var d in dic)
                    

uj5u.com熱心網友回復:

你貼得代碼不是一樣得, ThreadRecvProc(object obj)
這個obj就是一個Socket么,那還有啥說得,自己把sokect close掉,就會自動進入你后面寫得那個catch里面

 s.Shutdown(SocketShutdown.Both);
 s.Close();

這樣就行了,想觸發他,可以用上面得cache,如果不想用cache,用

    while (s.Connected)
            {
                CancellationTokenSource cts=new CancellationTokenSource(TimeSpan.FromMinutes(1));
                cts.Token.Register(() =>
                {
                    s.Shutdown(SocketShutdown.Both);
                    s.Close();
                });

                ret = s.Receive(buffer, 1500, SocketFlags.None);
            }

uj5u.com熱心網友回復:

   Task<bool> aTask = Task<bool>.Factory.StartNew(() =>
            {


                for (int i = 0; i < 3; i++)
                {
                    CancellationTokenSource cts = new CancellationTokenSource(TimeSpan.FromSeconds(1));
                    CancellationToken token = cts.Token;
                    token.Register(() =>
                    {
                        if (cts != null)
                        {
                            Trace.WriteLine("執行緒a,超時取消");
                        }
                    });

                    Task.Delay(TimeSpan.FromSeconds(3)).Wait();

                    cts = null;
                }

                return true;
            });

            Task<bool> bTask = Task<bool>.Factory.StartNew(() =>
            {
                for (int i = 0; i < 3; i++)
                {
                    CancellationTokenSource cts = new CancellationTokenSource(TimeSpan.FromSeconds(3));
                    CancellationToken token = cts.Token;
                    token.Register(() =>
                    {
                        if (cts != null)
                        {
                            Trace.WriteLine("執行緒b,超時取消");
                        }
                    });

                    Task.Delay(TimeSpan.FromSeconds(1)).Wait();

                    cts = null;
                }

                return true;
            });


其實超時處理有很多手段,我們只是展示一些常用得手段。那啥信號量,waitone這類我不打算寫了,一次給太多消化不良

ps:你是時候可以看看Task,async/wait 這類東西了,在往后面還不打算碰這些玩意得話,不說看nuget上得代碼,就是他介紹給得簡單演示都沒辦法看了

uj5u.com熱心網友回復:

參考 16 樓 wanghui0380 的回復:
   Task<bool> aTask = Task<bool>.Factory.StartNew(() =>
            {


                for (int i = 0; i < 3; i++)
                {
                    CancellationTokenSource cts = new CancellationTokenSource(TimeSpan.FromSeconds(1));
                    CancellationToken token = cts.Token;
                    token.Register(() =>
                    {
                        if (cts != null)
                        {
                            Trace.WriteLine("執行緒a,超時取消");
                        }
                    });

                    Task.Delay(TimeSpan.FromSeconds(3)).Wait();

                    cts = null;
                }

                return true;
            });

            Task<bool> bTask = Task<bool>.Factory.StartNew(() =>
            {
                for (int i = 0; i < 3; i++)
                {
                    CancellationTokenSource cts = new CancellationTokenSource(TimeSpan.FromSeconds(3));
                    CancellationToken token = cts.Token;
                    token.Register(() =>
                    {
                        if (cts != null)
                        {
                            Trace.WriteLine("執行緒b,超時取消");
                        }
                    });

                    Task.Delay(TimeSpan.FromSeconds(1)).Wait();

                    cts = null;
                }

                return true;
            });


其實超時處理有很多手段,我們只是展示一些常用得手段。那啥信號量,waitone這類我不打算寫了,一次給太多消化不良

ps:你是時候可以看看Task,async/wait 這類東西了,在往后面還不打算碰這些玩意得話,不說看nuget上得代碼,就是他介紹給得簡單演示都沒辦法看了

  

絕對的大師

那個高級編程里面介紹 async/wait  這些的章節直接被我跳過去了。

uj5u.com熱心網友回復:

同步tcp,如果因為recv阻塞等待,把socket關閉了,就可以不阻塞,退出回圈 了。
使用異步通訊

uj5u.com熱心網友回復:

肯定是單拿一個執行緒來做的吧,放進執行緒池,得到future,另起執行緒檢測

uj5u.com熱心網友回復:

設定socket超時時間即可,如果超時沒有資料接收就回傳了

uj5u.com熱心網友回復:

可以用cancellationTokenSource.Cancel()取消任務,但是如果不監聽cancellationToken.IsCancellationRequested屬性,或者不呼叫ThrowIfCancellationRequested方法任務一直執行下去

uj5u.com熱心網友回復:

阻塞  也有退出條件,比如 超時   斷開  等,   再soketerror 有阻塞中斷的愿因

uj5u.com熱心網友回復:

學習分享,高手啊都是。

uj5u.com熱心網友回復:

牛皮

uj5u.com熱心網友回復:

我知道 TerminateThread 函式

uj5u.com熱心網友回復:

牛逼厲害厲害厲害

uj5u.com熱心網友回復:

厲害。。。。。。

uj5u.com熱心網友回復:

學習分享,學習分享,

uj5u.com熱心網友回復:

設定timeout時間應該可以吧

uj5u.com熱心網友回復:

兄弟,你代碼肯定有問題。不管你的接受邏輯是在一個單獨執行緒還是在當前執行緒,你都不應該讓接受邏輯阻塞。應該及時的讓出cpu讓其他代碼干活兒,這樣你的代碼肯定效率會更高

uj5u.com熱心網友回復:

學習分享,代碼有問題

uj5u.com熱心網友回復:

我也不太懂這個

uj5u.com熱心網友回復:

不是很明白。 

uj5u.com熱心網友回復:

增加接受資料鏈

uj5u.com熱心網友回復:

好吧,我也不會寫,咋辦呢?

uj5u.com熱心網友回復:

為什么阻塞呢?應用層協議沒設計好?是否出現丟包和黏包的現象?

uj5u.com熱心網友回復:

參考 21 樓 MYsce 的回復:
可以用cancellationTokenSource.Cancel()取消任務,但是如果不監聽cancellationToken.IsCancellationRequested屬性,或者不呼叫ThrowIfCancellationRequested方法任務一直執行下去



  /// <summary>
        /// 點擊掃描,發送掃描指令
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private async void btnScan_Click(object sender, EventArgs e)
        {
            #region await 異步編程方式實作
            //btnScan.Enabled = false;
            //var task = await Task_SendScanCmd();
            //Console.WriteLine("{0}", task);
            //btnScan.Enabled = true;
            //InitComboBleAddr();
            #endregion

            #region CancellationTokenSource 方式取消任務

            //創建cancellationTokenSource 物件
            m_ctsScanCancel = new CancellationTokenSource();

            //創建task物件
            Task task = new Task(() =>
            {
                m_ble.sendBleStartScanCmd();

                Thread.Sleep(6000);

                try
                {
                    m_ctsScanCancel.Token.ThrowIfCancellationRequested();
                    Console.WriteLine("掃描執行緒被執行");
                }
                catch (Exception ex)
                {
                    Console.WriteLine("掃描執行緒被取消" + ex.Message);
                }

            }, m_ctsScanCancel.Token);

            task.Start();

            #endregion

        }


感覺cancellationTokenSource 只是在task執行完 cancel, 不是中途cancel掉的   , 能在task  Sleep的時候停掉么   

uj5u.com熱心網友回復:

參考 15 樓 wanghui0380 的回復:
你貼得代碼不是一樣得, ThreadRecvProc(object obj)
這個obj就是一個Socket么,那還有啥說得,自己把sokect close掉,就會自動進入你后面寫得那個catch里面

 s.Shutdown(SocketShutdown.Both);
 s.Close();

這樣就行了,想觸發他,可以用上面得cache,如果不想用cache,用

    while (s.Connected)
            {
                CancellationTokenSource cts=new CancellationTokenSource(TimeSpan.FromMinutes(1));
                cts.Token.Register(() =>
                {
                    s.Shutdown(SocketShutdown.Both);
                    s.Close();
                });

                ret = s.Receive(buffer, 1500, SocketFlags.None);
            }


這里不是簡單的超時就斷開連接,而是一個連接建立后,1分鐘服務器沒有收到資料集而且是合法的資料,就認為這個連接是無效的,超時的,然后服務器就主動斷掉這個連接,避免不必要的資源開銷, 我想實作的是這種效果。

uj5u.com熱心網友回復:

哎,不管你想要什么,不管你想怎么實作。都是一樣的代碼,觸發條件不同。

你后面新增的需求。類比最簡單的都能聽懂的東西,asp.net 的session(很像把)
自己做個session不難,微軟給你準備好了,相對時間快取依賴。
你收到了你覺著ok的資料,訪問一下他更新他,他過期移除了給你事件,你
 s.Shutdown(SocketShutdown.Both);
 s.Close();
就好

快取依賴代碼自己百度。

手段很多,其實實作都一樣。在介紹另外一樣rx.net

假設我們寫個擴展方法是這樣的

s.我認為一條滿意的資料().timeout(timespan.3分鐘) 
時間到了,你會得到一個例外,表示3分鐘內,你沒收到一條你認為滿意的資料,那么還是shutdown他,close他

紅字部分是rx編程的一部分,我不想展示,已經在這里展示的夠多了。你們愿意接受就接受,不愿意接受我不想強推

uj5u.com熱心網友回復:

現在的polly庫也是一樣的表達

polly
{
做你想做的事情,你想接受資料就接資料,3分鐘沒接到,丟一個timeout例外出來
}
.當有個timeout例外出來,我來掛接處理他
{
s.Shutdown(SocketShutdown.Both);
 s.Close();
}


還是那句話,不要糾結那些東西。你只需要做一件事情。無論我給你展示canceltoken,rx,依賴快取,還是polly
你沒發現都是一樣的,全都是 做你該做的事情,如果沒有等到你要東西,那么扔個例外或者呼叫一個事件,讓外面處理

uj5u.com熱心網友回復:

做你想做的事情

正常來說,你的代碼不就這么寫么

sockect.接收資料()
決議資料
如果成功決議一條
------------------這里都不用動,下面就是才是需要動的東西
如果要依賴快取,那么這里訪問一下快取,讓快取自己更新一下時間,快取過期有過期通知,你在過期通知里關閉他
如果用rx,那么這里用onnext把決議好的資料發出去,在最初acceptconn的時候我們會有一個訂閱,當超時沒收到這個訂閱我們處理他
canceltoken一樣,每次你while接受資料前給個new一個,決議成功了就出去,沒決議到一條超時就觸發了
polly其實一樣,每次準備決議的動作當作你要完成的一次polly


---------------------------
總之我們不搞什么scan掃描這種東西,我們只自然而然的寫代碼,這東西的自然描述不就是。你連上我了,俺們3分鐘沒來電,那就撤么?就這么自然而然的寫,不必繞那個彎



uj5u.com熱心網友回復:

客戶端采用長連接的方式,
server側肯定需要有超時處理的策略來兜底
否則時間長了,server側的資源就耗光了

在client的屬性中增加上一次通信的時戳屬性
采用一定的排序方法,把早未通信的client連接關閉掉

轉載請註明出處,本文鏈接:https://www.uj5u.com/net/44664.html

標籤:C#

上一篇:在后臺實作rsa加密 已知私鑰,要加密的問題

下一篇:如何用VS實作基于關聯規則的推薦系統,系統主題頁面已經實作,就差推薦的功能

標籤雲
其他(157675) Python(38076) JavaScript(25376) Java(17977) C(15215) 區塊鏈(8255) C#(7972) AI(7469) 爪哇(7425) MySQL(7132) html(6777) 基礎類(6313) sql(6102) 熊猫(6058) PHP(5869) 数组(5741) R(5409) Linux(5327) 反应(5209) 腳本語言(PerlPython)(5129) 非技術區(4971) Android(4554) 数据框(4311) css(4259) 节点.js(4032) C語言(3288) json(3245) 列表(3129) 扑(3119) C++語言(3117) 安卓(2998) 打字稿(2995) VBA(2789) Java相關(2746) 疑難問題(2699) 细绳(2522) 單片機工控(2479) iOS(2429) ASP.NET(2402) MongoDB(2323) 麻木的(2285) 正则表达式(2254) 字典(2211) 循环(2198) 迅速(2185) 擅长(2169) 镖(2155) 功能(1967) .NET技术(1958) Web開發(1951) python-3.x(1918) HtmlCss(1915) 弹簧靴(1913) C++(1909) xml(1889) PostgreSQL(1872) .NETCore(1853) 谷歌表格(1846) Unity3D(1843) for循环(1842)

熱門瀏覽
  • WebAPI簡介

    Web體系結構: 有三個核心:資源(resource),URL(統一資源識別符號)和表示 他們的關系是這樣的:一個資源由一個URL進行標識,HTTP客戶端使用URL定位資源,表示是從資源回傳資料,媒體型別是資源回傳的資料格式。 接下來我們說下HTTP. HTTP協議的系統是一種無狀態的方式,使用請求/ ......

    uj5u.com 2020-09-09 22:07:47 more
  • asp.net core 3.1 入口:Program.cs中的Main函式

    本文分析Program.cs 中Main()函式中代碼的運行順序分析asp.net core程式的啟動,重點不是剖析原始碼,而是理清程式開始時執行的順序。到呼叫了哪些實體,哪些法方。asp.net core 3.1 的程式入口在專案Program.cs檔案里,如下。ususing System; us ......

    uj5u.com 2020-09-09 22:07:49 more
  • asp.net網站作為websocket服務端的應用該如何寫

    最近被websocket的一個問題困擾了很久,有一個需求是在web網站中搭建websocket服務。客戶端通過網頁與服務器建立連接,然后服務器根據ip給客戶端網頁發送資訊。 其實,這個需求并不難,只是剛開始對websocket的內容不太了解。上網搜索了一下,有通過asp.net core 實作的、有 ......

    uj5u.com 2020-09-09 22:08:02 more
  • ASP.NET 開源匯入匯出庫Magicodes.IE Docker中使用

    Magicodes.IE在Docker中使用 更新歷史 2019.02.13 【Nuget】版本更新到2.0.2 【匯入】修復單列匯入的Bug,單元測驗“OneColumnImporter_Test”。問題見(https://github.com/dotnetcore/Magicodes.IE/is ......

    uj5u.com 2020-09-09 22:08:05 more
  • 在webform中使用ajax

    如果你用過Asp.net webform, 說明你也算是.NET 開發的老兵了。WEBform應該是2011 2013左右,當時還用visual studio 2005、 visual studio 2008。后來基本都用的是MVC。 如果是新開發的專案,估計沒人會用webform技術。但是有些舊版 ......

    uj5u.com 2020-09-09 22:08:50 more
  • iis添加asp.net網站,訪問提示:由于擴展配置問題而無法提供您請求的

    今天在iis服務器配置asp.net網站,遇到一個問題,記錄一下: 問題:由于擴展配置問題而無法提供您請求的頁面。如果該頁面是腳本,請添加處理程式。如果應下載檔案,請添加 MIME 映射。 WindowServer2012服務器,添加角色安裝完.netframework和iis之后,運行aspx頁面 ......

    uj5u.com 2020-09-09 22:10:00 more
  • WebAPI-處理架構

    帶著問題去思考,大家好! 問題1:HTTP請求和回傳相應的HTTP回應資訊之間發生了什么? 1:首先是最底層,托管層,位于WebAPI和底層HTTP堆疊之間 2:其次是 訊息處理程式管道層,這里比如日志和快取。OWIN的參考是將訊息處理程式管道的一些功能下移到堆疊下端的OWIN中間件了。 3:控制器處理 ......

    uj5u.com 2020-09-09 22:11:13 more
  • 微信門戶開發框架-使用指導說明書

    微信門戶應用管理系統,采用基于 MVC + Bootstrap + Ajax + Enterprise Library的技術路線,界面層采用Boostrap + Metronic組合的前端框架,資料訪問層支持Oracle、SQLServer、MySQL、PostgreSQL等資料庫。框架以MVC5,... ......

    uj5u.com 2020-09-09 22:15:18 more
  • WebAPI-HTTP編程模型

    帶著問題去思考,大家好!它是什么?它包含什么?它能干什么? 訊息 HTTP編程模型的核心就是訊息抽象,表示為:HttPRequestMessage,HttpResponseMessage.用于客戶端和服務端之間交換請求和回應訊息。 HttpMethod類包含了一組靜態屬性: private stat ......

    uj5u.com 2020-09-09 22:15:23 more
  • 部署WebApi隨筆

    一、跨域 NuGet參考Microsoft.AspNet.WebApi.Cors WebApiConfig.cs中配置: // Web API 配置和服務 config.EnableCors(new EnableCorsAttribute("*", "*", "*")); 二、清除默認回傳XML格式 ......

    uj5u.com 2020-09-09 22:15:48 more
最新发布
  • C#多執行緒學習(二) 如何操縱一個執行緒

    <a href="https://www.cnblogs.com/x-zhi/" target="_blank"><img width="48" height="48" class="pfs" src="https://pic.cnblogs.com/face/2943582/20220801082530.png" alt="" /></...

    uj5u.com 2023-04-19 09:17:20 more
  • C#多執行緒學習(二) 如何操縱一個執行緒

    C#多執行緒學習(二) 如何操縱一個執行緒 執行緒學習第一篇:C#多執行緒學習(一) 多執行緒的相關概念 下面我們就動手來創建一個執行緒,使用Thread類創建執行緒時,只需提供執行緒入口即可。(執行緒入口使程式知道該讓這個執行緒干什么事) 在C#中,執行緒入口是通過ThreadStart代理(delegate)來提供的 ......

    uj5u.com 2023-04-19 09:16:49 more
  • 記一次 .NET某醫療器械清洗系統 卡死分析

    <a href="https://www.cnblogs.com/huangxincheng/" target="_blank"><img width="48" height="48" class="pfs" src="https://pic.cnblogs.com/face/214741/20200614104537.png" alt="" /&g...

    uj5u.com 2023-04-18 08:39:04 more
  • 記一次 .NET某醫療器械清洗系統 卡死分析

    一:背景 1. 講故事 前段時間協助訓練營里的一位朋友分析了一個程式卡死的問題,回過頭來看這個案例比較經典,這篇稍微整理一下供后來者少踩坑吧。 二:WinDbg 分析 1. 為什么會卡死 因為是表單程式,理所當然就是看主執行緒此時正在做什么? 可以用 ~0s ; k 看一下便知。 0:000> k # ......

    uj5u.com 2023-04-18 08:33:10 more
  • SignalR, No Connection with that ID,IIS

    <a href="https://www.cnblogs.com/smartstar/" target="_blank"><img width="48" height="48" class="pfs" src="https://pic.cnblogs.com/face/u36196.jpg" alt="" /></a>...

    uj5u.com 2023-03-30 17:21:52 more
  • 一次對pool的誤用導致的.net頻繁gc的診斷分析

    <a href="https://www.cnblogs.com/dotnet-diagnostic/" target="_blank"><img width="48" height="48" class="pfs" src="https://pic.cnblogs.com/face/3115652/20230225090434.png" alt=""...

    uj5u.com 2023-03-28 10:15:33 more
  • 一次對pool的誤用導致的.net頻繁gc的診斷分析

    <a href="https://www.cnblogs.com/dotnet-diagnostic/" target="_blank"><img width="48" height="48" class="pfs" src="https://pic.cnblogs.com/face/3115652/20230225090434.png" alt=""...

    uj5u.com 2023-03-28 10:13:31 more
  • C#遍歷指定檔案夾中所有檔案的3種方法

    <a href="https://www.cnblogs.com/xbhp/" target="_blank"><img width="48" height="48" class="pfs" src="https://pic.cnblogs.com/face/957602/20230310105611.png" alt="" /></a&...

    uj5u.com 2023-03-27 14:46:55 more
  • C#/VB.NET:如何將PDF轉為PDF/A

    <a href="https://www.cnblogs.com/Carina-baby/" target="_blank"><img width="48" height="48" class="pfs" src="https://pic.cnblogs.com/face/2859233/20220427162558.png" alt="" />...

    uj5u.com 2023-03-27 14:46:35 more
  • 武裝你的WEBAPI-OData聚合查詢

    <a href="https://www.cnblogs.com/podolski/" target="_blank"><img width="48" height="48" class="pfs" src="https://pic.cnblogs.com/face/616093/20140323000327.png" alt="" /><...

    uj5u.com 2023-03-27 14:46:16 more