Kerangka kerja soket untuk Swift menggunakan manajer paket Swift. Bekerja di iOS, macOS, dan Linux.
swift-5.1-RELEASE Toolchain ( minimum diperlukan untuk rilis terbaru )swift-5.4-RELEASE Toolchain ( Disarankan )Catatan:
Jika membuat server UDP di iOS, Anda mungkin perlu mengikuti beberapa langkah:
Untuk membangun soket dari baris perintah:
% cd <path-to-clone>
% swift build
Untuk menjalankan tes unit yang disediakan untuk soket dari baris perintah:
% cd <path-to-clone>
% swift build
% swift test
Untuk memasukkan bluesocket ke dalam paket manajer paket Swift, tambahkan ke atribut dependencies yang ditentukan dalam file Package.swift Anda. Anda dapat memilih versi menggunakan parameter majorVersion dan minor . Misalnya:
dependencies: [
.Package(url: "https://github.com/Kitura/BlueSocket.git", majorVersion: <majorVersion>, minor: <minor>)
]
Untuk memasukkan bluesocket dalam proyek menggunakan Carthage, tambahkan baris ke Cartfile Anda dengan organisasi GitHub dan nama serta versi proyek. Misalnya:
github "Kitura/BlueSocket" ~> <majorVersion>.<minor>
Untuk memasukkan bluesocket dalam proyek menggunakan cocoapods, Anda cukup menambahkan BlueSocket ke Podfile Anda, misalnya:
platform :ios, '10.0'
target 'MyApp' do
use_frameworks!
pod 'BlueSocket'
end
Hal pertama yang perlu Anda lakukan adalah mengimpor kerangka kerja soket. Ini dilakukan dengan berikut ini:
import Socket
Bluesocket mendukung keluarga, jenis, dan protokol berikut:
Socket.ProtocolFamily.inetSocket.ProtocolFamily.inet6Socket.ProtocolFamily.unixSocket.SocketType.streamSocket.SocketType.datagramSocket.SocketProtocol.tcpSocket.SocketProtocol.udpSocket.SocketProtocol.unixBluesocket menyediakan empat metode pabrik berbeda yang digunakan untuk membuat instance. Ini adalah:
create() - Ini membuat soket default yang sepenuhnya dikonfigurasi. Soket default dibuat dengan family: .inet , type: .stream , dan proto: .tcp .create(family family: ProtocolFamily, type: SocketType, proto: SocketProtocol) - API ini memungkinkan Anda untuk membuat instance Socket yang dikonfigurasi yang disesuaikan untuk kebutuhan Anda. Anda dapat menyesuaikan keluarga protokol, jenis soket, dan protokol soket.create(connectedUsing signature: Signature) - API ini akan memungkinkan Anda membuat instance Socket dan berusaha untuk terhubung ke server berdasarkan informasi yang Anda lewati di Socket.Signature .create(fromNativeHandle nativeHandle: Int32, address: Address?) - API ini memungkinkan Anda membungkus deskriptor file asli yang menggambarkan soket yang ada dalam instance baru Socket . Bluesocket memungkinkan Anda untuk mengatur ukuran buffer baca yang akan digunakan. Kemudian, tergantung pada kebutuhan aplikasi, Anda dapat mengubahnya menjadi nilai yang lebih tinggi atau lebih rendah. Default diatur ke Socket.SOCKET_DEFAULT_READ_BUFFER_SIZE yang memiliki nilai 4096 . Ukuran buffer baca minimum adalah Socket.SOCKET_MINIMUM_READ_BUFFER_SIZE yang diatur ke 1024 . Di bawah ini menggambarkan cara mengubah ukuran buffer baca (penanganan pengecualian dihilangkan untuk singkatnya):
let mySocket = try Socket.create()
mySocket.readBufferSize = 32768
Contoh di atas menetapkan ukuran buffer baca default ke 32768 . Pengaturan ini harus dilakukan sebelum menggunakan instance Socket untuk pertama kalinya.
Untuk menutup soket instance terbuka, fungsi berikut disediakan:
close() - Fungsi ini akan melakukan tugas yang diperlukan untuk menutup soket terbuka dengan bersih.Untuk menggunakan bluesocket untuk mendengarkan koneksi pada soket API berikut disediakan:
listen(on port: Int, maxBacklogSize: Int = Socket.SOCKET_DEFAULT_MAX_BACKLOG, allowPortReuse: Bool = true, node: String? = nil) port parameter pertama, apakah port yang akan digunakan untuk mendengarkan. Parameter kedua, maxBacklogSize memungkinkan Anda untuk mengatur ukuran koneksi antrian yang tertunda. Fungsi akan menentukan konfigurasi soket yang sesuai berdasarkan port yang ditentukan. Untuk kenyamanan pada macOS, Socket.SOCKET_MAX_DARWIN_BACKLOG konstan.socket_max_darwin_backlog dapat diatur untuk menggunakan ukuran backlog maksimum yang diizinkan. Nilai default untuk semua platform adalah Socket.SOCKET_DEFAULT_MAX_BACKLOG , saat ini ditetapkan ke 50 . Untuk penggunaan server, mungkin perlu meningkatkan nilai ini. Untuk memungkinkan penggunaan kembali port mendengarkan, atur allowPortReuse menjadi true . Jika diatur ke false , kesalahan akan terjadi jika Anda mencoba mendengarkan di port yang sudah digunakan. Perilaku DEFAULT adalah untuk allow penggunaan kembali port. Parameter terakhir, node , dapat digunakan untuk mendengarkan di alamat tertentu . Nilai yang dilewati adalah string opsional yang berisi alamat jaringan numerik (untuk IPv4, angka dan notasi titik, untuk IPv6, strting heksidesimal). Perilaku DEFAULT adalah mencari antarmuka yang sesuai. Jika node diformat secara tidak benar kesalahan Socket_err_Getaddrinfo_failed akan dikembalikan. Jika node diformat dengan benar tetapi alamat yang ditentukan tidak tersedia, socket_err_bind_failed akan dikembalikan.listen(on path: String, maxBacklogSize: Int = Socket.SOCKET_DEFAULT_MAX_BACKLOG) API ini hanya dapat digunakan dengan keluarga protokol .unix . path parameter pertama, adalah jalur yang digunakan untuk mendengarkan. Parameter kedua, maxBacklogSize memungkinkan Anda untuk mengatur ukuran koneksi antrian yang tertunda. Fungsi akan menentukan konfigurasi soket yang sesuai berdasarkan port yang ditentukan. Untuk kenyamanan pada macOS, Socket.SOCKET_MAX_DARWIN_BACKLOG konstan.socket_max_darwin_backlog dapat diatur untuk menggunakan ukuran backlog maksimum yang diizinkan. Nilai default untuk semua platform adalah Socket.SOCKET_DEFAULT_MAX_BACKLOG , saat ini ditetapkan ke 50 . Untuk penggunaan server, mungkin perlu meningkatkan nilai ini. Contoh berikut membuat instance Socket default dan kemudian segera mulai mendengarkan pada port 1337 . Catatan: Penanganan pengecualian dihilangkan untuk singkat, lihat contoh lengkap di bawah ini untuk contoh penanganan pengecualian.
var socket = try Socket . create ( )
try socket . listen ( on : 1337 )Ketika soket mendengarkan mendeteksi permintaan koneksi yang masuk, kontrol dikembalikan ke program Anda. Anda kemudian dapat menerima koneksi atau melanjutkan mendengarkan atau keduanya jika aplikasi Anda multi-threaded. Bluesocket mendukung dua cara berbeda untuk menerima koneksi yang masuk. Mereka adalah:
acceptClientConnection(invokeDelegate: Bool = true) - Fungsi ini menerima koneksi dan mengembalikan instance Socket baru berdasarkan soket yang baru terhubung. Contoh yang mendengarkan secara tidak terpengaruh. Jika invokeDelegate false dan Socket memiliki delegasi SSLService yang terpasang, Anda harus memanggil metode invokeDelegateOnAccept menggunakan instance Socket yang dikembalikan oleh fungsi ini.invokeDelegateOnAccept(for newSocket: Socket) - Jika instance Socket memiliki delegasi SSLService , ini akan meminta fungsi menerima delegasi untuk melakukan negosiasi SSL. Itu harus dipanggil dengan instance Socket yang dikembalikan oleh acceptClientConnection . Fungsi ini akan melempar pengecualian jika dipanggil dengan instance Socket yang salah, dipanggil beberapa kali, atau jika instance Socket tidak memiliki delegasi SSLService .acceptConnection() - Fungsi ini menerima koneksi yang masuk, mengganti dan menutup soket mendengarkan yang ada. Properti yang sebelumnya terkait dengan soket mendengarkan digantikan oleh properti yang relevan dengan soket yang baru terhubung. Selain Metode create(connectedUsing:) Factory yang dijelaskan di atas, Bluesocket mendukung tiga fungsi instance tambahan untuk menghubungkan instance Socket ke server. Mereka adalah:
connect(to host: String, port: Int32, timeout: UInt = 0) - API ini memungkinkan Anda untuk terhubung ke server berdasarkan hostname dan port yang Anda berikan. Catatan: exception akan dilemparkan oleh fungsi ini jika nilai port tidak ada dalam kisaran 1-65535 . Secara opsional, Anda dapat menetapkan timeout dengan jumlah milidetik untuk menunggu koneksi. Catatan: Jika soket dalam mode pemblokiran itu akan diubah ke mode non-blocking sementara jika timeout lebih besar dari nol (0) disediakan. Soket yang dikembalikan akan diatur kembali ke pengaturan aslinya (pemblokiran atau non-blocking) . Jika soket diatur ke non-blocking dan tidak ada nilai batas waktu yang disediakan , pengecualian akan dilemparkan. Atau, Anda dapat mengatur soket ke non-blocking setelah berhasil menghubungkan.connect(to path: String) - API ini hanya dapat digunakan dengan keluarga protokol .unix . Ini memungkinkan Anda untuk terhubung ke server berdasarkan path yang Anda berikan.connect(using signature: Signature) - API ini memungkinkan Anda menentukan informasi koneksi dengan memberikan Socket.Signature yang berisi informasi. Lihat Socket.Signature di Socket.Swift untuk informasi lebih lanjut.Bluesocket mendukung empat cara berbeda untuk membaca data dari soket. Ini (dalam urutan penggunaan yang disarankan):
read(into data: inout Data) - Fungsi ini membaca semua data yang tersedia di soket dan mengembalikannya di objek Data yang dilewati.read(into data: NSMutableData) - Fungsi ini membaca semua data yang tersedia di soket dan mengembalikannya di objek NSMutableData yang dilewati.readString() - Fungsi ini membaca semua data yang tersedia di soket dan mengembalikannya sebagai String . nil dikembalikan jika tidak ada data yang tersedia untuk dibaca.read(into buffer: UnsafeMutablePointer<CChar>, bufSize: Int, truncate: Bool = false) - Fungsi ini memungkinkan Anda untuk membaca data ke dalam buffer dengan ukuran yang ditentukan dengan menyediakan pointer yang tidak aman untuk buffer itu dan bilangan bulat menunjukkan ukuran buffer itu. API ini (selain jenis pengecualian lainnya) akan melempar Socket.SOCKET_ERR_RECV_BUFFER_TOO_SMALL jika buffer yang disediakan terlalu kecil, kecuali truncate = true dalam hal ini soket akan bertindak seolah -olah hanya byte bufSize yang dibaca (byte yang tidak dikembalikan akan dikembalikan dalam panggilan berikutnya). Jika truncate = false , Anda perlu menelepon lagi dengan ukuran buffer yang tepat (lihat Error.bufferSizeNeeded di socket.swift untuk informasi lebih lanjut).readString() dapat mengembalikan nol (0). Ini dapat menunjukkan bahwa koneksi jarak jauh ditutup atau dapat menunjukkan bahwa soket akan diblokir (dengan asumsi Anda mematikan pemblokiran). Untuk membedakan antara keduanya, properti remoteConnectionClosed dapat diperiksa. Jika true , mitra remote soket telah menutup koneksi dan instance Socket ini harus ditutup.Selain membaca dari soket, Bluesocket juga memasok empat metode untuk menulis data ke soket. Ini (dalam urutan penggunaan yang disarankan):
write(from data: Data) - Fungsi ini menulis data yang terkandung dalam objek Data ke soket.write(from data: NSData) - Fungsi ini menulis data yang terkandung dalam objek NSData ke soket.write(from string: String) - Fungsi ini menulis data yang terkandung dalam String yang disediakan untuk soket.write(from buffer: UnsafeRawPointer, bufSize: Int) - Fungsi ini menulis data yang terkandung dalam buffer dari ukuran yang ditentukan dengan menyediakan pointer yang tidak aman untuk buffer itu dan bilangan bulat yang menunjukkan ukuran buffer itu.Bluesocket mendukung tiga cara berbeda untuk mendengarkan datagram yang masuk. Ini (dalam urutan penggunaan yang disarankan):
listen(forMessage data: inout Data, on port: Int, maxBacklogSize: Int = Socket.SOCKET_DEFAULT_MAX_BACKLOG) - Fungsi ini mendengarkan datagram yang masuk, membacanya dan mengembalikannya di objek Data yang dilewatkan. Ini mengembalikan tuple yang berisi jumlah byte yang dibaca dan Address dari mana data berasal.listen(forMessage data: NSMutableData, on port: Int, maxBacklogSize: Int = Socket.SOCKET_DEFAULT_MAX_BACKLOG) - Fungsi ini mendengarkan datagram yang masuk, membacanya dan mengembalikannya dalam objek NSMutableData yang disahkan. Ini mengembalikan tuple yang berisi jumlah byte yang dibaca dan Address dari mana data berasal.listen(forMessage buffer: UnsafeMutablePointer<CChar>, bufSize: Int, on port: Int, maxBacklogSize: Int = Socket.SOCKET_DEFAULT_MAX_BACKLOG) - Fungsi ini mendengarkan datagram yang masuk, membacanya dan mengembalikannya dalam objek Data yang disahkan. Ini mengembalikan tuple yang berisi jumlah byte yang dibaca dan Address dari mana data berasal.port yang ditentukan. Menetapkan nilai port ke nol (0) akan menyebabkan fungsi menentukan port bebas yang sesuai.maxBacklogSize memungkinkan Anda untuk mengatur ukuran koneksi antrian yang tertunda. Fungsi akan menentukan konfigurasi soket yang sesuai berdasarkan port yang ditentukan. Untuk kenyamanan pada macOS, Socket.SOCKET_MAX_DARWIN_BACKLOG konstan.socket_max_darwin_backlog dapat diatur untuk menggunakan ukuran backlog maksimum yang diizinkan. Nilai default untuk semua platform adalah Socket.SOCKET_DEFAULT_MAX_BACKLOG , saat ini ditetapkan ke 50 . Untuk penggunaan server, mungkin perlu meningkatkan nilai ini.Bluesocket mendukung tiga cara berbeda untuk membaca datagram yang masuk. Ini (dalam urutan penggunaan yang disarankan):
readDatagram(into data: inout Data) - Fungsi ini membaca datagram yang masuk dan mengembalikannya di objek Data yang dilewatkan. Ini mengembalikan tuple yang berisi jumlah byte yang dibaca dan Address dari mana data berasal.readDatagram(into data: NSMutableData) - Fungsi ini membaca datagram yang masuk dan mengembalikannya di objek NSMutableData yang dilewati. Ini mengembalikan tuple yang berisi jumlah byte yang dibaca dan Address dari mana data berasal.readDatagram(into buffer: UnsafeMutablePointer<CChar>, bufSize: Int) - Fungsi ini membaca datagram yang masuk dan mengembalikannya di objek Data yang dilewatkan. Ini mengembalikan tuple yang berisi jumlah byte yang dibaca dan Address dari mana data berasal. Jika jumlah data yang dibaca lebih dari sekadar bufSize hanya akan bufSize . Sisa dari data yang dibaca akan dibuang.Bluesocket juga memasok empat metode untuk menulis datagram ke soket. Ini (dalam urutan penggunaan yang disarankan):
write(from data: Data, to address: Address) - Fungsi ini menulis datagram yang terkandung dalam objek Data ke soket.write(from data: NSData, to address: Address) - Fungsi ini menulis datagram yang terkandung dalam objek NSData ke soket.write(from string: String, to address: Address) - Fungsi ini menulis datagram yang terkandung dalam String yang disediakan untuk soket.write(from buffer: UnsafeRawPointer, bufSize: Int, to address: Address) - Fungsi ini menulis data yang terkandung dalam buffer ukuran yang ditentukan dengan menyediakan pointer yang tidak aman untuk buffer dan bilangan bulat yang menunjukkan ukuran buffer itu.address mewakili alamat untuk tujuan yang Anda kirimkan ke Datagram. API baca dan tulis di atas yang menggunakan NSData atau NSMutableData mungkin akan sudah usang di masa depan yang tidak begitu jauh.
hostnameAndPort(from address: Address) - Fungsi kelas ini menyediakan sarana untuk mengekstrak nama host dan port dari Socket.Address yang diberikan. Setelah selesai, tuple yang berisi hostname dan port dikembalikan.checkStatus(for sockets: [Socket]) - Fungsi kelas ini memungkinkan Anda untuk memeriksa status array instance Socket . Setelah selesai, tuple yang berisi dua array Socket dikembalikan. Array pertama berisi instance Socket adalah yang memiliki data yang tersedia untuk dibaca dan array kedua berisi instance Socket yang dapat ditulis. API ini tidak memblokir. Ini akan memeriksa status setiap instance Socket dan kemudian mengembalikan hasilnya.wait(for sockets: [Socket], timeout: UInt, waitForever: Bool = false) - fungsi kelas ini memungkinkan untuk memantau array instance Socket , menunggu batas waktu terjadi atau data dapat dibaca di salah satu instance Socket yang dipantau. Jika batas waktu nol (0) ditentukan, API ini akan memeriksa setiap soket dan segera kembali. Kalau tidak, itu akan menunggu sampai batas waktu berakhir atau data dapat dibaca dari satu atau lebih instance Socket yang dipantau. Jika terjadi batas waktu, API ini akan mengembalikan nil . Jika data tersedia pada satu atau lebih dari instance Socket yang dipantau, contoh -contoh tersebut akan dikembalikan dalam array. Jika bendera waitForever diatur ke True, fungsi akan menunggu tanpa batas untuk data tersedia terlepas dari nilai batas waktu yang ditentukan .createAddress(host: String, port: Int32) - Fungsi kelas ini memungkinkan pembuatan Address enum yang diberikan host dan port . Pada keberhasilan, fungsi ini mengembalikan Address atau nil jika host yang ditentukan tidak ada.isReadableOrWritable(waitForever: Bool = false, timeout: UInt = 0) - Fungsi instan ini memungkinkan untuk menentukan apakah instance Socket dapat dibaca dan/atau dapat ditulis. Tuple dikembalikan berisi dua nilai Bool . Yang pertama, jika benar, menunjukkan instance Socket memiliki data untuk dibaca, yang kedua, jika benar, menunjukkan bahwa instance Socket dapat ditulis. waitForever jika benar, menyebabkan rutinitas ini menunggu sampai Socket dapat dibaca atau dapat ditulis atau kesalahan terjadi. Jika false, parameter timeout menentukan berapa lama menunggu. Jika nilai nol (0) ditentukan untuk nilai batas waktu, fungsi ini akan memeriksa status saat ini dan segera kembali. Fungsi ini mengembalikan tuple yang berisi dua orang boolean, yang pertama readable dan yang kedua, writable . Mereka diatur ke true jika Socket dapat dibaca atau dapat ditulis secara reparitas. Jika tidak ada yang diatur ke true, batas waktu telah terjadi. Catatan: Jika Anda mencoba menulis ke soket yang baru terhubung, Anda harus memastikan bahwa itu dapat ditulis sebelum mencoba operasi.setBlocking(shouldBlock: Bool) - Fungsi instan ini memungkinkan Anda mengontrol apakah instance Socket ini harus ditempatkan dalam mode pemblokiran atau tidak. CATATAN: Semua instance Socket , secara default , dibuat dalam mode pemblokiran .setReadTimeout(value: UInt = 0) - Fungsi instan ini memungkinkan Anda untuk mengatur batas waktu untuk operasi baca. value adalah UInt yang menentukan waktu untuk operasi baca menunggu sebelum kembali. Jika terjadi batas waktu, operasi baca akan mengembalikan 0 byte baca dan errno akan diatur ke EAGAIN .setWriteTimeout(value: UInt = 0) - Fungsi instan ini memungkinkan Anda untuk mengatur batas waktu untuk operasi tulis. value adalah UInt yang menentukan waktu untuk operasi tulis untuk menunggu sebelum kembali. Jika terjadi batas waktu, operasi tulis akan mengembalikan 0 byte yang ditulis dan errno akan diatur ke EAGAIN untuk soket TCP dan UNIX , untuk UDP , operasi tulis akan berhasil terlepas dari nilai batas waktu.udpBroadcast(enable: Bool) - Fungsi instan ini digunakan untuk mengaktifkan mode siaran pada soket UDP. Lewati true untuk mengaktifkan siaran, false untuk menonaktifkan. Fungsi ini akan melempar pengecualian jika instance Socket bukan soket UDP. Contoh berikut menunjukkan cara membuat server gema multi-threaded yang relatif sederhana menggunakan API pengiriman GCD based baru. Berikut ini adalah kode untuk server gema sederhana yang pernah berjalan, dapat diakses melalui telnet ::1 1337 .
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 ( ) Server ini dapat dibangun dengan menentukan Package.swift berikut. Menggunakan Swift 4.
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 "
] ) ,
]
) Atau jika Anda masih menggunakan Swift 3, dengan menentukan paket Package.swift berikut.
import PackageDescription
let package = Package (
name : " EchoServer " ,
dependencies : [
. Package ( url : " https://github.com/Kitura/BlueSocket.git " , majorVersion : 1 , minor : 0 ) ,
] ,
exclude : [ " EchoServer.xcodeproj " ]
) Urutan perintah berikut akan membangun dan menjalankan server Echo di Linux. Jika berjalan di macOS atau dengan toolchain apa pun yang lebih baru dari toolchain 8/18, Anda dapat menghilangkan sakelar -Xcc -fblocks karena tidak diperlukan lagi.
$ 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
Kami senang berbicara dengan Swift dan Kitura di sisi server. Bergabunglah dengan kelonggaran kami untuk bertemu tim!
Perpustakaan ini dilisensikan di bawah Apache 2.0. Teks lisensi lengkap tersedia dalam lisensi.