C#通过socket 异步传输数据功能已实现,如果网络不好的情况(电信服务器给网通服务器发送数据)偶尔会出现数据丢失 客户端发送数据成功,但服务端接口不到,如何才能避免网络不好的情况下数据正常接收?如果帮我侧地解决掉这个问题,绝对按标题说的给帮我解决问题的朋友打200元,绝不食言!一下是我的代码--------------------------------------- 服务端代码  用线程调用 Listen()方法 private void Listen() 
        {             string strIP = Dns.GetHostEntry(Dns.GetHostName()).AddressList[0].ToString(); 
            if (strIP.Length < 9) 
            { 
                strIP = Dns.GetHostEntry(Dns.GetHostName()).AddressList[1].ToString(); 
            }             IPAddress ip = IPAddress.Parse(strIP); 
            IPEndPoint ipe = new IPEndPoint(ip, 8889); 
            sockets = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp); 
            sockets.Bind(ipe); 
            sockets.Listen(500); 
            while (isRun) 
            { 
                Control.CheckForIllegalCrossThreadCalls = false;                 try 
                { 
                    allDone.Reset(); 
                    sockets.BeginAccept(new AsyncCallback(AcceptCallback), sockets); 
                    allDone.WaitOne(); 
                } 
                catch 
                {                 } 
            } 
          
        } 
        private void AcceptCallback(IAsyncResult ar) 
        { 
            try 
            { 
                allDone.Set(); 
                Socket listener = (Socket)ar.AsyncState; 
                Socket handler = listener.EndAccept(ar);                 StateObject state = new StateObject(); 
                state.workSocket = handler; 
                handler.BeginReceive(state.buffer, 0, StateObject.BufferSize, 0, new AsyncCallback(ReadCallback), state); 
            } 
            catch 
            { 
                
            } 
        } 
        private 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) 
                { 
                    state.sb.Append(Encoding.Default.GetString(state.buffer, 0, bytesRead)); 
                  
                    string info = state.sb.ToString();                     } 
                } 
            } 
            catch 
            { } 
        } 

解决方案 »

  1.   

    首先,你这是使用异步的语法,实际上是同步编程。我从来不使用WaitHandle用于服务器监听。msdn上这类使用信号量阻塞来在异步代码中模拟同步控制的例子,每当我看到我就骂一遍。你要么就是用同步的Accept方法,要么就是用真正的异步多线程多并发控制。
      

  2.   

    其次,你的 allDone.Set();  似乎太早了吧?不过我所谓了,这类用信号量阻塞方式来冒充异步编程的东西,东西我看到了就不想测试了。
      

  3.   

    老兄  能不能给个演示的代码啊? 其实我对socket 也是一知半解的,谢谢了
      

  4.   

    首先问题还不够细。。
    其次个人感觉csdn里面分比钱重要。。感觉楼主还是胆子小点。你把钱放在猪八戒上面,估计现在任务已经解决了。
      

  5.   

    首先,你是使用ProtocolType.Tcp, 在IP/TCP协议中,应用层是不需要理会丢包问题的,因为底层会有重发机制,面向连接的SOCKET中是没有接收不到包的情况的,也没有丢包的说法,这个基础需要去补补。
    好的,现在的问题是如何检测掉线的问题,在 sockets.BeginAccept方法中.NET封装了一些异常捕获,在SocketException中:        try{
                  //...
            }
            catch (SocketException e)   
            {   
                //10035 == WSAEWOULDBLOCK   
                if (e.NativeErrorCode.Equals(10035))   
                {   
                    //仍然处于连接状态,但是发送可能被阻塞   
                }   
                else  
                {   
                    //连接错误,返回错误代码:e.NativeErrorCode   
                    Socket_e.ResCode = e.NativeErrorCode.ToString();   
                    SocketEvent(this, Socket_e);   
                    return;   
                }   
            }   
        catch (Exception e)   
             {      
                 //其他错误   
                 Socket_e.ResCode = e.ToString();   
                 SocketEvent(this, Socket_e);   
                 return;                       
             }        
    如果是UDP的连接就要考虑丢包的解决方案。一般是在判断包头的信息,重组,丢弃等做法。
      

  6.   

    在MSDN上,这部分的实例代码确实不实用,在很多地方需要自己修改下,重要的是理解方法的使用,建议弄清楚SOCKET这个类,如果有时间,建议了解下WIN32中的SOCKET编程,对更加深刻的理解网络编程有好处,.NET虽然封装了很多操作,SOCKET的操作更是简单的一塌糊涂,但是,这样对真正的深入编程是没有好处的,没有弄清楚原理,只有沦为代码搬运工。
      

  7.   

    TCP是不会丢包的,是不是连接断了,如果是短连接就加个心跳包,要真不是连接的问题,估计楼主用的是UDP了
      

  8.   

    为什么不建议使用 WaitHandle ?
      

  9.   

    这是MSDN上的标准写法,没有任何问题。楼主你的问题是出在catch块中没有做任何处理,因为一旦因网络不稳定导致数据传输失败,catch中肯定会有异常抛出,你的代码中直接将这类异常丢弃了,这显然是不行的。
      

  10.   

        本来TCP应该是出错会重传的,但是网通和电信之间传输的话,很可能是在中间路由的时候出现了问题,结果连重传都没做,那样的话,你最好增加自己的消息验证,方法如下:
        首先给每次发送的消息编号,使用GUID即可,如果是发送XML更佳。当消息发送到服务器端后,服务器端返回一个确认消息给客户端,确认消息也要带上刚收到的消息的编号,这样客户端得到了这个确认消息就认为服务器端正常接收,否则就有可能接收失败,如果未收到确认消息(也可能是确认消息发送失败),客户端再次发送上次的消息,编号仍旧用上次的,这样服务器端即使重复收到了消息,也可以通过编号来识别是否是上次的消息重发了。
      

  11.   

    问题被猪八戒的网友解决了,也谢谢各位的回答,我把代码公布下,希望有这方面问题的朋友可以参考下:客户端代码:public partial class Form1 : Form
        {
            string host = "192.168.1.5";
            int port = 8888;
            Thread thread;
            int rcount;
            int fcount;
            int sendcount = 1;
            public Form1()
            {
                InitializeComponent();
            }        private void button1_Click(object sender, EventArgs e)
            {            thread = new Thread(new ThreadStart(send));
                thread.Start();
                
            }
            private void UpdateUI(object o, System.EventArgs e)
            {
                sendcount += 1;
                label1.Text = o.ToString();
            }
            private void send()
            {
                string msg = "";
                for (int i = 0; i < 10000; i++)
                {
                    msg = "第" + i + "次发送数据";
                    TcpClient client = new TcpClient();
                    client.Connect(host, port);
                    NetworkStream ns = client.GetStream();
                    ns.ReadTimeout = 1000;
                    byte[] bs = Encoding.Default.GetBytes(msg);
                    bool isSend = true;
                    while (isSend)
                    {
                        if (client.Connected == false)
                        {
                            client.Close();
                            client = new TcpClient();
                            client.Connect(host, port);
                            ns = client.GetStream();
                            ns.ReadTimeout = 1000;
                        }
                        ns.Write(bs, 0, bs.Length);
                        try
                        {
                            if (bs[0] == ns.ReadByte())
                            {
                                isSend = false;
                                label1.BeginInvoke(new System.EventHandler(UpdateUI), "send ok" + (rcount++));
                            }
                            else
                            {
                                break;
                            }
                        }
                        catch (Exception ex)
                        {
                            label1.BeginInvoke(new System.EventHandler(UpdateUI), "send fail" + (fcount++));
                        }
                        Thread.Sleep(1000);
                    }
                    client.Close();
                }
            }
        }
      

  12.   

     byte[] reveidata;
            Thread thread;
            TcpListener listener;
            int reqeustcount = 0;        /// <summary>
            /// 开始监听
            /// </summary>
            /// <param name="sender"></param>
            /// <param name="e"></param>
            private void button1_Click(object sender, EventArgs e)
            {
                thread = new Thread(new ThreadStart(Listen));
                thread.Start();
                Rolling();
            }        /// <summary>
            /// 停止监听
            /// </summary>
            /// <param name="sender"></param>
            /// <param name="e"></param>
            private void button2_Click(object sender, EventArgs e)
            {
                try
                {
                    listener.Stop();
                    thread.Abort();
                }
                catch(Exception ex)
                {
                    throw ex;
                }
                Rolling();
            }
            private void Rolling()
            {
                richTextBox1.SelectionStart = richTextBox1.Text.Length;
                richTextBox1.ScrollToCaret();
            }
            private void UpdateUI(object o, System.EventArgs e)
            {
                richTextBox1.AppendText("\n" + o.ToString());
            }
            private void Listen()
            {
                try
                {
                    string hostname = System.Net.Dns.GetHostName();
                    IPHostEntry ipEntry = Dns.GetHostEntry(hostname);
                    IPAddress ip = ipEntry.AddressList[0];
                     listener = new TcpListener(IPAddress.Any, 8889);
                    listener.Start();
                    bool done = false;
                    reveidata = new byte[1000];
                    while (!done)
                    {
                        reqeustcount += 1;
                        Socket client = listener.AcceptSocket();
                        try
                        {
                            byte[] returnNum = new byte[1];
                            client.Receive(reveidata);
                            string str = Encoding.Default.GetString(reveidata);
                            richTextBox1.BeginInvoke(new System.EventHandler(UpdateUI), "第:" + reqeustcount.ToString() + "接收数据  " + str);
                            returnNum[0] = reveidata[0];
                            client.Send(returnNum);
                        }
                        catch (Exception e)
                        {
                            richTextBox1.BeginInvoke(new System.EventHandler(UpdateUI), "端口被占用  ");
                        }
                    }
                }
                catch(Exception ex)
                {
                    throw ex;
     
                }
            }
      

  13.   

    上周刚完成了一个通信的C S 程序,开始做的时候确实很烦锁,明明设计好的程序就是不听使,经过一周的不断调试,现在已经非常稳定,不知是否可帮楼主,主要思路各位都说了,而我的思路之前LZ发的贴我也回复过,如果不行可能是你细节代码的问题,有兴趣了解可加我QQ183003220
      

  14.   


    ping XXX.XXX.XXX.XXX -t
    发现有TIMEOUT的情况直接回给领导...这种事情你的小罗罗..还解决个毛啊.....电信..网通内部都是走的私网..网络有丢包..说不定是那个交换机设备不好呢...
    你要做的是网络不好..比如网络断了..重连多少次..失败了..上报一个告警..就完事了...不要一直重连...这样有的设备会认为是攻击的...会出大事的...
      

  15.   

    可以在客户端自己做一个cash保存所有你发出去的消息形成一个消息队列,然后只要有收到的回复,那么就将这条消息从队列中remove,如果没有回复则一直try发送,然后接收断就要做到同一个消息只接受一次的办法,这样一来就差不多可以了!
      

  16.   

    学习了                  if (client.Connected == false) 
                        { 
                            client.Close(); 
                            client = new TcpClient(); 
                            client.Connect(host, port); 
                            ns = client.GetStream(); 
                            ns.ReadTimeout = 1000; 
                        } 这个地方做个判断,不理解,如果前一次的连接不成功,你再连一次,如果再连一次不成功呢?
    你能直接发送数据?
      

  17.   


    哈哈,看到你骂WaitHandle不止一次了,确实B4 MSND的这个例子
      

  18.   

    到底是怎么解决的,我也是服务端生产错误,当客户端非常规断开后
     try
    {
      bytesRead = handler.EndReceive(ar);// Read data from the client socket. 
    }
    catch (Exception ex)
    {
      //抛出异常 远程主机强迫关闭一个现在的连接
    }
    再也接收不到数据了??
      

  19.   

    制定通讯协议
    比如CRC16校验什么的