如何将TCPClient和NetworkStream移植到Silverlight?

时间:2011-04-10 12:29:11

标签: .net silverlight sockets tcpclient networkstream

为什么Silverlight中缺少TCPClient和NetworkStream?
是否有任何已知的TCPClient和NetworkStream端口到Silverlight?
如果没有,我是否可以将源代码从.NET 4运行时复制到我自己的库中? 如果没有,我如何开始将这些类移植到Silverlight?

2 个答案:

答案 0 :(得分:2)

Networking in Silverlight存在一些限制,主要与Silverlight在浏览器中的沙箱中运行(例如跨域策略,端口限制等)有关,这可以部分通过使用OOB应用程序来解决放松的安全模型)。

但是,Silverlight为Sockets提供了一些支持,并且有一些高级客户端实现,例如this one

这些可能是开始构建自己的端口的良好基础,因为我认为.NET 4运行时许可证不包括分叉源代码的权利,甚至不包括将它们移植到Silverlight。

答案 1 :(得分:1)

我知道这个问题很老,但对我来说非常有用。 谢谢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
    }
}