ソケット接続
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 | func connect() { print( "ソケット接続" ) var inputStream : NSInputStream! var outputStream : NSOutputStream! var readStream : Unmanaged<cfreadstream>? var writeStream : Unmanaged<cfwritestream>? let serverAddress = "127.0.0.1" let serverPort = "53489" // 適当 // ソケット作成 CFStreamCreatePairWithSocketToHost( kCFAllocatorDefault, serverAddress, serverPort, &readStream, &writeStream) inputStream = readStream!.takeRetainedValue() as NSInputStream outputStream = writeStream!.takeRetainedValue() as NSOutputStream // ストリームイベントの委譲先 inputStream.delegate = self outputStream.delegate = self inputStream.scheduleInRunLoop( NSRunLoop.currentRunLoop(), forMode: NSDefaultRunLoopMode) outputStream.scheduleInRunLoop( NSRunLoop.currentRunLoop(), forMode: NSDefaultRunLoopMode) inputStream.open() outputStream.open() } </cfwritestream></cfreadstream> |
この辺りは用途で大きく変わらないかと。
受信用と送信用にそれぞれ作成していてinputStreamが受信用、outputStreamが送信用になります。通常はクラスのメンバとして保持します。
serverAddress、port番号はサーバ側で指定された値を使用します。
また実装によっては委譲先(delegate)を変えることがあるかも。
ソケット切断
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 | /** 接続の切断処理を行う */ func disConnect() { print( "ソケット切断" ) inputStream.delegate = nil outputStream.delegate = nil inputStream.close() outputStream.close() inputStream.removeFromRunLoop( NSRunLoop.currentRunLoop(), forMode: NSDefaultRunLoopMode) outputStream.removeFromRunLoop( NSRunLoop.currentRunLoop(), forMode: NSDefaultRunLoopMode) } |
順番を守らなかったりすると予期せぬエラーが発生する可能性があります。
ソケットのハンドルイベント
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 | /** ストリームの状態が変化した時に呼ばれる */ func stream(aStream: NSStream, handleEvent eventCode: NSStreamEvent) { if aStream === inputStream { // 入力ストリーム switch eventCode { case NSStreamEvent.ErrorOccurred: print( "input: ErrorOccurred: \(aStream.streamError?.description)" ) case NSStreamEvent.OpenCompleted: print( "input: OpenCompleted" ) case NSStreamEvent.HasBytesAvailable: print( "input: HasBytesAvailable" ) // 入力ストリーム読み込み可能 getResponse() case NSStreamEvent.EndEncountered: print( "input: EndEncountered" ) // サーバから切断された? disConnect() default : break } } else if aStream === outputStream { // 出力ストリーム switch eventCode { case NSStreamEvent.ErrorOccurred: print( "output: ErrorOccurred: \(aStream.streamError?.description)" ) case NSStreamEvent.OpenCompleted: print( "output: OpenCompleted" ) case NSStreamEvent.HasSpaceAvailable: print( "output: HasSpaceAvailable" ) print( "データ送信可能" ) isConnected = true case NSStreamEvent.EndEncountered: print( "output: EndEncountered" ) disConnect() default : break } } } |
委譲先のクラスで定義します。
NSStreamDelegateを継承すること。
上記ソースは受信用ストリームと送信用ストリームで処理を分けています。
以下はイベントの詳細です
ErrorOccurred
何かしらエラーが発生した時に呼ばれます(見たことないけど)再接続処理が必要かもしれません。
OpenCompleted
通信可能になった状態です。HasBytesAvailable
受信専用イベント。何かしら受信した時に呼ばれます。
一回のレスポンスで複数回データが分割されて受信することがあるので対応が必要になります。
HasSpaceAvailable
データが送信可能になった時に呼ばれます。ただし実際送信可能かどうか調べるときは送信時にoutputStream.hasSpaceAvailable プロパティを参照するようにした方が確実に動作します。
EndEncountered
主にサーバ側から通信が遮断された時に呼ばれます。こちらも切断処理を行い場合によっては再接続処理を行います
ちょっと長くなったのでここまで
続きは以下
データ送信
データ受信
まとめ