Swift 패키지 관리자를 사용한 Swift 용 소켓 프레임 워크. iOS, MacOS 및 Linux에서 작동합니다.
swift-5.1-RELEASE Toolchain ( 최신 릴리스에 필요한 최소 )swift-5.4-RELEASE Toolchain ( 권장 )메모:
iOS에서 UDP 서버를 작성하는 경우 몇 단계를 따라야 할 수도 있습니다.
명령 줄에서 소켓을 빌드하려면 :
% cd <path-to-clone>
% swift build
명령 줄에서 소켓 에 대한 제공된 단위 테스트를 실행하려면 :
% cd <path-to-clone>
% swift build
% swift test
Swift 패키지 관리자 패키지에 Bluesocket을 포함하려면 Package.swift 파일에 정의 된 dependencies 속성에 추가하십시오. majorVersion 및 minor 매개 변수를 사용하여 버전을 선택할 수 있습니다. 예를 들어:
dependencies: [
.Package(url: "https://github.com/Kitura/BlueSocket.git", majorVersion: <majorVersion>, minor: <minor>)
]
Carthage를 사용하는 프로젝트에 Bluesocket을 포함하려면 Github 조직 및 프로젝트 이름 및 버전으로 Cartfile 에 라인을 추가하십시오. 예를 들어:
github "Kitura/BlueSocket" ~> <majorVersion>.<minor>
Cocoapods를 사용하는 프로젝트에 Bluesocket을 포함하려면 Podfile 에 BlueSocket 추가하십시오.
platform :ios, '10.0'
target 'MyApp' do
use_frameworks!
pod 'BlueSocket'
end
가장 먼저해야 할 일은 소켓 프레임 워크를 가져 오는 것입니다. 이것은 다음에 의해 수행됩니다.
import Socket
Bluesocket은 다음 가족, 유형 및 프로토콜을 지원합니다.
Socket.ProtocolFamily.inetSocket.ProtocolFamily.inet6Socket.ProtocolFamily.unixSocket.SocketType.streamSocket.SocketType.datagramSocket.SocketProtocol.tcpSocket.SocketProtocol.udpSocket.SocketProtocol.unixBluesocket은 인스턴스를 만드는 데 사용되는 4 가지 공장 방법을 제공합니다. 이들은 다음과 같습니다.
create() - 완전히 구성된 기본 소켓을 만듭니다. 기본 소켓은 family: .inet , type: .stream 및 proto: .tcp .create(family family: ProtocolFamily, type: SocketType, proto: SocketProtocol) -이 API를 사용하면 필요에 맞게 사용자 정의 된 구성된 Socket 인스턴스를 만들 수 있습니다. 프로토콜 패밀리, 소켓 유형 및 소켓 프로토콜을 사용자 정의 할 수 있습니다.create(connectedUsing signature: Signature) -이 API를 사용하면 Socket 인스턴스를 생성하고 Socket.Signature 에서 전달한 정보를 기반으로 서버에 연결하려고 시도합니다.create(fromNativeHandle nativeHandle: Int32, address: Address?) -이 API를 사용하면 새로운 Socket 인스턴스에서 기존 소켓을 설명하는 기본 파일 디스크립터를 랩핑 할 수 있습니다. Bluesocket을 사용하면 사용할 읽기 버퍼의 크기를 설정할 수 있습니다. 그런 다음 애플리케이션의 요구에 따라 애플리케이션을 더 높거나 낮은 값으로 변경할 수 있습니다. 기본값은 Socket.SOCKET_DEFAULT_READ_BUFFER_SIZE 로 설정되어 값이 4096 입니다. 최소 읽기 버퍼 크기는 Socket.SOCKET_MINIMUM_READ_BUFFER_SIZE 는 1024 로 설정됩니다. 아래는 읽기 버퍼 크기를 변경하는 방법을 보여줍니다 (간결성에 대한 예외 처리) :
let mySocket = try Socket.create()
mySocket.readBufferSize = 32768
위의 예는 기본 판독 버퍼 크기를 32768 로 설정합니다. 이 설정은 Socket 인스턴스를 처음 사용하기 전에 수행해야합니다.
열린 인스턴스의 소켓을 닫으려면 다음 기능이 제공됩니다.
close() -이 기능은 열린 소켓을 깨끗하게 닫기 위해 필요한 작업을 수행합니다.Bluesocket을 사용하여 소켓의 연결을 듣기 위해 다음 API가 제공됩니다.
listen(on port: Int, maxBacklogSize: Int = Socket.SOCKET_DEFAULT_MAX_BACKLOG, allowPortReuse: Bool = true, node: String? = nil) 첫 번째 매개 변수 port 들을 수있는 포트입니다. 두 번째 매개 변수 인 maxBacklogSize 사용하면 보류중인 연결을 유지하는 대기열의 크기를 설정할 수 있습니다. 함수는 지정된 port 기반으로 적절한 소켓 구성을 결정합니다. MACOS의 편의를 위해 Constant Socket.SOCKET_MAX_DARWIN_BACKLOG 최대 허용 백 로그 크기를 사용하도록 설정할 수 있습니다. 모든 플랫폼의 기본값은 Socket.SOCKET_DEFAULT_MAX_BACKLOG 이며 현재 50 으로 설정되었습니다. 서버 사용의 경우이 값을 높이는 것이 필요할 수 있습니다. 청취 포트의 재사용을 허용하려면 allowPortReuse true 로 설정하십시오. false 로 설정되면 이미 사용중인 포트에서 듣기를 시도하면 오류가 발생합니다. DEFAULT 동작은 포트 재사용을 allow 입니다. 마지막 매개 변수 인 node 는 특정 주소 에서 듣는 데 사용할 수 있습니다. 전달 된 값은 숫자 네트워크 주소를 포함하는 선택적 문자열 입니다 (IPv4, 숫자 및 도트 표기법, IPv6, 16 진 스트링). DEFAULT 동작은 적절한 인터페이스를 검색하는 것입니다. node 부적절하게 서식하면 socket_err_getaddrinfo_failed 오류가 반환됩니다. node 올바르게 형식화되어 있지만 지정된 주소를 사용할 수 없으면 socket_err_bind_failed가 반환됩니다.listen(on path: String, maxBacklogSize: Int = Socket.SOCKET_DEFAULT_MAX_BACKLOG) 이 API는 .unix 프로토콜 패밀리와 함께 만 사용할 수 있습니다. 첫 번째 매개 변수 path 듣는 데 사용되는 경로입니다. 두 번째 매개 변수 인 maxBacklogSize 사용하면 보류중인 연결을 유지하는 대기열의 크기를 설정할 수 있습니다. 함수는 지정된 port 기반으로 적절한 소켓 구성을 결정합니다. MACOS의 편의를 위해 Constant Socket.SOCKET_MAX_DARWIN_BACKLOG 최대 허용 백 로그 크기를 사용하도록 설정할 수 있습니다. 모든 플랫폼의 기본값은 Socket.SOCKET_DEFAULT_MAX_BACKLOG 이며 현재 50 으로 설정되었습니다. 서버 사용의 경우이 값을 높이는 것이 필요할 수 있습니다. 다음 예제는 기본 Socket 인스턴스를 생성 한 다음 즉시 포트 1337 에서 듣기 시작합니다. 참고 : 간결성에 대해서는 예외 처리가 생략되었고 예외 처리의 예는 아래의 전체 예를 참조하십시오.
var socket = try Socket . create ( )
try socket . listen ( on : 1337 )청취 소켓이 들어오는 연결 요청을 감지하면 컨트롤이 프로그램으로 반환됩니다. 그런 다음 응용 프로그램이 멀티 스레드 인 경우 연결을 수락하거나 계속 듣거나 계속 청취 할 수 있습니다. Bluesocket은 들어오는 연결을 수락하는 두 가지 다른 방법을 지원합니다. 그들은 다음과 같습니다.
acceptClientConnection(invokeDelegate: Bool = true) -이 함수는 연결을 수락하고 새로 연결된 소켓을 기반으로 새 Socket 인스턴스를 반환합니다. 영향을받지 않은 인스턴스. invokeDelegate 가 false 이고 Socket 에 SSLService 대의원이 첨부 된 경우이 함수에 의해 리턴되는 Socket 인스턴스를 사용하여 invokeDelegateOnAccept 메소드를 호출 해야합니다 .invokeDelegateOnAccept(for newSocket: Socket) - Socket 인스턴스에 SSLService 대의원이있는 경우 대의원이 SSL 협상을 수행 할 기능을 호출합니다. acceptClientConnection 에 의해 Socket 인스턴스를 반환 한 상태에서 호출해야합니다. 이 기능은 여러 번 Socket 인스턴스가 잘못되었거나 Socket 인스턴스에 SSLService 대의원이 없는 경우 예외가 발생합니다.acceptConnection() -이 함수는 기존 청취 소켓을 대체하고 닫는다 . 이전에 청취 소켓과 관련된 특성은 새로 연결된 소켓과 관련된 특성으로 대체됩니다. Bluesocket은 위에서 설명한 create(connectedUsing:) 공장 방법 외에도 Socket 인스턴스를 서버에 연결하기위한 세 가지 추가 인스턴스 기능을 지원합니다. 그들은 다음과 같습니다.
connect(to host: String, port: Int32, timeout: UInt = 0) -이 API를 사용하면 제공하는 hostname 과 port 기반으로 서버에 연결할 수 있습니다. 참고 : port 의 값이 1-65535 범위에 있지 않으면이 함수에 의해 exception 발생합니다. 선택적으로, 연결을 기다리기 위해 timeout 를 밀리 초 수로 설정할 수 있습니다. 참고 : 소켓이 차단 모드에 있으면 0 (0)보다 큰 timeout 제공되면 일시적으로 비 블로킹 모드로 변경됩니다. 반환 된 소켓은 원래 설정 (차단 또는 비 차단)으로 다시 설정 됩니다. 소켓이 블로킹을하지 않고 시간 초과 값이 제공되지 않으면 예외가 발생합니다. 또는 성공적으로 연결 한 후 소켓을 비 블로킹 으로 설정할 수 있습니다.connect(to path: String) -이 API는 .unix 프로토콜 패밀리와 함께만 사용할 수 있습니다. 제공하는 path 에 따라 서버에 연결할 수 있습니다.connect(using signature: Signature) 정보가 포함 된 Socket.Signature 인스턴스를 제공하여 연결 정보를 지정할 수 있습니다. 자세한 내용은 Socket.signature 의 Socket.Signature 참조하십시오.Bluesocket은 소켓에서 데이터를 읽는 4 가지 방법을 지원합니다. 이들은 (권장 사용 주문)입니다.
read(into data: inout Data) -이 기능은 소켓에서 사용 가능한 모든 데이터를 읽고 통과 된 Data 객체에서 반환합니다.read(into data: NSMutableData) -이 함수는 소켓에서 사용 가능한 모든 데이터를 읽고 통과 된 NSMutableData 객체에서 반환합니다.readString() -이 함수는 소켓에서 사용 가능한 모든 데이터를 읽고 String 로 반환합니다. 읽을 수있는 데이터가없는 경우 nil 반환됩니다.read(into buffer: UnsafeMutablePointer<CChar>, bufSize: Int, truncate: Bool = false) -이 기능을 사용하면 해당 버퍼에 안전하지 않은 포인터를 제공하여 지정된 크기의 버퍼로 데이터를 읽을 수 있으며 정수는 해당 버퍼의 크기를 나타냅니다. 이 API (다른 유형의 예외 외에)는 Socket.SOCKET_ERR_RECV_BUFFER_TOO_SMALL 제공된 버퍼가 너무 작 으면 truncate = true 가 아닌 한 소켓이 bufSize 바이트 만 읽는 것처럼 작용하지 않는 한 (다음 호출에서 불확실한 바이트가 반환됩니다). truncate = false 인 경우 적절한 버퍼 크기로 다시 호출해야합니다 (자세한 내용은 소켓 에서 Error.bufferSizeNeeded 참조하십시오.readString() 제외한 위의 모든 읽기 API는 0 (0)을 반환 할 수 있습니다. 이것은 원격 연결이 닫히거나 소켓이 차단 될 것을 나타낼 수 있습니다 (차단을 끄는 것으로 가정). 둘을 구별하기 위해 속성 remoteConnectionClosed 확인할 수 있습니다. true 이라면 소켓 원격 파트너가 연결을 닫고이 Socket 인스턴스가 닫아야합니다.소켓에서 읽는 것 외에도 Bluesocket은 소켓에 데이터를 작성하는 4 가지 방법을 제공합니다. 이들은 (권장 사용 주문)입니다.
write(from data: Data) -이 함수는 소켓에 Data 객체에 포함 된 데이터를 씁니다.write(from data: NSData) -이 기능은 NSData 객체에 포함 된 데이터를 소켓에 씁니다.write(from string: String) -이 함수는 소켓에 제공된 String 에 포함 된 데이터를 씁니다.write(from buffer: UnsafeRawPointer, bufSize: Int) -이 기능은 해당 버퍼에 대한 안전하지 않은 포인터와 해당 버퍼의 크기를 나타내는 정수를 제공하여 지정된 크기의 버퍼에 포함 된 데이터를 씁니다.Bluesocket은 들어오는 데이터 그램을 듣는 세 가지 방법을 지원합니다. 이들은 (권장 사용 주문)입니다.
listen(forMessage data: inout Data, on port: Int, maxBacklogSize: Int = Socket.SOCKET_DEFAULT_MAX_BACKLOG) -이 함수는 들어오는 데이터 그램에 대해 장려하고 읽고 전달 된 Data 객체에서 반환합니다. 읽기 수와 데이터가 시작된 위치의 Address 를 포함하는 튜플을 반환합니다.listen(forMessage data: NSMutableData, on port: Int, maxBacklogSize: Int = Socket.SOCKET_DEFAULT_MAX_BACKLOG) -이 함수는 들어오는 데이터 그램에 대해 리ent을보고 읽고 전달 된 NSMutableData 객체에서 반환합니다. 읽기 수와 데이터가 시작된 위치의 Address 를 포함하는 튜플을 반환합니다.listen(forMessage buffer: UnsafeMutablePointer<CChar>, bufSize: Int, on port: Int, maxBacklogSize: Int = Socket.SOCKET_DEFAULT_MAX_BACKLOG) - 들어오는 데이터 그램에 대해서는 듣고 읽고 통과 된 Data 객체에서 반환합니다. 읽기 수와 데이터가 시작된 위치의 Address 를 포함하는 튜플을 반환합니다.port 기반으로 적절한 소켓 구성을 결정합니다. port 값을 0 (0)으로 설정하면 기능이 적합한 자유 포트를 결정하게됩니다.maxBacklogSize 사용하면 보류중인 연결을 유지하는 대기열의 크기를 설정할 수 있습니다. 함수는 지정된 port 기반으로 적절한 소켓 구성을 결정합니다. MACOS의 편의를 위해 Constant Socket.SOCKET_MAX_DARWIN_BACKLOG 최대 허용 백 로그 크기를 사용하도록 설정할 수 있습니다. 모든 플랫폼의 기본값은 Socket.SOCKET_DEFAULT_MAX_BACKLOG 이며 현재 50 으로 설정되었습니다. 서버 사용의 경우이 값을 높이는 것이 필요할 수 있습니다.Bluesocket은 들어오는 데이터 그램을 읽는 세 가지 방법을 지원합니다. 이들은 (권장 사용 주문)입니다.
readDatagram(into data: inout Data) -이 기능은 들어오는 데이터 그램을 읽고 전달 된 Data 객체에서 반환합니다. 읽기 수와 데이터가 시작된 위치의 Address 를 포함하는 튜플을 반환합니다.readDatagram(into data: NSMutableData) -이 함수는 들어오는 데이터 그램을 읽고 전달 된 NSMutableData 객체에서 반환합니다. 읽기 수와 데이터가 시작된 위치의 Address 를 포함하는 튜플을 반환합니다.readDatagram(into buffer: UnsafeMutablePointer<CChar>, bufSize: Int) -이 함수는 들어오는 데이터 그램을 읽고 전달 된 Data 객체에서 반환합니다. 읽기 수와 데이터가 시작된 위치의 Address 를 포함하는 튜플을 반환합니다. 읽는 데이터 양이 bufSize 보다 더 많은 경우 bufSize 만 반환됩니다. 읽은 나머지 데이터는 폐기됩니다.Bluesocket은 또한 소켓에 데이터 그램을 작성하는 4 가지 방법을 제공합니다. 이들은 (권장 사용 주문)입니다.
write(from data: Data, to address: Address) -이 함수는 Data 객체에 포함 된 데이터 그램을 소켓에 씁니다.write(from data: NSData, to address: Address) -이 함수는 NSData 객체에 포함 된 데이터 그램을 소켓에 씁니다.write(from string: String, to address: Address) -이 함수는 소켓에 제공된 String 에 포함 된 데이터 그램을 씁니다.write(from buffer: UnsafeRawPointer, bufSize: Int, to address: Address)address 매개 변수는 데이터 그램을 보내는 대상의 주소를 나타냅니다. NSData 또는 NSMutableData 사용하는 위의 읽기 및 쓰기 API는 아마도 먼 미래에서는 더 이상 사용 되지 않을 것입니다.
hostnameAndPort(from address: Address) -이 클래스 함수는 주어진 Socket.Address 에서 호스트 이름과 포트를 추출하는 수단을 제공합니다. 성공적인 완료시 hostname 과 port 포함하는 튜플이 반환됩니다.checkStatus(for sockets: [Socket]) -이 클래스 함수를 사용하면 Socket 인스턴스 배열의 상태를 확인할 수 있습니다. 완료되면 2 개의 Socket 어레이를 포함하는 튜플이 반환됩니다. 첫 번째 배열에는 Socket 인스턴스가 포함되어 있으며 데이터를 읽을 수 있고 두 번째 배열에는 작성할 수있는 Socket 인스턴스가 포함되어 있습니다. 이 API는 차단되지 않습니다 . 각 Socket 인스턴스의 상태를 확인한 다음 결과를 반환합니다.wait(for sockets: [Socket], timeout: UInt, waitForever: Bool = false) -이 클래스 함수를 사용하면 Socket 인스턴스 배열을 모니터링 할 수 있습니다. 시간 초과가 발생하거나 모니터링 된 Socket 인스턴스 중 하나에서 데이터를 읽을 수 있습니다. 0 (0)의 시간 초과가 지정되면이 API는 각 소켓을 확인하고 즉시 반환합니다. 그렇지 않으면, 시간 초과 만료 나 데이터가 하나 이상의 모니터링 된 Socket 인스턴스에서 읽을 수있을 때까지 기다립니다. 시간 초과가 발생하면이 API는 nil 반환합니다. 하나 이상의 모니터링 된 Socket 인스턴스에서 데이터를 사용할 수있는 경우 해당 인스턴스는 배열로 반환됩니다. waitForever 플래그가 true로 설정된 경우, 지정된 시간 초과 값에 관계없이 데이터가 데이터를 사용할 수 있도록 함수가 무기한 대기합니다.createAddress(host: String, port: Int32) -이 클래스 함수는 host 와 port 주어진 Address 열거를 생성 할 수 있습니다. 성공시,이 기능은 지정된 host 존재하지 않으면 Address nil 합니다.isReadableOrWritable(waitForever: Bool = false, timeout: UInt = 0) -이 인스턴스 함수를 사용하면 Socket 인스턴스를 읽을 수 있고/또는 쓸 수 있는지 여부를 결정할 수 있습니다. 두 개의 Bool 값을 포함하는 튜플이 반환됩니다. 첫 번째는 true 인 경우 Socket 인스턴스에 읽을 데이터가 있음을 나타냅니다. 두 번째는 True 인 경우 Socket 인스턴스를 작성할 수 있음을 나타냅니다. waitForever TRUE 인 경우 Socket 읽기 쉬우거나 쓰기 쉬거나 오류가 발생할 때 까지이 루틴이 기다릴 수 있습니다. False 인 경우 timeout 매개 변수는 대기 시간이 얼마나 오래 지정됩니다. 타임 아웃 값에 대해 0 (0) 의 값이 지정되면이 함수는 현재 상태를 확인하고 즉시 반환됩니다. 이 함수는 두 개의 readable 을 포함하는 튜플을 반환 writable . Socket 읽을 수 있거나 쓸 수있는 경우에는 진실로 설정됩니다. 참으로 설정되지 않으면 타임 아웃이 발생했습니다. 참고 : 새로 연결된 소켓 에 편지를 쓰려고하는 경우 작업을 시도하기 전에 쓰기가 있는지 확인해야합니다.setBlocking(shouldBlock: Bool) -이 인스턴스 기능을 사용하면이 Socket 인스턴스가 차단 모드에 배치되어야하는지 여부를 제어 할 수 있습니다. 참고 : 모든 Socket 인스턴스는 기본적 으로 차단 모드 에서 생성됩니다.setReadTimeout(value: UInt = 0) -이 인스턴스 기능을 사용하면 읽기 작업의 시간 초과를 설정할 수 있습니다. value 은 UInt 입니다. 반환 전에 읽기 작업이 기다릴 시간을 지정합니다. 시간 초과가 발생한 경우 읽기 작업은 0 바이트를 반환하고 errno EAGAIN 으로 설정됩니다.setWriteTimeout(value: UInt = 0) -이 인스턴스 기능을 사용하면 쓰기 작업의 시간 초과를 설정할 수 있습니다. value 은 UInt 입니다. 이는 쓰기 작업이 돌아 오기 전에 기다릴 시간을 지정합니다. 타임 아웃의 경우, 쓰기 작업은 0 바이트를 반환하고 errno TCP 및 UNIX 소켓을 위해 EAGAIN 으로 설정됩니다. UDP 의 경우 쓰기 작업은 타임 아웃 값에 관계없이 성공합니다 .udpBroadcast(enable: Bool) -이 인스턴스 기능은 UDP 소켓에서 브로드 캐스트 모드를 활성화하는 데 사용됩니다. 방송을 활성화하려면 true , false 사용하여 비활성화하십시오. Socket 인스턴스가 UDP 소켓이 아닌 경우이 기능은 예외를 던집니다. 다음 예제는 새로운 GCD based 디스패치 API를 사용하여 비교적 간단한 멀티 스레드 에코 서버를 만드는 방법을 보여줍니다. 다음은 한 번 실행되면 telnet ::1 1337 통해 액세스 할 수있는 간단한 Echo 서버에 대한 코드입니다.
import Foundation
import Socket
import Dispatch
class EchoServer {
static let quitCommand : String = " QUIT "
static let shutdownCommand : String = " SHUTDOWN "
static let bufferSize = 4096
let port : Int
var listenSocket : Socket ? = nil
var continueRunningValue = true
var connectedSockets = [ Int32 : Socket ] ( )
let socketLockQueue = DispatchQueue ( label : " com.kitura.serverSwift.socketLockQueue " )
var continueRunning : Bool {
set ( newValue ) {
socketLockQueue . sync {
self . continueRunningValue = newValue
}
}
get {
return socketLockQueue . sync {
self . continueRunningValue
}
}
}
init ( port : Int ) {
self . port = port
}
deinit {
// Close all open sockets...
for socket in connectedSockets . values {
socket . close ( )
}
self . listenSocket ? . close ( )
}
func run ( ) {
let queue = DispatchQueue . global ( qos : . userInteractive )
queue . async { [ unowned self ] in
do {
// Create an IPV6 socket...
try self . listenSocket = Socket . create ( family : . inet6 )
guard let socket = self . listenSocket else {
print ( " Unable to unwrap socket... " )
return
}
try socket . listen ( on : self . port )
print ( " Listening on port: ( socket . listeningPort ) " )
repeat {
let newSocket = try socket . acceptClientConnection ( )
print ( " Accepted connection from: ( newSocket . remoteHostname ) on port ( newSocket . remotePort ) " )
print ( " Socket Signature: ( String ( describing : newSocket . signature ? . description ) ) " )
self . addNewConnection ( socket : newSocket )
} while self . continueRunning
}
catch let error {
guard let socketError = error as? Socket . Error else {
print ( " Unexpected error... " )
return
}
if self . continueRunning {
print ( " Error reported: n ( socketError . description ) " )
}
}
}
dispatchMain ( )
}
func addNewConnection ( socket : Socket ) {
// Add the new socket to the list of connected sockets...
socketLockQueue . sync { [ unowned self , socket ] in
self . connectedSockets [ socket . socketfd ] = socket
}
// Get the global concurrent queue...
let queue = DispatchQueue . global ( qos : . default )
// Create the run loop work item and dispatch to the default priority global queue...
queue . async { [ unowned self , socket ] in
var shouldKeepRunning = true
var readData = Data ( capacity : EchoServer . bufferSize )
do {
// Write the welcome string...
try socket . write ( from : " Hello, type 'QUIT' to end session n or 'SHUTDOWN' to stop server. n " )
repeat {
let bytesRead = try socket . read ( into : & readData )
if bytesRead > 0 {
guard let response = String ( data : readData , encoding : . utf8 ) else {
print ( " Error decoding response... " )
readData . count = 0
break
}
if response . hasPrefix ( EchoServer . shutdownCommand ) {
print ( " Shutdown requested by connection at ( socket . remoteHostname ) : ( socket . remotePort ) " )
// Shut things down...
self . shutdownServer ( )
return
}
print ( " Server received from connection at ( socket . remoteHostname ) : ( socket . remotePort ) : ( response ) " )
let reply = " Server response: n ( response ) n "
try socket . write ( from : reply )
if ( response . uppercased ( ) . hasPrefix ( EchoServer . quitCommand ) || response . uppercased ( ) . hasPrefix ( EchoServer . shutdownCommand ) ) &&
( !response . hasPrefix ( EchoServer . quitCommand ) && !response . hasPrefix ( EchoServer . shutdownCommand ) ) {
try socket . write ( from : " If you want to QUIT or SHUTDOWN, please type the name in all caps. ? n " )
}
if response . hasPrefix ( EchoServer . quitCommand ) || response . hasSuffix ( EchoServer . quitCommand ) {
shouldKeepRunning = false
}
}
if bytesRead == 0 {
shouldKeepRunning = false
break
}
readData . count = 0
} while shouldKeepRunning
print ( " Socket: ( socket . remoteHostname ) : ( socket . remotePort ) closed... " )
socket . close ( )
self . socketLockQueue . sync { [ unowned self , socket ] in
self . connectedSockets [ socket . socketfd ] = nil
}
}
catch let error {
guard let socketError = error as? Socket . Error else {
print ( " Unexpected error by connection at ( socket . remoteHostname ) : ( socket . remotePort ) ... " )
return
}
if self . continueRunning {
print ( " Error reported by connection at ( socket . remoteHostname ) : ( socket . remotePort ) : n ( socketError . description ) " )
}
}
}
}
func shutdownServer ( ) {
print ( " n Shutdown in progress... " )
self . continueRunning = false
// Close all open sockets...
for socket in connectedSockets . values {
self . socketLockQueue . sync { [ unowned self , socket ] in
self . connectedSockets [ socket . socketfd ] = nil
socket . close ( )
}
}
DispatchQueue . main . sync {
exit ( 0 )
}
}
}
let port = 1337
let server = EchoServer ( port : port )
print ( " Swift Echo Server Sample " )
print ( " Connect with a command line window by entering 'telnet ::1 ( port ) ' " )
server . run ( ) 이 서버는 다음 Package.swift 지정하여 구축 할 수 있습니다.
import PackageDescription
let package = Package (
name : " EchoServer " ,
dependencies : [
. package ( url : " https://github.com/Kitura/BlueSocket.git " , from : " 1.0.8 " ) ,
] ,
targets : [
. target (
name : " EchoServer " ,
dependencies : [
" Socket "
] ) ,
]
) 또는 여전히 Swift 3을 사용하는 경우 다음 Package.swift 지정하여 파일을 지정합니다.
import PackageDescription
let package = Package (
name : " EchoServer " ,
dependencies : [
. Package ( url : " https://github.com/Kitura/BlueSocket.git " , majorVersion : 1 , minor : 0 ) ,
] ,
exclude : [ " EchoServer.xcodeproj " ]
) 다음 명령 시퀀스는 Linux에서 Echo 서버를 빌드하고 실행합니다. MACOS에서 실행되거나 8/18 도구 체인보다 새로운 툴체인을 사용하는 경우 더 이상 필요하지 않으므로 -Xcc -fblocks 스위치를 생략 할 수 있습니다.
$ swift build -Xcc -fblocks
$ .build/debug/EchoServer
Swift Echo Server Sample
Connect with a command line window by entering 'telnet ::1 1337'
Listening on port: 1337
우리는 Server-Side Swift와 Kitura에 대해 이야기하는 것을 좋아합니다. 팀을 만나기 위해 슬랙에 가입하십시오!
이 라이브러리는 Apache 2.0에 따라 라이센스가 부여됩니다. 전체 라이센스 텍스트는 라이센스로 제공됩니다.