Разъем закрывается без видимой причины

Я пытаюсь реализовать механизм Facebook X_FACEBOOK_PLATFORM SASL, чтобы я мог интегрировать чат Facebook с моим приложением через XMPP.

Вот код:

  var ak = "my app id";
  var sk = "access token";
  var aps = "my app secret";
  using (var client = new TcpClient())
  {
    client.Connect("chat.facebook.com", 5222);
    using (var writer = new StreamWriter(client.GetStream())) using (var reader = new StreamReader(client.GetStream()))
    {
      // Write for the first time
      writer.Write("<stream:stream xmlns=\"jabber:client\" xmlns:stream=\"http://etherx.jabber.org/streams\" version=\"1.0\" to=\"chat.facebook.com\"><auth xmlns=\"urn:ietf:params:xml:ns:xmpp-sasl\" mechanism=\"X-FACEBOOK-PLATFORM\" /></stream:stream>");
      writer.Flush();
      Thread.Sleep(500);
      // I am pretty sure following works or at least it's not what causes the error
      var challenge = Encoding.UTF8.GetString(Convert.FromBase64String(XElement.Parse(reader.ReadToEnd()).Elements().Last().Value)).Split('&').Select(s => s.Split('=')).ToDictionary(s => s[0], s => s[1]);
      var response = new SortedDictionary<string, string>() { { "api_key", ak }, { "call_id", DateTime.Now.Ticks.ToString() }, { "method", challenge["method"] }, { "nonce", challenge["nonce"] }, { "session_key", sk }, { "v", "1.0" } };
      var responseString1 = string.Format("{0}{1}", string.Join(string.Empty, response.Select(p => string.Format("{0}={1}", p.Key, p.Value)).ToArray()), aps);
      byte[] hashedResponse1 = null;
      using (var prov = new MD5CryptoServiceProvider()) hashedResponse1 = prov.ComputeHash(Encoding.UTF8.GetBytes(responseString1));
      var builder = new StringBuilder();
      foreach (var item in hashedResponse1) builder.Append(item.ToString("x2"));
      var responseString2 = Convert.ToBase64String(Encoding.UTF8.GetBytes(string.Format("{0}&sig={1}", string.Join("&", response.Select(p => string.Format("{0}={1}", p.Key, p.Value)).ToArray()), builder.ToString().ToLower()))); ;
      // Write for the second time
      writer.Write(string.Format("<response xmlns=\"urn:ietf:params:xml:ns:xmpp-sasl\">{0}</response>", responseString2));
      writer.Flush();
      Thread.Sleep(500);
      MessageBox.Show(reader.ReadToEnd());
    }
  }

Я сократил и сократил код настолько, насколько это возможно, потому что я думаю, что моя реализация SASL (работает ли она или нет, у меня еще не было возможности протестировать ее) не является причиной ошибки.

Я получаю следующее исключение: мне не удалось прочитать данные из транспортного соединения: установленное соединение было прервано программным обеспечением на вашем хост-компьютере. 10053 System.Net.Sockets.SocketError.ConnectionAborted

Это происходит каждый раз, когда я пытаюсь читать с clientПоток во второй раз. Как вы можете видеть, я приостановил поток здесь, чтобы у сервера Facebook было достаточно времени, чтобы ответить мне, но раньше я использовал асинхронный подход и столкнулся с точно такой же вещью, поэтому я решил сначала попробовать его синхронно. В любом случае, фактическая реализация механизма SASL на самом деле не должна вызывать это, потому что, если я не пытаюсь сразу же аутентифицироваться, но отправляю запрос, чтобы посмотреть, какие механизмы использует сервер, и выбираю этот механизм в другом цикле чтения и записи, он терпит неудачу, но когда я сразу отправляю XML выбора механизма, он работает и не работает в любую секунду, которую я отправляю.

Таким образом, вывод следующий: я открываю сокетное соединение, пишу в него, читаю из него (первое чтение работает как синхронно, так и асинхронно), пишу в него во второй раз и пытаюсь прочитать из него во второй раз, и вот оно всегда выходит из строя. Очевидно, что проблема связана с самим сокетным соединением. Я пытался использовать новый StreamReader для второго чтения, но безрезультатно. Это довольно неприятно, так как я действительно хотел бы реализовать фасад над NetworkStream с событием "Получено" или что-то вроде Send(string data, Action<string> responseProcessor) чтобы получить некоторое удобство при работе с этим потоком, у меня уже была реализация, но она также не удалась при втором чтении.

Спасибо за ваши предложения.

Изменить: Вот код фасада над NetworkStream. То же самое происходит при использовании этого асинхронного подхода, но пару часов назад он работал, но для второго ответа возвращалась та же строка, что и для первого. Я не могу понять, что я изменил за это время и как.

public void Send(XElement fragment)
{
  if (Sent != null) Sent(this, new XmppEventArgs(fragment));
  byte[] buffer = new byte[1024];
  AsyncCallback callback = null;
  callback = (a) => 
  {
    var available = NetworkStream.EndRead(a);
    if (available > 0)
    {
      StringBuilder.Append(Encoding.UTF8.GetString(buffer, 0, available));
      NetworkStream.BeginRead(buffer, 0, buffer.Length, callback, buffer);
    }
    else
    {
      var args = new XmppEventArgs(XElement.Parse(StringBuilder.ToString()));
      if (Received != null) Received(this, args);
      StringBuilder = new StringBuilder();
      // NetworkStream.BeginRead(buffer, 0, buffer.Length, callback, buffer);
    }
  };
  NetworkStream.BeginRead(buffer, 0, buffer.Length, callback, buffer);
  NetworkStreamWriter.Write(fragment);
  NetworkStreamWriter.Flush();
}

1 ответ

Решение

reader.ReadToEnd() call потребляет все до конца потока, то есть до тех пор, пока TCP-соединение не будет закрыто.

Другие вопросы по тегам