【问题标题】:c# tcp socket receive loop break logicc# tcp socket接收循环中断逻辑
【发布时间】:2015-06-08 11:05:39
【问题描述】:

我正在编写一个 c# tcp 套接字服务器,它将从 c++ 套接字应用程序接收数据。现在一切正常,除了我的 c# 接收线程中的循环中断逻辑。我在下面显示一个代码 sn-p 以便更好地解释。

    //creating socket object
    private Socket socket = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);

    //accepting connections
     TcpListener tcpListener = new TcpListener(ipAdd, iPort);
     tcpListener.Start();
     this.socket = tcpListener.AcceptSocket();
     tcpListener.Stop();        

    //code for 
    //public byte[] ReceiveMessage(ref int intError)
    while (this.socket.Available > 0)
    {
      try
      {
        intBytesReceived = this.socket.Receive(byteReceivedBuffer, byteReceivedBuffer.Length, SocketFlags.None);
        Thread.Sleep(100);
      }
      catch (SocketException ex)
      {
        string str = ex.Message;
        intError = -1;
      }
    }

下面是连续接收数据的线程函数

  //Thread to continuous poll data from client
  //Now this has been done as I need to receive multiple messages from client after server ack received at client side. 

  //Thread quit logic based on manual stop button press
  //I want to have one more logic by which thread will exit if the connection closed by client socket. i.e. a call of 'CloseSocket()' function from c++ application.     

  if (TCPServerListener.serverStatus == TCPServerListener.ServerStatus.Stopped)
  {
    tcpCommunication.Disconnect();
    break;
  }

  while(true)
  {
    int sockError = 0;
    byte[] byteData = tcpCommunication.ReceiveMessage(ref sockError);
    if (byteData.Length > 0)
    {
      ParseBuffer(byteData, ref tcpCommunication);
    }
  }

为了获得更好的图片,我正在使用我的通信协议。

  1. 客户端启动连接。发送数据集
  2. 服务器接收、处理、发送确认
  3. 客户端处于暂停模式,直到它收到来自服务器的确认,但没有关闭套接字
  4. 这一次,服务器不会收到任何消息,但接收线程应该处于活动状态,因为我正在为每个客户端创建一个线程。
  5. 一旦客户端收到确认,它将继续发送下一个数据
  6. 服务器接收线程现在将获取数据并进行相应处理
  7. 一旦客户端关闭其套接字,服务器接收线程也应该关闭

我能够完成我的工作,但服务器接收器线程没有关闭。那是我的问题。任何建议都会有很大帮助。

【问题讨论】:

  • 也许你应该对 sockError 做点什么?而且很多时候如果接收到的数据长度为负数,也是连接关闭的标志。取决于 tcpCommunication 实际上是什么。这样你就可以跳出线程了。
  • 嗯,我在考虑 15 秒或更多的超时值。因为我的客户不会等待超过 3 秒的单次数据发送和确认接收。因此,如果服务器连续 15 秒没有收到任何数据,它将假定客户端已关闭连接。但这对于实时应用程序来说听起来不错吗?
  • 既然 TCP 已经告诉你连接是否已经关闭,为什么还要超时呢?除非客户端有可能只是闲逛而不发送任何东西,而不是关闭套接字(崩溃也会导致套接字关闭)。
  • 如何查看客户端是否关闭了套接字?那是我的实际问题。客户端连接关闭时没有触发 SocketException / 异常。
  • 这取决于您使用的是什么。 tcpCommunication 可能会告诉你,但我不可能说,因为我不知道它是什么类型的对象。在最低级别Socket 将有关于打开或关闭的信息,通常读取操作将在连接关闭时返回

标签: c# sockets tcp


【解决方案1】:

根据我的经验,当您使用 TCP 服务器/客户端套接字关系时,TCP 服务器套接字端将处于由标志控制的线程中,以继续侦听直到被告知停止(您的 cmets 提到了停止按钮)。

客户端运行直到所有数据完成,或者控制服务器端的同一标志被触发。

当客户端连接时,我会将 AcceptSocket 存储到一个列表中。当我这样做时,我有一个自定义类,它接受 AcceptSocket,并且自定义类有计数器,用于计算多少条消息,或者从这个客户端发送/接收的字节数。

// This should be a threaded method if you're using a button to stop
private void StartTcpListener()
{
    List<ClientClass> clientClassList = new List<ClientClass>();

    TcpListener tcpListener = new TcpListener(ipAdd, iPort);
    tcpListener.Start();

    while (keepListening)
    {
        Socket socket = tcpListener.AcceptSocket();

        // Create a client object and store it in a list
        ClientClass clientClass = new ClientClass(socket);
        clientClassList.Add(clientClass);

        // This method would start a thread to read data from the accept socket while it was connected.
        clientClass.Start();
    }

    foreach (ClientClass client in clientClassList)
    {
        // This method would stop the thread that reads data from the accept socket and close the accept socket
        client.Stop();
    }
    tcpListener.Stop();
}

对于客户端,当从客户端接受套接字读取时,这将是线程控制的,并且线程被中止或客户端关闭其结束导致读取返回 -1 表示读取的字节数。

// Threaded method
private void Receive()
{
    // Don't know how much of a buffer you need
    byte[] dataIn = byte[1000];
    while (acceptSocket.Connected)
    {
        // Exception handling so you either end the thread or keep processing data
        try
        {
            int bytesRead = acceptSocket.Read(dataIn);
            if (bytesRead != -1)
            {
                // Process your data
            }
            else
            {
                // -1 Bytes read should indicate the client shutdown on their end
                break;
            }
        }
        catch(SocketException se)
        {
            // You could exit this loop depending on the SocketException
        }
        catch(ThreadAbortException tae)
        {
            // Exit the loop
        }
        catch (Exception e)
        {
            // Handle exception, but keep reading for data
        }
    }

    // You have to check in case the socket was disposed or was never successfully created
    if (acceptSocket != null)
    {
        acceptSocket.Close();
    }
}

// This is the stop method if you press your stop button
private void Stop()
{
    // Aborts your read thread and the socket should be closed in the read thread.  The read thread should have a ThreadState.Stopped if the while loop was gracefully ended and the socket has already been closed
    if (readThread != null && readThread.ThreadState != ThreadState.Stopped)
    {
        readThread.Abort();
    }
}

我认为这是我之前所做工作的基础。我确信现在有“更清洁”的方法可以做到这一点。这是几年前我用来实现 TCP 客户端/服务器套接字对象的时候。

希望这会有所帮助...

【讨论】:

  • 感谢您的代码 sn-p。我不明白你用这个'while(acceptSocket.Connected)'检查哪个套接字?这里的acceptSocket应该是你收到连接的TcpListener.AcceptSocket对象吧?不是吗?
  • 我放的另一个代码是我的示例,也应该注意按下手动停止按钮时的情况。对 acceptSocket.Read() 的调用是否阻塞?
  • 是的,我的 sn-p 中的 acceptSocket 来自 TcpListener.AcceptSocket。在我的代码 sn-ps 中,第一个 sn-p 是服务器类中的方法,第二个 sn-p 是客户端类中的方法。我为 TcpListener 接收到的每个 AcceptSocket 创建客户端,然后只监听另一个客户端连接。此 SO 线程还说明了侦听多个客户端 (stackoverflow.com/questions/19387086/…)。
猜你喜欢
  • 1970-01-01
  • 2011-06-05
  • 2018-09-17
  • 2020-11-24
  • 2017-09-04
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多