我目前正在开发一个需要通过套接字连接与MQTT服务器通信的应用程序。由于System.Net.Sockets API在从WiFi网络切换到3G网络时往往行为不端(实际上这种情况发生了很多)我决定尝试使用CFStream API。这样做我遇到了几个问题,如下所示。
当我在其中一个流上调用Open()时,用CreatePairWithSocketToHost
创建一对流会使应用程序崩溃。
CFStream.CreatePairWithSocketToHost(GetEndPoint(), out mReadStream, out mWriteStream);
mReadStream.EnableEvents(CFRunLoop.Current, CFRunLoop.CFDefaultRunLoopMode);
mWriteStream.EnableEvents(CFRunLoop.Current, CFRunLoop.CFDefaultRunLoopMode);
mReadStream.Open();
mWriteStream.Open();
无论我是否呼叫EnableEvents()
,都会发生崩溃。例外是:
[ERROR] FATAL UNHANDLED EXCEPTION: MonoTouch.CoreFoundation.CFException: The operation couldn’t be completed. Cannot allocate memory
at MonoTouch.CoreFoundation.CFStream.CheckError () [0x0000f] in /Developer/MonoTouch/Source/monotouch/src/shared/CoreFoundation/CFStream.cs:236
at MonoTouch.CoreFoundation.CFStream.Open () [0x00040] in /Developer/MonoTouch/Source/monotouch/src/shared/CoreFoundation/CFStream.cs:248
at TestCfNework.RootViewController.TestCreatePairToHost () [0x00041] in /Users/adrian/Projects/TestCfNework/TestCfNework/RootViewController.cs:79
at TestCfNework.RootViewController.ViewDidLoad () [0x00000] in /Users/adrian/Projects/TestCfNework/TestCfNework/RootViewController.cs:24
at MonoTouch.UIKit.UIWindow.MakeKeyAndVisible () [0x00008] in /Developer/MonoTouch/Source/monotouch/src/UIKit/UIWindow.g.cs:124
at TestCfNework.AppDelegate.FinishedLaunching (MonoTouch.UIKit.UIApplication app, MonoTouch.Foundation.NSDictionary options) [0x0002e] in /Users/adrian/Projects/TestCfNework/TestCfNework/AppDelegate.cs:32
at MonoTouch.UIKit.UIApplication.Main (System.String[] args, System.String principalClassName, System.String delegateClassName) [0x0004c] in /Developer/MonoTouch/Source/monotouch/src/UIKit/UIApplication.cs:38
at TestCfNework.Application.Main (System.String[] args) [0x00000] in /Users/adrian/Projects/TestCfNework/TestCfNework/Main.cs:17
通过首先创建并连接CreatePairWithSocket
来创建一对包含CFSocket
的流,允许Open()
继续而不会崩溃,但CanAcceptBytesEvent
永远不会被触发,{{1始终为false,任何写入尝试都会因超时而失败。
CanAcceptBytes()
使用mSocket = new CFSocket(AddressFamily.InterNetwork,
SocketType.Stream,
ProtocolType.Tcp,
CFRunLoop.Current);
mSocket.ConnectEvent += delegate {
Console.WriteLine("Socket connected");
CFStream.CreatePairWithSocket(mSocket, out mReadStream, out mWriteStream);
mReadStream.EnableEvents(CFRunLoop.Current, CFRunLoop.CFDefaultRunLoopMode);
mWriteStream.EnableEvents(CFRunLoop.Current, CFRunLoop.CFDefaultRunLoopMode);
mReadStream.Open();
mWriteStream.Open();
mWriteStream.CanAcceptBytesEvent += delegate {
Console.WriteLine("Write stream can now accept data");
};
mWriteStream.ErrorEvent += delegate {
Console.WriteLine(mWriteStream.GetError());
};
};
mSocket.Connect(GetEndPoint(), 0);
创建一对流是唯一一个实际生成一对我可以使用的流:开放不会崩溃,我可以分别写入和读取。
API在模拟器和实际设备上都以这种方式运行。那么,这是我做错了吗?这是MonoTouch问题吗?这是CFStream API本身的错误吗?
MonoTouch版本:6.0.1。 XCode版本:4.5。
答案 0 :(得分:1)
我在MonoMac / MonoTouch中写了大部分CFNetwork代码,所以我希望能够帮助你: - )
您的代码对我来说没问题。它适用于MonoMac(Mac上的独立Cocoa应用程序),但我发现MonoTouch存在同样的问题。打开读取流有时会起作用,有时候不会打开写入流总是失败。
CFStream.CreatePairWithSocketToHost()
来电CFStreamCreatePairWithSocketToCFHost()
。
添加新的重载版本后:
public static void CreatePairWithSocketToHost (string host, int port,
out CFReadStream readStream,
out CFWriteStream writeStream)
调用CFStreamCreatePairWithSocketToHost()
,现在工作正常。
我刚看了一眼,发现了问题,很快就会解决它。
关于你的第二个问题,CFSocket API在内部遇到相同的代码路径,所以它也受到这个bug的影响。
答案 1 :(得分:0)