1.我现在定义了一个全局的变量,用来存储当前在线的客户端
        /// <summary>
        /// 当前所有在线客户端
        /// </summary>
        internal IDictionary<string, MySocketAsyncEventArgs> ClientList;2.现在有个定时器定时去发送数据给这些客户端
        /// <summary>
        /// 定时轮询
        /// </summary>
        /// <param name="myObject"></param>
        /// <param name="myEventArgs"></param>
        internal void Timer_Elapsed(Object myObject, System.Timers.ElapsedEventArgs myEventArgs)
        {
           
            string[] keys = readWritePool.OnlineUID;
            for (int i = 0; i < keys.Length; i++)
            {
                if (!string.IsNullOrEmpty(keys[i])&&readWritePool.ClientList.ContainsKey(keys[i]))
                {
                    MySocketAsyncEventArgs e = readWritePool.ClientList[keys[i]];
                    if (e.IsAlive)
                    {
                        Byte[] sendBuffer = Encoding.Default.GetBytes("Hello World!");
                        Socket s = e.UserToken as Socket;
                        SendData(s, sendBuffer);
                    }
                }
            }
        }3.另外主线程时刻去侦听客户端,如果客户端断开,立马从ClientList删除
 private void CloseClientSocket(string uid)
        {
            if (uid == string.Empty || uid == "")
                return;
            SocketAsyncEventArgsWithId saeaw = readWritePool.FindByUID(uid);
            if (saeaw == null)
                return;
            Socket s = saeaw.ReceiveSAEA.UserToken as Socket;
            try
            {
                s.Shutdown(SocketShutdown.Both);
            }
            catch (Exception)
            {
                //客户端已经关闭
            }
            this.semaphoreAcceptedClients.Release();
            Interlocked.Decrement(ref this.numConnections);
            this.readWritePool.Push(saeaw);
        }现在就有个问题了,假如3将某个客户端A从ClientList删除了,并且关闭了Socket连接,但是2中还没有及时更新,导致其访问的还是旧数据,所以当给A发送数据时就立马报错,因为这时候A已经断开了,请问我如何保证2中在执行发送的时候始终是在线的客户端呢?

解决方案 »

  1.   

    这要涉及到线程同步,你给客户端设置一个Active属性,代表这个客户端的链接状态,
     public bool Active
            {
                get
                {
                    lock (syncActive)
                    {
                        return active;
                    }
                }
                set
                {
                    lock (syncActive)
                    {
                        active = value;
                    }
                }        }
    在3中关闭客户端连接前设置Active=false;
    在2中发送数据前判断该客户端的Active是否为true;
      

  2.   

    每次读写 ClientList 都把它 lock 起来
      

  3.   

    用lock 锁住ClientList   一次只允许一个线程访问
      

  4.   

    在第二步加Lock的话,假如客户端A现在已经断开了,我恰好又给A发送数据,这时候还是会报错啊,似乎不行
      

  5.   

    这是发送方法
    /// <summary>
            /// 发送数据包
            /// </summary>
            /// <param name="sock"></param>
            /// <param name="data"></param>
            public void SendData(Socket sock, byte[] data,MySocketAsyncEventArgs e)
            {
                if (e.IsAlive)
                {
                    sock.BeginSend(data, 0, data.Length, SocketFlags.None, AsynCallBack, sock);
                }
            }        /// <summary>
            /// 
            /// </summary>
            /// <param name="result"></param>
            void AsynCallBack(IAsyncResult result)
            {
                try
                {
                    Socket sock = result.AsyncState as Socket;                if (sock != null)
                    {
                        sock.EndSend(result);
                    }
                }
                catch
                {
                }这是判断是否用的属性 private bool isAlive = false;        object syncActive = new object();        /// <summary>
            /// 是否可用
            /// </summary>
            public bool IsAlive
            {
                get
                {
                    lock (syncActive)
                    {
                        return isAlive;
                    }
                }
                set
                {
                    lock (syncActive)
                    {
                        isAlive = value;
                    }
                }
            }但是还会报错哦
      

  6.   

    bool 本来就是线程安全的, lock 不 lock 都是一个样。要 lock 的是 Dictionary.Add, Dictionary.TryGetValue() 之类的方法保证同一个时间仅有一个线程修改 Dictionary
      

  7.   

    有种情况大家可能要注意哈,就是Dictionary集合随时可能都会变,也就是说客户端随时可能都会掉线,我给客户端发送信息时,应该保证每次读到的就是最新的在线数据,就算我在读的时候Lock了,客户端那里断了,我给它发的时候还是会报错,不知道我理解可对
      

  8.   

    sp1234,大侠你的意思是不用管这种情况吗,就算报错直接Try_Catch吗,是的,我测试的时候如果短线非常频繁的话就会出现“您的主机中的软件放弃了一个已建立的连接”的错误,还请指教