ソケット接続
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
主にサーバ側から通信が遮断された時に呼ばれます。こちらも切断処理を行い場合によっては再接続処理を行います
ちょっと長くなったのでここまで
続きは以下
データ送信
データ受信
まとめ