ソケット接続
func connect() { print("ソケット接続") var inputStream : NSInputStream! var outputStream : NSOutputStream! var readStream : Unmanaged? var writeStream : Unmanaged ? 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() }
この辺りは用途で大きく変わらないかと。
受信用と送信用にそれぞれ作成していてinputStreamが受信用、outputStreamが送信用になります。通常はクラスのメンバとして保持します。
serverAddress、port番号はサーバ側で指定された値を使用します。
また実装によっては委譲先(delegate)を変えることがあるかも。
ソケット切断
/** 接続の切断処理を行う */ 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) }
順番を守らなかったりすると予期せぬエラーが発生する可能性があります。
ソケットのハンドルイベント
/** ストリームの状態が変化した時に呼ばれる */ 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
主にサーバ側から通信が遮断された時に呼ばれます。こちらも切断処理を行い場合によっては再接続処理を行います
ちょっと長くなったのでここまで
続きは以下
データ送信
データ受信
まとめ