zoukankan      html  css  js  c++  java
  • Socket开发异常总结

    Socket异常开发总结

    事情概况:今天早上手机充值业务突然停止,客户端又不断提交充值订单上来,短时间出现大量客户投诉,经检查,后在同事Aaron的帮助下,查找出问题原因

    首先看一下充值系统架构,手机充值Win Service 会每稍钟从数据库里查询出一条没有提交充值的订单去充值。结构类图概要如下

    其中充值的类里是去查询订单,送给SocketHelpSubmit方法去充值

    主要程序如下

    查询Win service 

    代码
     internal partial class TopupService3 : ServiceBase
        {
            
    private readonly Timer _submitTimer;


            
    public TopupService3()
            {
              
                _submitTimer 
    = new Timer(1000);
                _submitTimer.Elapsed 
    += SubmitTimerElapsed;

                _verifyTimer 
    = new Timer(5 * 60 * 1000);
                _verifyTimer.Elapsed 
    += VerifyTimerElapsed;
            }

            
    protected override void OnStart(string[] args)
            {
                _submitTimer.Start();
            }

            
    protected override void OnStop()
            {
                _submitTimer.Stop();
            
            }

            
    internal void SubmitTimerElapsed(object sender, ElapsedEventArgs e)
            {
                _submitTimer.Stop();
               
                
    try
                {

                 
    //查询提交充值            

                }
                
    catch (SqlException sqlException)
                {
                   
       
                }
                
    catch (Exception exception)
                {

                }
                
    finally
                {
                    _submitTimer.Start();
                }
           }
       }

    提交充值的SocketHelp

    代码
     public class SocketHelp
        {
            
    #region  手机充值

            
    public static string Submit()
            {
                
    try
                {
                    IPAddress ip 
    = IPAddress.Parse(Host);
                    var ipe 
    = new IPEndPoint(ip, Port); //把ip和端口转化为IPEndPoint实例
                    DFSubmitLog.Debug("建立sockets连接");
                    c 
    = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp); //创建一个Socket
                    DFSubmitLog.Debug("Connecting......");
                    c.Connect(ipe); 
    //连接到服务器
                    byte[] bs = Encoding.UTF8.GetBytes(upOrderContent);
                    c.Send(bs, bs.Length, 
    0); //发送测试信息
                    string recvStr = "";
                    var recvBytes 
    = new byte[1024];
                    Thread.Sleep(SocketTimeout);
                    
    int bytes = c.Receive(recvBytes, recvBytes.Length, 0);
                    recvStr 
    += Encoding.UTF8.GetString(recvBytes, 0, bytes);
                    c.Close();
                    
    return recvStr;
                }
                
    catch (ArgumentNullException e)
                {
                
                    
    return "";
                   
                }
                
    catch (SocketException e)
                {
                    
    return "";
                }
                
    finally
                {
                    
    if (c != null)
                    {
                       
                    }
                }

        }

    以上程序的Socket部份有问题,就是在Socket发送信息出去以后,程序就相当于停在那了,没有接收信息。此时不知道是发送的过程中出了问题,还是接收的过程中出了问题,总之程序是没有获取到异常。引用Aaron的原话是Socket处于无限期等待当中,在通讯过程中,由于客户端是周期性地向服务器请求数据,若客户端的请求指令或是服务端发来的数据包丢失的话,那么客户端将一直等待,陷入假死状态。

    针对这个问题,把Socket程序修改成同步Socket,代码如下

     

    代码
    public class SocketHelp
        {
            
    #region  手机充值

            
    public static string Submit(Order record, string productInfo)
            { 
                
    try
                {
                    IPAddress ip 
    = IPAddress.Parse(Host);
                    IPEndPoint ipe 
    = new IPEndPoint(ip, Port); 
                    
    using (Socket clientSocket = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp))
                    {
                        clientSocket.ReceiveTimeout 
    = SocketTimeout;
                        clientSocket.SendTimeout 
    = SocketTimeout;
                        DFSubmitLog.Debug(
    "Connecting......");
                        clientSocket.Connect(ipe);
                        
    byte[] bs = Encoding.UTF8.GetBytes(upOrderContent);
                        clientSocket.Send(bs, bs.Length, 
    0);
                        
    string recvStr = String.Empty;
                        
    byte[] recvBytes = new byte[1024];
                        Thread.Sleep(SocketTimeout);
                        
    int bytes = clientSocket.Receive(recvBytes, recvBytes.Length, 0);
                        recvStr 
    = Encoding.UTF8.GetString(recvBytes, 0, bytes);
                        clientSocket.Shutdown(SocketShutdown.Both);
                        clientSocket.Close();
                        
    return recvStr;
                    }
                }
                
    catch (ArgumentNullException e)
                {
                    
    return String.Empty;
                }
                
    catch (SocketException e)
                {
                    
    return string.Empty ;
                }
                
    catch (Exception e)
                {
                    
    return string.Empty;
                }
            }

        }

    指定了,发送数据时间,接收数据时间,超过这个时间了就引发socket异常

    修改了程序以后,我把其中变量SocketTimeout设置成500,即500毫秒,由于这个时间还是不够长,在程序起动的时候会引发   SocketException: 由于连接方在一段时间后没有正确答复或连接的主机没有反应,连接尝试失败

    后来我把SocketTimeout设置成2000,即2秒钟就没有问题,程序可以正常运行

    相关Socket类的MSND地址是:

    http://msdn.microsoft.com/zh-cn/library/attbb8f5(v=VS.80).aspx

    其中关于Socket类的几个属性资料摘录如下

    1.       当数据发送和数据接收完成之后,可使用 Shutdown 方法来禁用 Socket。在调用 Shutdown 之后,可调用 Close 方法来释放与 Socket 关联的所有资源

    2.       Socket.SendTimeout 属性

    获取或设置一个值,该值指定之后同步 Send 调用将超时的时间长度。

    命名空间:System.Net.Sockets属性值

    超时值(以毫秒为单位)。如果将该属性设置为 1 499 之间的值,该值将被更改为 500。默认值为 0,指示超时期限无限大。指定 -1 还会指示超时期限无限大。

    3 Socket.ReceiveTimeout 属性

    获取或设置一个值,该值指定之后同步 Receive 调用将超时的时间长度。

    命名空间:System.Net.Sockets

    程序集:System(在 system.dll 中)

    超时值(以毫秒为单位)。默认值为 0,指示超时期限无限大。指定 -1 还会指示超时期限无限大。

    异常

    --------------------------------------------------------------------------------

    异常类型 条件

    SocketException

       试图访问套接字时发生错误。

    ObjectDisposedException

       Socket 已关闭。

    ArgumentOutOfRangeException

     为设置操作指定的值小于 -1

    --------------------------------------------------------------------------------

    此选项仅适用于同步 Receive 调用。如果超过超时期限,Receive 方法将引发 SocketException

     

     

    其它参考文摘

    http://blog.163.com/gfmq_312/blog/static/17823682200951711112373/

    在通讯过程中,由于客户端是周期性地向服务器请求数据,若客户端的请求指令或是服务端发来的数据包丢失的话,那么客户端将一直等待,陷入假死状态。由于默认为无超时,所以一定要记得设定客户端接收的超时时间,若服务器端无相应,客户端应该抛出异常,而不是毫无意义的等待

     

  • 相关阅读:
    导出CSV乱码
    php让一个数组按照另外一个数组的键名进行排序
    电脑没有网
    Android抓包方法(转)
    封装curl的get和post请求
    JavaScript动态加载CSS和JS文件
    压缩视频之后网页上只有声音,没有图像
    php BCMath高精度计算
    非table结构数据导入excel
    如何将页面上的数据导入excel中
  • 原文地址:https://www.cnblogs.com/zycblog/p/1909389.html
Copyright © 2011-2022 走看看