半关闭TcpClient

时间:2016-03-25 19:21:23

标签: c# .net tcpclient

我在半关闭TcpClient时遇到了严重问题。我想做的是:

在客户端:

  1. 发送消息
  2. 关闭底层套接字以进行发送
  3. 收到回复
  4. 关闭底层套接字以供阅读(或者,此时,只需将其关闭)
  5. 在服务器上:

    1. 收到消息
    2. 关闭底层套接字以供阅读
    3. 发送回复
    4. 关闭底层套接字以进行写入(或者,此时,只需将其关闭)
    5. 但是,在客户端或服务器上的第2步之后,我无法使用TcpClient的流。 这是我的代码的一个非常简化的版本(没有异步调用,处理和清理,也使用StreamReader和StreamWriter而不是XmlSerializer):

              //initialize the connection between the server and the client
              var listener = new TcpListener(IPAddress.Any, 13546);
              listener.Start();
              var client = new TcpClient("127.0.0.1", 13546);
              var server = listener.AcceptTcpClient();
              listener.Stop();
      
              //CLIENT: send the message
              var cwriter = new StreamWriter(client.GetStream());
      
              cwriter.Write("client's message");
              cwriter.Flush();
      
              client.Client.Shutdown(SocketShutdown.Send);
      
              //SERVER: receive the message
              string msg;
              var sreader = new StreamReader(server.GetStream());
      
              msg = sreader.ReadToEnd();
      
              server.Client.Shutdown(SocketShutdown.Receive);
      
              //SERVER: send a response
              //Here the code fails on server.GetStream() - 
              //InvalidOperationException, apparently the whole connection is closed now
      
              var swriter = new StreamWriter(server.GetStream());
      
              swriter.Write(msg + " with server's response");
              swriter.Flush();
      
              server.Client.Shutdown(SocketShutdown.Send);
      
              //CLIENT: receive the message
              var creader = new StreamReader(client.GetStream());
      
              var response = creader.ReadToEnd();
      
              client.Client.Shutdown(SocketShutdown.Receive);
      

      有没有办法在不使用原始套接字的情况下执行此操作?有什么我错了吗?

1 个答案:

答案 0 :(得分:1)

问题是ReadToEnd读取数据直到流的末尾。通过发出Client.Shutdown,您实际上关闭了套接字,使其无法重用(至少在TCPClient的情况下)。这是GetStream()

的代码
public NetworkStream GetStream() {
    if(Logging.On)Logging.Enter(Logging.Sockets, this, "GetStream", "");
    if (m_CleanedUp){
        throw new ObjectDisposedException(this.GetType().FullName);        
    }
    if (!Client.Connected) {
        throw new InvalidOperationException(SR.GetString(SR.net_notconnected));
    }
    if (m_DataStream==null) {
        m_DataStream = new NetworkStream(Client, true);
    }
    if(Logging.On)Logging.Exit(Logging.Sockets, this, "GetStream", m_DataStream);
    return m_DataStream;
}

如您所见,由于关闭套接字而发生错误。

编辑:这是奇怪的奇怪,但我想我找到了它无法正常工作的原因。原因是Shutdown总是将整个套接字的标志设置为断开连接。即使我们实际上没有那样关闭它!如果我们在方法的开头保留流,我们就不会遇到这个问题,因为问题在于GetStream方法,它检查套接字的状态。但是当其他代码检查套接字状态时,我们可能会遇到一些错误。