问题1:在我的客户端关闭后,服务器怎么也关闭了;
问题2:如果服务器要连接多个客户端,我想在AcceptCallback里继续调用Socket.BeginAccpet为什么不可以呢?如何才能连接多个客户端?代码如下:
【服务器端】using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Net;
using System.Net.Sockets;
using System.Threading;
using System.Windows.Forms;namespace AsyncTcpServer {    public partial class Form1 : Form {
        public const int BUFFSIZE = 1024;
        public Socket m_server;
        public byte[] m_buffer = new byte[BUFFSIZE];        // Thread signal.
        public static ManualResetEvent allDone = new ManualResetEvent(false);        public Form1() {
            InitializeComponent();
        }
        private void Form1_Load(object sender, EventArgs e) {
            //从程序设计上来说,只有创建界面的主线程才能访问界面上的控件
            //因为我们在OnReceive中访问了控件,所以这里设置成false
            CheckForIllegalCrossThreadCalls = false;
            // Create a TCP/IP socket.
            m_server = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
            IPAddress ipAddress = IPAddress.Parse("127.0.0.1");
            IPEndPoint localEndPoint = new IPEndPoint(ipAddress, 9998);            try {
                m_server.Bind(localEndPoint);
                m_server.Listen(100);                //while (true)
                //{
                //    allDone.Reset();
                m_server.BeginAccept(
                    new AsyncCallback(AcceptCallback),
                    m_server);
                //    allDone.WaitOne();
                //}
            } catch (Exception ex) {
                MessageBox.Show(ex.ToString());
            }
        }        public void AcceptCallback(IAsyncResult ar) {
            try {
                //allDone.Set();
                // Get the socket that handles the client request.
                //Socket listener = (Socket)ar.AsyncState;
                Socket handler = m_server.EndAccept(ar); //返回的是什么?服务器的socket????                m_server = handler;                handler.BeginReceive(m_buffer, 0, m_buffer.Length, 0,
                    new AsyncCallback(ReceiveCallback), handler);
            } catch (Exception ex) {
                m_server.BeginAccept(new AsyncCallback(AcceptCallback), m_server);
            }        }        public void ReceiveCallback(IAsyncResult ar) {
            
            String content = String.Empty;
            // Read data from the client socket. 
            int bytesRead = m_server.EndReceive(ar);
            string strData = Encoding.ASCII.GetString(m_buffer, 0, bytesRead);
            try {
                if (bytesRead > 0) {
                    if (strData.Equals("closeClient")) {
                        strData = "client has gotten out...";
                    }
                    lstContent.Items.Add(strData);
                }
                m_server.BeginReceive(m_buffer, 0, m_buffer.Length, 0,
                        new AsyncCallback(ReceiveCallback), m_server);
            } catch (Exception ex) {
                //MessageBox.Show(ex.ToString());
                m_server.BeginAccept(new AsyncCallback(AcceptCallback), m_server);
            }
        }        private void Send(String data) {
            // Convert the string data to byte data using ASCII encoding.
            byte[] byteData = Encoding.ASCII.GetBytes(data);            // Begin sending the data to the remote device.
            m_server.BeginSend(byteData, 0, byteData.Length, 0,
                 new AsyncCallback(SendCallback), m_server);
        }        private void SendCallback(IAsyncResult ar) {
            try {
                // Complete sending the data to the remote device.
                int bytesSent = m_server.EndSend(ar);                //handler.Shutdown(SocketShutdown.Both);
                //handler.Close();            } catch (Exception e) {
                MessageBox.Show(e.ToString());
            }
        }
    }
}【客户端】
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Windows.Forms;
using System.Net;
using System.Threading;
using System.Net.Sockets;namespace AsyncTcpClient
{
    public partial class Form1 : Form
    {
        public Socket m_client;
        public EndPoint m_epServer;
        public byte[] m_buffer;
        public int port = 9998;
        public Form1()
        {
            InitializeComponent();
        }
        private void Form1_Load(object sender, EventArgs e)
        {
            try
            {
                IPAddress ipAddress = IPAddress.Parse("127.0.0.1");
                m_epServer = new IPEndPoint(ipAddress, port);
                m_client = new Socket(AddressFamily.InterNetwork,SocketType.Stream, ProtocolType.Tcp);
                // Connect to the remote endpoint.
                m_client.BeginConnect(m_epServer,
                    new AsyncCallback(ConnectCallback), m_client);
            }
            catch (Exception ex)
            {            }
        }
        private void ConnectCallback(IAsyncResult ar)
        {
            try
            {                
                // Complete the connection.
                m_client.EndConnect(ar);                lstContent.Items.Add("Socket connected to "+
                    m_client.RemoteEndPoint.ToString());
            }
            catch (Exception e)
            {
                MessageBox.Show(e.ToString());
            }
        }        private void Receive()
        {
            try
            {
                // Begin receiving the data from the remote device.
                m_client.BeginReceive(m_buffer, 0, m_buffer.Length, 0,
                    new AsyncCallback(ReceiveCallback), m_client);
            }
            catch (Exception e)
            {
                Console.WriteLine(e.ToString());
            }
        }        private void ReceiveCallback(IAsyncResult ar)
        {
            try
            {
                // Read data from the remote device.
                int bytesRead = m_client.EndReceive(ar);                if (bytesRead > 0)
                {
                    lstContent.Items.Add(Encoding.ASCII.GetString(m_buffer, 0, bytesRead));
                }       
                m_client.BeginReceive(m_buffer, 0, m_buffer.Length, 0,
                    new AsyncCallback(ReceiveCallback), m_client);    
            }
            catch (Exception e)
            {
                MessageBox.Show(e.ToString());
            }
        }        private void Send(String data)
        {
            // Convert the string data to byte data using ASCII encoding.
            byte[] byteData = Encoding.ASCII.GetBytes(data);            // Begin sending the data to the remote device.
            m_client.BeginSend(byteData, 0, byteData.Length, 0,
                new AsyncCallback(SendCallback), m_client);
        }        private void SendCallback(IAsyncResult ar)
        {
            try
            {
                // Retrieve the socket from the state object.
                Socket client = (Socket)ar.AsyncState;                // Complete sending the data to the remote device.
                int bytesSent = client.EndSend(ar);
               lstContent.Items.Add(String.Format("Sent {0} bytes to server.", bytesSent));
            }
            catch (Exception e)
            {
                Console.WriteLine(e.ToString());
            }
        }        private void btnSend_Click(object sender, EventArgs e)
        {
            if (txtMessage.Text != string.Empty)
            {
                Send(txtMessage.Text);
            }
        }        private void Form1_FormClosing(object sender, FormClosingEventArgs e)
        {
            Send("closeClient");//发送关闭客户端指令
        }
    }
}
C# Tcp 异步 Socket 断开 

解决方案 »

  1.   

    一看就知道是抄来的代码,而且自己完全不动C#。
    //while (true)
    //{
    //    allDone.Reset();
          m_server.BeginAccept(
          new AsyncCallback(AcceptCallback),
          m_server);
    //    allDone.WaitOne();
    //}
    把这里面的注释去掉就可以连接多个客户端了,AcceptCallback方法里面的注释也要去掉,catch部分添加注释,出现异常输出即可,不要自动重新等待连接。
      

  2.   

    80%是服务器出现异常
    你用Ctrl+F5运行程序,出异常cmd窗口还在,异常会显示在上面。
      

  3.   


    谢谢您的回复,这里的注释是我自己加的,代码是我把MSDN里的console代码该成现在的Window代码了……如果把注释恢复的话,Server的主窗体将不会显示出来,我感觉是allDone把主线程阻塞了。我尝试了把上面的While放在了新的线程里,但那样还是不对。为什么啊?
      

  4.   

    client的窗体正常关闭的时候,服务器的窗体就自动关闭了
      

  5.   

    你在服务端一步一步debug,看看他是在哪里关闭,为什么会关闭。
      

  6.   

    allDone就是阻塞线程用的,否则那个while就会无限打开新的监听,这是不合理的,因此需要等待上个监听被连接后,才开始新的监听。因此while必须放在其它线程里执行,而不能直接在窗口控件所在的线程里执行。
      

  7.   

    其实不用allDone也可以做到,而且更好,微软这里使用了异步方式编程,但又使用allDone来阻塞,说白了只是为了让你学习这两者东西,而实际编程这样做就是画蛇添足,如果你用了异步方式,就不该阻塞,否则直接同步方法调用Accept方法不就好啦。
    正确的做法是在BeginAccept的回调函数AcceptCallback的最后再次执行BeginAccept,这样就可以做到处理完一个连接请求继续处理下一个。而且由于最初的BeginAccept不是循环内执行,只执行了一次就离开了,所以不会阻塞UI线程。
      

  8.   

    楼上说的对,但是如果在AcceptCallBack中调用BeginAccept,当客户端刚启动时,服务器就自动关闭了……这是为什么啊?
      

  9.   

    自动关闭就是发生了错误,但是没有被检测到,比如你这里设置了“CheckForIllegalCrossThreadCalls = false;”,不让程序自动检查跨线程操作,但是这种操作很危险的,很容易出现错误导致系统崩溃。你可以先屏蔽那个频繁的“lstContent.Items.Add”操作,通过变量存储收发内容,最后一次性更新到界面上去。
      

  10.   

    谢谢您的回答,我用Invoke代替了“CheckForIllegalCrossThreadCalls = false;”,这样在AcceptCallBack中调用Socket.BeginAccept后,启动客户端服务器不会自动关闭了。但是在AcceptCallBack中调用BeginAccept抛出必须先调用Socket.Listen的异常,我把Listen加上之后又抛出“在一个已经连接的套接字上做了一个连接请求”,这是怎么回事儿啊?
      

  11.   

    //Socket listener = (Socket)ar.AsyncState;
    Socket handler = m_server.EndAccept(ar); 
    看下这两句,第一句被你屏蔽了,关键点也就是它,这两个Socket是不同的Socket,第一个listener通过ar获取的,那个才是你服务端用来监听的Socket,而第二个只是同客户端建立连接的Socket,不是监听用的Socket
      

  12.   

    再次感谢您的耐心回答……
    //Socket listener = (Socket)ar.AsyncState;把这句恢复后还是和屏蔽时一样的错。
    我在调用BeginAccept的时候是这样的
    m_server.BeginAccept(new AsyncCallback(AcceptCallback),
                        m_server);
    所以Socket listener = (Socket)ar.AsyncState;这句注释和不注释是一样的吧
      

  13.   


    我把AcceptCallBack改成了如下:public void AcceptCallback(IAsyncResult ar) {
                try {
                    // Get the socket that handles the client request.
                    Socket listener = (Socket)ar.AsyncState;
                    Socket handler = listener.EndAccept(ar);                 handler.BeginReceive(m_buffer, 0, m_buffer.Length, 0,
                        new AsyncCallback(ReceiveCallback), handler);                listener.BeginAccept(new AsyncCallback(AcceptCallback), handler);
                } catch (Exception ex) {
                    MessageBox.Show(ex.ToString());
                }        }然后就晕了,listener和handler与m_server这三个Socket不一样吗?
    在AcceptCallBack中调用BeginAccept的是m_server还是listener啊?
    改成如上的代码后,没异常了,但是当客户端发送消息时,服务器就自动关闭了