관리 메뉴

HAMA 블로그

[Swift 3 ] 가장 쉬운 소켓 (TCP) 통신 방법을 찾고 계신가요? 본문

아이폰 (IOS)

[Swift 3 ] 가장 쉬운 소켓 (TCP) 통신 방법을 찾고 계신가요?

[하마] 이승현 (wowlsh93@gmail.com) 2016. 11. 24. 12:59


iOS 앱개발과 스위프트라는 언어를  처음 시작하면서 소켓 통신 관련해서 좀 애를 먹고있다. 기능은 인증/푸쉬/전광판/사용히스토리/지도/음성인식/설정 정도인  prototype 앱을 2주안에 개발해야하는 촉박한 일정 탓에 약간 멘붕상태에서 봉주르,코코아,파운데이션,Object-C, Swift 2.0 / 3.0 , NSStream, 게임키트 같이 처음 시작하는 사람이 보기에 너무 많은 정보 속에 과연 어떻게 하면 쉽고 빠르게 개발을 할 수 있을까 하며 이것저것 뒤적뒤적 거렸는데 먼저 NSStream 을 이용해 봤다. 이게 가장 적합해 보였고 대략 코딩은 이러하다. (참고로 가장 쉬운 방법은 글 중간에 있으니..인내를)


let addr = "192.168.1.45" let port = 22090 var inp : InputStream? var out : OutputStream? Stream.getStreamsToHost(withName: addr, port: port, inputStream: &inp, outputStream: &out) let inputstream = inp! let outputstream = out! inputstream.open() outputstream.open() outputstream.write(query,maxLength:query.characters.count) let buffersize = 1024 var buffer = [UInt8](repeating :0, count : buffersize) let bytesRead = inputstream.read(&buffer, maxLength: buffersize) var getString : NSString? if(bytesRead>0){ getString = NSString(bytes: buffer, length: bytesRead, encoding: String.Encoding.utf8.rawValue) return getString as! String }else{ return PKConst.connection_fail } inputstream.close() outputstream.close()

이렇게 자바IO 스타일로 코딩을 했는데 뭐 주고 받는것은 문제가 없으나 문서를 다시 읽어 본 결과  Streme 은 ( 참고로 swift 3.0 에서는 NS 같은 쓸데없는 prefix 가 빠졌다. 속이 다 시원하다.)  아래처럼 RunLoop 등 비동기식으로  써야 맞는거다.

 inputstream.delegate = self

 outputstream.delegate = self

        

 inputstream.schedule(in: RunLoop.current, forMode: RunLoopMode.defaultRunLoopMode)
 outputstream.schedule(in: RunLoop.current, forMode: RunLoopMode.defaultRunLoopMode)

NSStreamEventOpenCompleted
NSStreamEventHasSpaceAvailable
NSStreamEventHasBytesAvailable
NSStreamEventEndEncountered
NSStreamEventErrorOccurred

이런게 있는거 봐선 느낌상 Reactor 패턴식 (멀티플렉싱) 으로 통신하는게 정석인듯 싶은데 점점 골치 아파 오기 시작한다. Object-C 는 완전한 예제들이 있는듯한데 개인적으로 Object-C 를 굉장히 싫어하며 , 이 와중에 공부해서 포팅하고 싶지도 않다. 

참고로 swift 3.0 으로 구현된 Stream 예제는 대략 다음과 같으나 확실치 않고 추천하고 싶지 않다.
(동기적,비동기적 각각 완전한 예제를 발견하지 못했다. 좋은 예제를 가지고 계신분은 홍익인간의 정신으로 공유좀 ㅜㅜ ) 


import Foundation class Connection: NSObject, StreamDelegate { var host:String? var port:Int? var inputStream: InputStream? var outputStream: OutputStream? var sneds = Queue<String>() func connect(host: String, port: Int) { self.host = host self.port = port Stream.getStreamsToHost(withName:host, port: port, inputStream: &inputStream, outputStream: &outputStream) if inputStream != nil && outputStream != nil { // Set delegate inputStream!.delegate = self outputStream!.delegate = self // Schedule inputStream!.schedule(in: .main, forMode: RunLoopMode.defaultRunLoopMode) outputStream!.schedule(in: .main, forMode: RunLoopMode.defaultRunLoopMode) print("Start open()") // Open! inputStream!.open() outputStream!.open() } } func stream(aStream: Stream, handleEvent eventCode: Stream.Event) { if aStream === inputStream { switch eventCode { case Stream.Event.errorOccurred: print("input: ErrorOccurred: ") case Stream.Event.openCompleted: print("input: OpenCompleted") case Stream.Event.hasBytesAvailable: print("input: HasBytesAvailable") // Here you can `read()` from `inputStream` default: break } } else if aStream === outputStream { switch eventCode { case Stream.Event.errorOccurred: print("output: ErrorOccurred: ") case Stream.Event.openCompleted: print("output: OpenCompleted") case Stream.Event.hasSpaceAvailable: print("output: HasSpaceAvailable") // Here you can write() to `outputStream` default: break } } } } class SimpleSocketUtil { static func checkID ( id : String) -> Bool { let conn = Connection() conn.connect(host: "192.168.1.45", port: 22090) return true } }

여튼 이러한 와중에  나를 구원해 준것이 있었으니 SwiftSocket!!   아래를 참고하시라. 


SwiftSocket 

https://github.com/swiftsocket/SwiftSocket 

무지무지 하기 쉽다.


1. 디펜던시 추가

ytcpsocket.c / ytcpsocket.swift / ysocket.swift  이 3개를 자신의 프로젝트에 추가시킨다.


2. Connection 예제 

func connect(query : String){

   let addr = "192.168.1.45"
   let port = 22090
        
   let client:TCPClient = TCPClient(addr: "192.168.1.45", port: 22090)
   var (success,errmsg)=client.connect(timeout: 1)
   if success{
            var (success,errmsg)=client.send(str:"GET / HTTP/1.0\n\n" )
            if success{
                let data=client.read(1024*10)
                if let d=data{
                    if let str=String(bytes: d, encoding: String.Encoding.utf8){
                        print(str)
                    }
                }
            }else{
                print(errmsg)
            }
   }else{
     print(errmsg)
   }  
}
 이 보다 더 간단할 수 있겠는가? 

API 예제들을 간단히 살펴보면 아래와 같다.

api usage

create client socket

//create a socket connect to www.apple.com and port at 80
var client:TCPClient = TCPClient(addr: "www.apple.com", port: 80)

connect with timeout

var (success, errmsg) = client.connect(timeout: 10)

send data

var (success, errmsg) = client.send(str:"GET / HTTP/1.0\n\n")
//or you can send binnary data
//socket.send(data:[Int8])

read data

var data = client.read(1024*10) //return optional [Int8]

close socket

var (success, errormsg) = client.close()

create servert socket

var server:TCPServer = TCPServer(addr: "127.0.0.1", port: 8080)

listen

var (success, msg) = server.listen()

accept

var client = server.accept() //now you can use client socket api to read and write

client socket example

//创建socket
var client:TCPClient = TCPClient(addr: "www.apple.com", port: 80)
//连接
var (success, errmsg) = client.connect(timeout: 1)
if success {
    //发送数据
    var (success, errmsg) = client.send(str:"GET / HTTP/1.0\n\n" )
    if success {
        //读取数据
        var data = client.read(1024*10)
        if let d = data {
            if let str = String.stringWithBytes(d, length: d.count, encoding: NSUTF8StringEncoding){
                println(str)
            }
        }
    }else {
        println(errmsg)
    }
} else {
    println(errmsg)
}

server socket example (echo server)

func echoService(client c:TCPClient) {
    println("newclient from:\(c.addr)[\(c.port)]")
    var d = c.read(1024*10)
    c.send(data: d!)
    c.close()
}
func testserver(){
    var server:TCPServer = TCPServer(addr: "127.0.0.1", port: 8080)
    var (success, msg) = server.listen()
    if success {
        while true {
            if var client = server.accept() {
                echoService(client: client)
            } else {
                println("accept error")
            }
        }
    } else {
        println(msg)
    }
}




Comments