【问题标题】:Synchronous Socket: ReceiveTimeout同步套接字:ReceiveTimeout
【发布时间】:2020-10-12 10:15:52
【问题描述】:

我有一个在读取时阻塞的套接字线程。我将套接字上的接收超时设置为 30 秒;如果没有读取字节,则读取进入 IO 异常(内部异常:错误代码:10060)。我结束进程并关闭流并将线程设置为空。出于某种原因,我似乎无法关闭套接字连接。我不确定错误在哪里。以下是我的代码:

public class SampleClientSocket
{       
    private Socket cltSocket = null;        
    private volatile bool readyToRecv = false;        
    NetworkStream ns;
    BinaryReader br;
    BinaryWriter wr;
    private string _caller = "SampleSocketClient";
    Thread workerThread;
    
    static void Main(string[] args)
    {
        BeginWork();            
    }
    
    
    public void BeginWork()
    {            
        try
        {
            IPEndPoint ipe = new IPEndPoint("127.0.0.1", 5000);
            cltSocket = new Socket(ipe.AddressFamily, SocketType.Stream, ProtocolType.Tcp);

            cltSocket.Connect(ipe);

            cltSocket.ReceiveTimeout = 30000;
        
            cltSocket.SetSocketOption(SocketOptionLevel.Socket, SocketOptionName.ReuseAddress, true);            
        
            workerThread = new Thread(doWork_01);
            workerThread.Start();                
            readyToRecv = true;
        }
        catch (Exception f)
        {
            Console.WriteLine(this._caller + f.StackTrace);
        }
    }
    
    
    
    private void doWork_01()
    {
        try
        {
            this.ns = new NetworkStream(this.cltSocket);
            this.br = new BinaryReader(this.ns);
            this.wr = new BinaryWriter(this.ns);
            readyToRecv = true;
            this._lastSocketRead = toUnixTime(DateTime.Now);
        }
        catch
        {
            Console.WriteLine(this._caller + "ERROR OPENING STREAMS.");
            readyToRecv = false;
        }
        
        while (this.readyToRecv)
        {
            
            bool _etxEncountered = false;

            MemoryStream currentMessage = new MemoryStream();
            byte buf = (byte)0;

            while (!_etxEncountered)
            {
                try
                {
                    buf = this.br.ReadByte();
                }
                catch (EndOfStreamException)
                {
                    Console.WriteLine(this._caller + "ERROR: END OF STREAM");
                    readyToRecv = false;
                    _etxEncountered = true;
                    break;
                }
                catch (ObjectDisposedException)
                {
                    Console.WriteLine(this._caller + "ERROR: Stream is closed!");
                    readyToRecv = false;
                    _etxEncountered = true;
                    break;
                }
                catch (IOException i)
                {
                    Console.WriteLine(this._caller + "ERRORSTACK: IOException!" + i.StackTrace);
                    
                    //if the ReeceiveTimeout is reached an IOException will be raised...
                    /// with an InnerException of type SocketException an ErrorCode 10060
                    var socketExpert = i.InnerException as SocketException;
                    if (socketExpert.ErrorCode != 10060)
                    {   
                        Console.WriteLine(this._caller + "ERROR: IOException!" + socketExpert.ErrorCode);
                        readyToRecv = false;
                        _etxEncountered = true;
                    }
                    else
                    {                            
                        Console.WriteLine(this._caller + "Read: IOException for timeout! NOT DISCONNECTING");
                        readyToRecv = false;
                        _etxEncountered = true;
                        break;                            
                    }
                }
                catch (Exception f)
                {
                    Console.WriteLine(this._caller + "Unknown exception" + f.StackTrace);
                    var socketExpert = f.InnerException as SocketException;
                    Console.WriteLine(this._caller + "Error code number: " + socketExpert.ErrorCode);

                    readyToRecv = false;
                    _etxEncountered = true;
                }
                if (buf.Equals(0x03) == true)
                {
                    _etxEncountered = true;
                    break;
                }
                else if (buf.Equals(0x02) == false)
                {
                    try
                    {
                        currentMessage.WriteByte(buf);
                    }
                    catch (Exception)
                    {
                    }
                }
            }
            try { Thread.Sleep(10); }
            catch { }
        } // end while 

        EndWork();
    }
    
    public void EndWork()
    {
        try
        {
            readyToRecv = false;
            
            //close streams  
            this.br.BaseStream.Flush();
            this.br.Close();
            this.br.Dispose();
           
            this.wr.Flush();
            this.wr.Close();
            this.wr.Dispose();

            this.ns.Flush();
            this.ns.Close();
            this.ns.Dispose();

            
            this.cltSocket.Shutdown(SocketShutdown.Both);
            //this.cltSocket.Disconnect(true);
            this.cltSocket.Close();
            this.cltSocket.Dispose();
            this.cltSocket = null;                

            Console.WriteLine(this._caller + "GOODBYE...");
            try
            {
                this.workerThread.Join(1000);
                if (this.workerThread.IsAlive)
                {
                    this.workerThread.Abort();
                }
            }
            catch { }
            this.workerThread = null;
        }
        catch
        {
            this.readyToRecv = false;
            this.workerThread = null;
        }
        return;
    }
}

感谢任何帮助。

【问题讨论】:

  • "我似乎无法关闭套接字连接。"这是什么意思?你有例外吗?那是什么异常?你得到一个编译器错误吗?请解释会发生什么
  • 套接字连接仍然打开,另一端可以发送数据,我的线程即使在第一个 30 秒后仍然接收字节并进入 IOException。
  • 是socket没有关闭还是Backgroundworker没有关闭。尝试从 cmd.exe >Netstat -a 并检查端口号的状态以检查套接字的状态。
  • 套接字没有关闭。在 netstat -ao 中,我仍然看到客户端正在连接。在端口 5000 上建立连接;但是,在我的日志中,线程正在被处理。
  • @jdweng:你为我指明了正确的方向。有一个线程没有正确处理。所以,代码永远不会结束。感谢您指出问题。我不确定如何将您的评论标记为答案。

标签: c# sockets synchronous ioexception


【解决方案1】:

这段代码似乎有很多问题。

我认为问题的原因是您试图在工作线程上加入工作线程。 doWork_01 在工作线程上运行,因此EndWork 也将在工作线程上运行。这相当于调用Thread.CurrentThread.Join(),只会死锁。这种死锁可能会使您的进程保持活动状态,并可能导致不释放套接字等问题。

我认为这里没有什么理由尝试使用多个线程。原来的线程只是启动了worker,什么也不做。我建议删除所有线程,只对套接字使用局部变量,并使用using 确保它被释放。

要正确退出进程,请使用Environment.Exit(0);Application.Exit 或仅从 Main 返回。

【讨论】:

    【解决方案2】:

    我有一个线程没有碰到 Socket.Shutdown 和 socket.close。感谢 jdweng 向我指出这一点。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2014-12-15
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多