当前位置: 代码迷 >> C# >> c# 异步socket关闭有关问题,分还可以在加.
  详细解决方案

c# 异步socket关闭有关问题,分还可以在加.

热度:69   发布时间:2016-05-05 03:39:33.0
c# 异步socket关闭问题,在线等,分还可以在加......................................................

        public bool btnstatu = true;  //开始停止服务按钮状态
        public Thread myThread;       //声明一个线程实例

        //开始停止服务按钮
        private void startService_Click(object sender, EventArgs e)
        {
            if (btnstatu)
            {
                // 实例化新线程
                myThread = new Thread(new ThreadStart(Listen));
                btnstatu = false;
            }
            else
            {
                try
                {
                    newsock.Shutdown(SocketShutdown.Both);
                }
                catch { }
                newsock.Close();
                myThread.Abort();
                btnstatu = true;

            }
            
            GC.Collect();//即使垃圾回收
            GC.WaitForPendingFinalizers();

        }

        //监听函数
        public void Listen()
        {
            //后台线程
            Thread.CurrentThread.IsBackground = true; 
            //初始化SOCKET实例
            newsock = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
            //初始化终结点实例
            ipa = IPAddress.Any; //IPAddress.Parse(textBox1.Text.Trim());
            
            setPort = int.Parse(serverport.Text.Trim());
            localEP=new IPEndPoint(ipa,setPort);
            try
            {
                newsock.IOControl(IOControlCode.KeepAliveValues, GetKeepAliveSetting(1,1000,1000), null);
                //绑定
                newsock.Bind(localEP);
                //监听
                newsock.Listen(500);
               //开始接受连接,异步。

                while (true)
                {
                    AcceptDone.Reset();
                    try
                    {
                        newsock.BeginAccept(new AsyncCallback(AcceptCallback), newsock);
                    }
                    catch
                    {
                        Thread.Sleep(1000);
                        newsock.BeginAccept(new AsyncCallback(AcceptCallback), newsock);
                    }
                    AcceptDone.WaitOne();
                }
             }
            catch (Exception ex)
            {
                showClientMsg(ex.Message);
            }

        }

        public void AcceptCallback(IAsyncResult ar) //accpet的回调处理函数
        {

            AcceptDone.Set();
            server1 = (Socket)ar.AsyncState;
            //将接收到的Socket传给Client,然后继续监听
            Client = server1.EndAccept(ar);

            Control.CheckForIllegalCrossThreadCalls = false;
            DateTimeOffset now = DateTimeOffset.Now;
            //将提示信息发送给客户端,并在服务端显示连接信息。
            ClientIP = (Client.RemoteEndPoint as IPEndPoint).Address;//获取远程端口的ip地址
            ClientPORT = (Client.RemoteEndPoint as IPEndPoint).Port;//获取远程的端口
            ClientName = "IP:" + ClientIP + "Port:" + ClientPORT;

            StateObject state = new StateObject();
            state.workSocket = Client;
            state.socketid = ClientName;

            try
            {
                Client.BeginReceive(state.buffer, 0, StateObject.BufferSize, 0, new AsyncCallback(ReadCallback), state);
            }
            catch (SocketException)
            {
                Client.Shutdown(SocketShutdown.Both);
                Client.Close();
            }

        }
        public void ReadCallback(IAsyncResult ar)
        {
            try
            {
                String content = String.Empty;
                StateObject state = (StateObject)ar.AsyncState;
                Socket handler = state.workSocket;
                int bytesRead = handler.EndReceive(ar);
;
                if (bytesRead == 0)
                {
                    handler.Shutdown(SocketShutdown.Both);
                    handler.Close();
                }

                if (bytesRead > 0)
                {
                    string stringdata = ""; //接收到的数据
                    stringdata += Encoding.GetEncoding("utf-8").GetString(state.buffer, 0, bytesRead);
                    //显示客户端发送过来的信息
                    showClientMsg("【" + state.socketid + "】发送消息" + stringdata + "时间:" + DateTime.Now.ToString() + "\r\n");

                }
                
                handler.Shutdown(SocketShutdown.Both);
                handler.Close();
            }
            catch
            {
            }
        }



问题是点击关闭服务按钮,即btnstatu = false时,就提示

该如何关闭异步产生的socket


------解决思路----------------------
1、设置布尔变量(isListening),用来标识是否正在监听,只有isListening为tru时,在异步接收
2、窗体关闭前,释放监听(isListening置为false,socket对象进行close、赋null值)
------解决思路----------------------
关闭连接必然会报错的,这就是正常流程,关闭的时候只要 Shutdown 就行, 捕获错误后再 Close
另外楼主的监听部分, 使用了异步 BeginAccept, 却又用了AcceptDone来同步, 不是多此一举吗.
接收数据的部分收过一次就关闭连接了, 有可能数据没有一次性全部传过来, 需要考虑多次接收, 楼主的代码是有隐患的.
------解决思路----------------------
如你是想在主线程中关闭子线程的Socket,建议先判断一个子线程是否已经运行完成。如果完成了再去释放子线程中的资源。
但如果子线程是一直在运行了,那你只能做一个开关量来关闭子线程后在释放资源。就像backgroundworker.workerSupportsCancellation一样。。。
------解决思路----------------------
引用:
关闭连接必然会报错的,这就是正常流程,关闭的时候只要 Shutdown 就行, 捕获错误后再 Close
另外楼主的监听部分, 使用了异步 BeginAccept, 却又用了AcceptDone来同步, 不是多此一举吗.
接收数据的部分收过一次就关闭连接了, 有可能数据没有一次性全部传过来, 需要考虑多次接收, 楼主的代码是有隐患的.


关闭连接倒是不一定报错。
监听部分的确是‘多此一举’。


以下是一个如何‘开始/停止’监听的示例,示例用了TcpListener,自己换成Socket也可以,原理是相同的。
建议新建一个WinForm项目,然后拷贝以下代码,并编译运行,按'Start'按钮开始侦听。
测试客户可以用浏览器,在地址栏输入http://localhost:5678即可。


public partial class Form1 : Form
{
    public Form1()
    {
        InitializeComponent();

        FlowLayoutPanel layoutPanel = new FlowLayoutPanel() { Dock = DockStyle.Fill };
        layoutPanel.Controls.AddRange(new Control[] { textBoxPort, buttonStartStop, listBoxLog});
        buttonStartStop.Click += button1_Click;
        this.Controls.Add(layoutPanel);
    }

    void button1_Click(object sender, EventArgs e)
    {
        listening = !listening;
        if (listening)
        {
            int port = int.Parse(textBoxPort.Text);
            listenerThread = new Thread(ListenerThread) { IsBackground = true };
            listenerThread.Start(port);
        }
        else
        {
            listenerThread.Join();
        }
        buttonStartStop.Text = listening ? "Stop" : "Start";
    }

    void ListenerThread(object state)
    {
        try
        {
            TcpListener listener = new TcpListener(IPAddress.Any, (int)state);
            listener.Start();
            Log("Listener started on " + state);
            while (listening)
            {
                if (listener.Server.Poll(100, SelectMode.SelectRead)) // 一次最多阻塞100毫秒,以便检查listening标志。
                {
                    Socket socket = listener.AcceptSocket();
                    Log("Client connected - " + socket.RemoteEndPoint);
                    StateObject so = new StateObject() {socket = socket };
                    socket.BeginReceive(so.buffer, 0, so.buffer.Length, SocketFlags.None, OnReceived, so);
                }
            }
            listener.Stop();
            Log("Listener stopped");
        }
        catch (Exception ex)
        {
            Log("Exception in ListenerThread: " + ex.Message);
        }
    }

    void OnReceived(IAsyncResult iar)
    {
        try
        {
            StateObject so = (StateObject)iar.AsyncState;
            int received = so.socket.EndReceive(iar);
            if (received > 0)
            {
                string msg = Encoding.UTF8.GetString(so.buffer, 0, received);
                so.socket.Send(Encoding.UTF8.GetBytes(DateTime.Now.ToString("s")));
                Log(so.socket.RemoteEndPoint + " -> " + msg);
            }
            Log("Closing connection with " + so.socket.RemoteEndPoint);
            so.socket.Shutdown(SocketShutdown.Both);
            so.socket.Close();
        }
        catch (Exception ex)
        {
            Log("Exception in OnReceived: " + ex.Message);
        }
    }

    void Log(string line)
    {
        if (this.InvokeRequired)
        {
            this.BeginInvoke((Action)delegate { Log(line); });
            return;
        }
        listBoxLog.Items.Add(string.Format("[{0:s}] {1}", DateTime.Now, line));
    }

    TextBox textBoxPort = new TextBox() { Text = "5678" };
    Button buttonStartStop = new Button() { Text = "Start" };
    ListBox listBoxLog = new ListBox() { Size = new Size(400, 300) };
    Thread listenerThread;
    bool listening = false;

    private class StateObject
    {
        public Socket socket;
        public byte[] buffer = new byte[4 * 1024];
    }
}

------解决思路----------------------
你可以把 listenerThread.Join()
理解为
while( listenerThread.IsAlive)
{
sleep(1);
}
当然内部实现不会这么低级就是了,但是作用是一样的,当然用sleep来阻塞当前线程效率就低的多了
------解决思路----------------------
关闭的时候同时关闭
private void ClearClient()
        {
            if (AcceptSockAsyn != null)
            {
                AcceptSockAsyn.Dispose();
                AcceptSockAsyn = null;
            }

            EndPoint[] ep = new EndPoint[connectClient.Keys.Count];
            connectClient.Keys.CopyTo(ep, 0);

            Token token;
            SocketAsyncEventArgs args;
            for (int i = 0; i < ep.Length; ++i)
            {
                args = connectClient[ep[i]];
                token = args.UserToken as Token;
                CloseClientSocket(token);
            }

            connectClient.Clear();
            ep = null;
        }
  相关解决方案