【发布时间】:2012-04-27 20:16:30
【问题描述】:
我正在 Windows 8 Consumer Preview 中编写 Metro 应用程序。
但是,我无法在 .NET 4.5 中使用 TcpClient,似乎没有添加程序集引用的地方。
http://msdn.microsoft.com/en-us/library/1612451t(v=vs.110).aspx
【问题讨论】:
标签: windows windows-8 .net-4.5
我正在 Windows 8 Consumer Preview 中编写 Metro 应用程序。
但是,我无法在 .NET 4.5 中使用 TcpClient,似乎没有添加程序集引用的地方。
http://msdn.microsoft.com/en-us/library/1612451t(v=vs.110).aspx
【问题讨论】:
标签: windows windows-8 .net-4.5
metro 端不支持 TcpClient。您可以改用 StreamSocket 类。 Here 是一个关于如何使用它来创建 TCP Socket、建立连接、发送和接收数据的示例。示例在 JS 和 C++ 中,但相同的类适用于 C#。
【讨论】:
最终,我们可能应该使用新的 Metro NET 东西。但是,如果移植大量代码并取决于您使用的 TcpClient 成员的数量,那么仅围绕 Metro 对象创建一个有限的实现可能还不错。我想快速将一堆代码快速移植到 Metro 上(只是为了尝试一些东西),所以我拼凑了一些看似可行但肯定不理想的东西。 (您最终会同步一些通常不受欢迎的异步方法。)
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using Windows.Networking;
using Windows.Networking.Sockets;
using Windows.Storage.Streams;
namespace MetroNetHelper
{
public class IPAddress // assumes IPv4 currently
{
public string IP_String;
public IPAddress() { }
public IPAddress(string IP) { IP_String = IP; }
public static IPAddress Broadcast { get { return new IPAddress("255.255.255.255"); } }
public static IPAddress Parse(string IP) { return new IPAddress(IP); }
public static bool TryParse(string V, out IPAddress Addr)
{
try
{
Addr = IPAddress.Parse(V);
return true;
}
catch { Addr = null; return false; }
}
public HostName GetHostNameObject() { return new HostName(IP_String); }
public byte[] GetAddressBytes()
{
string[] Fields = IP_String.Split('.');
byte[] temp = new byte[4];
for (int i = 0; i < temp.Length; i++) temp[i] = byte.Parse(Fields[i]);
return temp;
}
}
public class IPEndPoint
{
public IPAddress Address;
public int Port;
public IPEndPoint() { }
public IPEndPoint(IPAddress Addr, int PortNum)
{
Address = Addr; Port = PortNum;
}
}
public class NetworkStream
{
private DataReader Reader;
private DataWriter Writer;
public void Set(StreamSocket HostClient)
{
Reader = new DataReader(HostClient.InputStream);
Reader.InputStreamOptions = InputStreamOptions.Partial;
Writer = new DataWriter(HostClient.OutputStream);
}
public int Write(byte[] Buffer, int Offset, int Len)
{
if (Offset != 0 || Len != Buffer.Length) throw new ArgumentException("Can only write whole byte array");
Writer.WriteBytes(Buffer);
Task Tk = Writer.StoreAsync().AsTask();
Tk.Wait();
return Buffer.Length;
}
public int Read(byte[] Buffer, int Offset, int Len)
{
if (Offset != 0 || Len != Buffer.Length) throw new ArgumentException("Can only read whole byte array");
Task<uint> Tk = Reader.LoadAsync((uint)Len).AsTask<uint>();
Tk.Wait();
uint Count = Tk.Result;
for (int i=0;i<Count;i++)
{
Buffer[i] = Reader.ReadByte();
}
return (int)Count;
}
public bool DataAvailable
{
get
{
return true; // Read() will still work if no data; could we do read ahead 1 byte to determine?
}
}
}
public class TcpClient
{
private StreamSocket sock;
public void Connect(IPEndPoint EndPt)
{
try
{
sock = new StreamSocket();
HostName Hst = EndPt.Address.GetHostNameObject();
Task Tsk = sock.ConnectAsync(Hst, EndPt.Port.ToString()).AsTask();
Tsk.Wait();
}
catch (Exception ex) { MetroHelpers.UnpeelAggregate(ex); }
}
public void Close()
{
sock.Dispose();
sock = null;
}
public NetworkStream GetStream()
{
var N = new NetworkStream();
N.Set(sock);
return N;
}
}
public static class MetroHelpers
{
public static void UnpeelAggregate(Exception Ex)
{
AggregateException Ag_Ex = Ex as AggregateException;
if (Ag_Ex == null) throw Ex;
if (Ag_Ex.InnerExceptions.Count > 0)
{
if (Ag_Ex.InnerExceptions.Count == 1) throw Ag_Ex.InnerExceptions[0];
StringBuilder Str = new StringBuilder();
foreach (Exception X in Ag_Ex.InnerExceptions)
{
Str.AppendLine(X.Message);
}
throw new Exception(Str.ToString(), Ag_Ex);
}
else throw Ag_Ex;
}
}
} // END NAMESPACE
这只是我早上做的又快又脏的事情。如果它可以帮助任何有想法的人,那就太好了。同样,我们很可能最好按照微软希望我们为 Metro 应用程序开发的方式。当他们不断改变红润的框架时,它只会变得令人沮丧。 (如果 Xamarin 可以在 iOS/Android/etc 上保持一致的框架,为什么不能在自己的操作系统上使用 MS!)
【讨论】: