Как перенести TCPClient и NetworkStream в Silverlight?

Почему TCPClient и NetworkStream отсутствуют в Silverlight?
Существуют ли какие-либо известные переносы TCPClient и NetworkStream в Silverlight?
Если их нет, могу ли я скопировать исходный код из среды выполнения .NET 4 в свою собственную? библиотека?
Если нет, то как начать перенос этих классов в Silverlight?


person the_drow    schedule 10.04.2011    source источник


Ответы (2)


Существуют некоторые ограничения на работу в сети в Silverlight, главным образом из-за того, что Silverlight работает в изолированной программной среде в браузере (например, междоменная политика, ограничения портов и т. д., которые можно частично решить с помощью приложений OOB с упрощенной моделью безопасности).

Однако Silverlight обеспечивает некоторую поддержку сокетов, и есть некоторые высокоуровневые реализации клиентов, такие как этот.

Возможно, это хорошая основа для того, чтобы начать создавать свои собственные порты, потому что я полагаю, что лицензия среды выполнения .NET 4 не включает право на разветвление исходных кодов, даже на их портирование в Silverlight.

person jCoder    schedule 10.04.2011
comment
Спасибо, но обратите внимание на первый вопрос. С какой стати их нет? - person the_drow; 11.04.2011
comment
Я предполагаю, что интеграция WCF/WebService, HttpWebRequest, WebClient казалась достаточной в первых версиях, а низкоуровневая сеть потребовалась позже разработчиками, когда ограничения стали более разочаровывающими. Но я думаю, что только у команды разработчиков Silverlight будет 100% ответ на эту часть вашего вопроса;) - person jCoder; 11.04.2011

Я знаю, что этот вопрос старый, но он был очень полезен для меня. Спасибо jCoder, я действительно создал решение на основе вашей связанной статьи. http://weblogs.asp.net/mschwarz/archive/2008/03/07/silverlight-2-and-sockets.aspx

Я сделал несколько изменений. В частности, в этом TcpClient есть утечка памяти, которую я устранил путем удаления ScoketAsyncEventArgs, созданного при отправке и получении. Здесь может быть лучший способ, но он сработал, поэтому я перестал искать. Без этого создается впечатление, что ссылка сохраняется из-за подписки на событие. Открыт для предложений.

Я использовал это только с BinaryReader и BinaryWriter, ваш пробег может отличаться от других читателей.

using System;
using System.Net;
using System.Net.Sockets;
using System.Threading;

namespace IBApi
{
    public class TcpClientSl
    {
      private const int Receive = 1;
      private const int Send = 0;

      private bool isConnected = false;

      private Socket socket;
      private DnsEndPoint endPoint;
      public NotifyStream socketStream;

      private static AutoResetEvent autoEvent = new AutoResetEvent(false);
      private static AutoResetEvent autoSendEvent = new AutoResetEvent(false);
      private static AutoResetEvent autoReceiveEvent = new AutoResetEvent(false);

      NLog.Logger logger = NLog.LogManager.GetCurrentClassLogger();

        public TcpClientSl(string host, int port)
        {
          logger.Trace("TcpClientSl(string {0}, int {1})", host, port);

          endPoint = new DnsEndPoint(host, port, AddressFamily.InterNetwork);

          socket = new Socket(AddressFamily.InterNetwork 
                      /* hostEndPoint.AddressFamily */, 
                      SocketType.Stream, ProtocolType.Tcp);
          socketStream = new NotifyStream();
          socketStream.OnRead = ReadDelegate;
          socketStream.OnWrite = WriteDelegate;
        }

        int ReadDelegate (byte[] buffer, int offset, int count)
        {
          //logger.Trace("ReadDelegate (byte[] buffer, int {0}, int {1})", offset, count);
            // Prepare receiving.
            SocketAsyncEventArgs args = new SocketAsyncEventArgs();
            args.SetBuffer(buffer, 0, buffer.Length);
            args.Completed += new EventHandler<SocketAsyncEventArgs>(OnReceive);
            socket.ReceiveAsync(args);
            if (!autoReceiveEvent.WaitOne(TimeSpan.FromMinutes(5)))
            {
              logger.Error("Receive Timeout");
              //this.Disconnect();
            }
            args.Dispose();
            return args.BytesTransferred;
        }

        void WriteDelegate(byte[] buffer, int offset, int count)
        {
          //logger.Trace("WriteDelegate(byte[] buffer, int {0}, int {1})", offset, count);
          if (isConnected && socket.Connected)
          {
              SocketAsyncEventArgs args = new SocketAsyncEventArgs();
              args.SetBuffer(buffer, offset, count);
              args.UserToken = socket;
              args.RemoteEndPoint = endPoint;
              args.Completed += new EventHandler<SocketAsyncEventArgs>(OnSend);

              socket.SendAsync(args);

              if (!autoSendEvent.WaitOne(TimeSpan.FromMinutes(1)))
              {
                logger.Error("Send Timeout");
                //this.Disconnect();
              }
              args.Dispose();
          }
          else
              throw new SocketException((int)SocketError.NotConnected);
        }

        public void Connect()
        {

          logger.Trace("Connect()");
          SocketAsyncEventArgs args = new SocketAsyncEventArgs();

          args.UserToken = socket;
          args.RemoteEndPoint = endPoint;
          args.Completed += new EventHandler<SocketAsyncEventArgs>(OnConnect);

          socket.ConnectAsync(args);
          autoEvent.WaitOne();

          if (args.SocketError != SocketError.Success)
              throw new SocketException((int)args.SocketError);
        }

        public void Disconnect()
        {
          logger.Trace("Disconnect()");
          socket.Close();
        }

        #region Events

        private void OnConnect(object sender, SocketAsyncEventArgs e)
        {
          logger.Trace("OnConnect");
          autoEvent.Set();
          isConnected = (e.SocketError == SocketError.Success);
        }

        private void OnReceive(object sender, SocketAsyncEventArgs e)
        {
          //logger.Trace("OnReceive {0} bytes", e.BytesTransferred);
          if (e.BytesTransferred > 0)
          {
            autoReceiveEvent.Set();
          }
        }

        private void OnSend(object sender, SocketAsyncEventArgs e)
        {
          //logger.Trace("OnSend Bytes={0}", e.BytesTransferred);

          autoSendEvent.Set();

          if (e.SocketError == SocketError.Success)
          {
              if (e.LastOperation == SocketAsyncOperation.Send)
              {
              }
          }
          else
          {
              ProcessError(e);
          }
        }

        #endregion

        private void ProcessError(SocketAsyncEventArgs e)
        {
          logger.Trace("ProcessError");
          Socket s = e.UserToken as Socket;
          if (s.Connected)
          {
              try
              {
                  s.Shutdown(SocketShutdown.Both);
              }
              catch (Exception)
              {
              }
              finally
              {
                  if (s.Connected)
                      s.Close();
              }
          }

          throw new SocketException((int)e.SocketError);
        }

        #region IDisposable Members

        public void Dispose()
        {
          logger.Trace("Dispose");
          autoEvent.Close();
          autoSendEvent.Close();
          autoReceiveEvent.Close();
          if (socket.Connected)
              socket.Close();
        }

        #endregion
    }
}
person Duane McKinney    schedule 11.07.2014