Socket Framework สำหรับ Swift โดยใช้ Swift Package Manager ใช้งานได้กับ iOS, MacOS และ Linux
swift-5.1-RELEASE Toolchain ( ขั้นต่ำที่จำเป็นสำหรับการเปิดตัวล่าสุด )swift-5.4-RELEASE toolchain ( แนะนำ )บันทึก:
หากสร้างเซิร์ฟเวอร์ UDP บน iOS คุณอาจต้องทำตามขั้นตอนสองสามขั้นตอน:
เพื่อสร้างซ็อกเก็ตจากบรรทัดคำสั่ง:
% cd <path-to-clone>
% swift build
ในการเรียกใช้การทดสอบหน่วยที่ให้มาสำหรับ ซ็อกเก็ต จากบรรทัดคำสั่ง:
% cd <path-to-clone>
% swift build
% swift test
หากต้องการรวม Bluesocket ลงในแพ็คเกจ Swift Package ให้เพิ่มลงในแอตทริบิวต์ dependencies ที่กำหนดไว้ในไฟล์ Package.swift ของคุณ คุณสามารถเลือกเวอร์ชันโดยใช้พารามิเตอร์ majorVersion และ minor ตัวอย่างเช่น:
dependencies: [
.Package(url: "https://github.com/Kitura/BlueSocket.git", majorVersion: <majorVersion>, minor: <minor>)
]
หากต้องการรวม Bluesocket ในโครงการที่ใช้ Carthage ให้เพิ่มบรรทัดลงใน Cartfile ของคุณด้วยองค์กร GitHub และชื่อโครงการและเวอร์ชัน ตัวอย่างเช่น:
github "Kitura/BlueSocket" ~> <majorVersion>.<minor>
ในการรวม Bluesocket ในโครงการที่ใช้ Cocoapods คุณเพียงเพิ่ม BlueSocket ลงใน Podfile ของคุณเช่น:
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 ให้วิธีการโรงงานที่แตกต่างกันสี่วิธีที่ใช้ในการสร้างอินสแตนซ์ นี่คือ:
create() - สิ่งนี้สร้างซ็อกเก็ตเริ่มต้นที่กำหนดค่าไว้อย่างสมบูรณ์ ซ็อกเก็ตเริ่มต้นถูกสร้างขึ้นด้วย family: .inet , type: .stream และ proto: .tcpcreate(family family: ProtocolFamily, type: SocketType, proto: SocketProtocol) - API นี้ช่วยให้คุณสร้างอินสแตนซ์ของ Socket ที่กำหนดค่าไว้สำหรับความต้องการของคุณ คุณสามารถปรับแต่งตระกูลโปรโตคอลประเภทซ็อกเก็ตและซ็อกเก็ตโปรโตคอลcreate(connectedUsing signature: Signature) - API นี้จะช่วยให้คุณสร้างอินสแตนซ์ของ Socket และพยายามเชื่อมต่อกับเซิร์ฟเวอร์ตามข้อมูลที่คุณส่งผ่านใน Socket.Signaturecreate(fromNativeHandle nativeHandle: Int32, address: Address?) - API นี้ช่วยให้คุณสามารถห่อ descriptor ไฟล์ดั้งเดิมที่อธิบายถึงซ็อกเก็ตที่มีอยู่ในอินสแตนซ์ใหม่ของ 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 Socket.SOCKET_MAX_DARWIN_BACKLOG สามารถตั้งค่าให้ใช้ขนาด backlog สูงสุดที่อนุญาต ค่าเริ่มต้นสำหรับแพลตฟอร์มทั้งหมดคือ Socket.SOCKET_DEFAULT_MAX_BACKLOG ปัจจุบันตั้งค่าเป็น 50 สำหรับการใช้งานเซิร์ฟเวอร์อาจจำเป็นต้องเพิ่มค่านี้ หากต้องการอนุญาตให้นำพอร์ตการฟังกลับมาใช้ใหม่ให้ตั้งค่า allowPortReuse ให้ใช้เป็น true หากตั้งค่าเป็น false ข้อผิดพลาดจะเกิดขึ้นหากคุณพยายามฟังบนพอร์ตที่ใช้งานอยู่แล้ว พฤติกรรม DEFAULT คือ allow พอร์ตกลับมาใช้ใหม่ พารามิเตอร์สุดท้าย node สามารถใช้ฟังตาม ที่อยู่เฉพาะ ค่าที่ส่งผ่านเป็น สตริงเสริม ที่มีที่อยู่เครือข่ายตัวเลข (สำหรับ IPv4, ตัวเลขและสัญลักษณ์จุดสำหรับ IPv6, hexidecimal strting) พฤติกรรม 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 Socket.SOCKET_MAX_DARWIN_BACKLOG สามารถตั้งค่าให้ใช้ขนาด 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 ที่แนบมาคุณ ต้อง เรียกใช้วิธีการเรียกใช้งาน invokeDelegateOnAccept โดยใช้อินสแตนซ์ Socket เก็ตที่ส่งคืนโดยฟังก์ชั่นนี้invokeDelegateOnAccept(for newSocket: Socket) - หากอินสแตนซ์ของ Socket มีตัวแทน SSLService สิ่งนี้จะเรียกร้องให้ผู้แทนยอมรับฟังก์ชั่นเพื่อทำการเจรจา SSL มันควรจะเรียกด้วยอินสแตนซ์ Socket ที่ส่งคืนโดย acceptClientConnection ฟังก์ชั่นนี้จะโยนข้อยกเว้นหากเรียกด้วยอินสแตน Socket เก็ตที่ไม่ถูกต้องที่เรียกว่าหลายครั้งหรือหากอินสแตนซ์ Socket เก็ต ไม่มี ตัวแทน SSLServiceacceptConnection() - ฟังก์ชั่นนี้ยอมรับการเชื่อมต่อที่เข้ามา แทนที่และปิด ซ็อกเก็ตการฟังที่มีอยู่ คุณสมบัติที่ก่อนหน้านี้เกี่ยวข้องกับซ็อกเก็ตการฟังจะถูกแทนที่ด้วยคุณสมบัติที่เกี่ยวข้องกับซ็อกเก็ตที่เชื่อมต่อใหม่ นอกเหนือจาก create(connectedUsing:) วิธีการที่อธิบายไว้ข้างต้น Bluesocket ยังรองรับฟังก์ชั่นอินสแตนซ์เพิ่มเติมสามฟังก์ชั่นสำหรับการเชื่อมต่อ Socket ซ์ซ็อกเก็ตกับเซิร์ฟเวอร์ พวกเขาคือ:
connect(to host: String, port: Int32, timeout: UInt = 0) - API นี้ช่วยให้คุณสามารถเชื่อมต่อกับเซิร์ฟเวอร์ตาม hostname และ port ที่คุณมีให้ หมายเหตุ: exception จะถูกโยนลงโดยฟังก์ชั่นนี้หากค่าของ port ไม่อยู่ในช่วง 1-65535 ทางเลือกคุณสามารถตั้ง timeout เป็นจำนวนมิลลิวินาทีเพื่อรอการเชื่อมต่อ หมายเหตุ: หากซ็อกเก็ตอยู่ในโหมดการปิดกั้นมันจะถูกเปลี่ยนเป็นโหมดที่ไม่ปิดกั้น ชั่วคราว หากมี timeout มากกว่าศูนย์ (0) ซ็อกเก็ตที่ส่งคืนจะถูก ตั้งค่ากลับไปที่การตั้งค่าดั้งเดิม (บล็อกหรือไม่ปิดกั้น) หากซ็อกเก็ตถูกตั้งค่าเป็นแบบ ไม่ปิดกั้น และ ไม่มีค่าหมดเวลาจะมี ข้อยกเว้นจะถูกโยนทิ้ง หรือคุณสามารถตั้งค่าซ็อกเก็ตให้ ไม่ปิดกั้น หลังจากเชื่อมต่อสำเร็จconnect(to path: String) - API นี้สามารถใช้กับตระกูลโปรโตคอล. .unix เท่านั้น ช่วยให้คุณสามารถเชื่อมต่อกับเซิร์ฟเวอร์ตาม path ที่คุณให้connect(using signature: Signature) - API นี้ช่วยให้คุณระบุข้อมูลการเชื่อมต่อโดยให้อินสแตนซ์ Socket.Signature ลงนามที่มีข้อมูล อ้างถึง Socket.Signature ใน Socket.swift สำหรับข้อมูลเพิ่มเติมBluesocket รองรับสี่วิธีที่แตกต่างกันในการอ่านข้อมูลจากซ็อกเก็ต เหล่านี้คือ (ตามลำดับการใช้งานที่แนะนำ):
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 หากบัฟเฟอร์ที่ให้ไว้มี bufSize เล็กเกินไปเว้นแต่จะ truncate = true หาก truncate = false คุณจะต้องโทรอีกครั้งด้วยขนาดบัฟเฟอร์ที่เหมาะสม (ดู Error.bufferSizeNeeded ใน socket.swift สำหรับข้อมูลเพิ่มเติม)readString() สามารถส่งคืนศูนย์ (0) สิ่งนี้สามารถบ่งชี้ว่าการเชื่อมต่อระยะไกลถูกปิดหรืออาจระบุว่าซ็อกเก็ตจะบล็อก (สมมติว่าคุณปิดการบล็อก) เพื่อแยกความแตกต่างระหว่างทั้งสองคุณสมบัติ remoteConnectionClosed สามารถตรวจสอบได้ หาก true คู่ค้าระยะไกลซ็อกเก็ตได้ปิดการเชื่อมต่อและควรปิดอินสแตนซ์ Socket เก็ตนี้นอกเหนือจากการอ่านจากซ็อกเก็ตแล้ว Bluesocket ยังให้วิธีการสี่วิธีในการเขียนข้อมูลไปยังซ็อกเก็ต เหล่านี้คือ (ตามลำดับการใช้งานที่แนะนำ):
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 ที่ผ่าน มันส่งคืน tuple ที่มีจำนวนไบต์ที่อ่านและ Address ของข้อมูลที่เกิดขึ้นlisten(forMessage data: NSMutableData, on port: Int, maxBacklogSize: Int = Socket.SOCKET_DEFAULT_MAX_BACKLOG) - ฟังก์ชั่นนี้ฟังข้อมูลที่เข้ามาอ่านและส่งคืนในวัตถุ NSMutableData ที่ผ่าน มันส่งคืน tuple ที่มีจำนวนไบต์ที่อ่านและ Address ของข้อมูลที่เกิดขึ้นlisten(forMessage buffer: UnsafeMutablePointer<CChar>, bufSize: Int, on port: Int, maxBacklogSize: Int = Socket.SOCKET_DEFAULT_MAX_BACKLOG) - ฟังก์ชั่นนี้ฟัง Data ที่เข้ามา มันส่งคืน tuple ที่มีจำนวนไบต์ที่อ่านและ Address ของข้อมูลที่เกิดขึ้นport ที่ระบุ การตั้งค่า port เป็นศูนย์ (0) จะทำให้ฟังก์ชันกำหนดพอร์ตฟรีที่เหมาะสมmaxBacklogSize ช่วยให้คุณสามารถตั้งค่าขนาดของการเชื่อมต่อคิวที่ค้างอยู่ ฟังก์ชั่นจะกำหนดการกำหนดค่าซ็อกเก็ตที่เหมาะสมตาม port ที่ระบุ เพื่อความสะดวกใน MacOS Socket.SOCKET_MAX_DARWIN_BACKLOG สามารถตั้งค่าให้ใช้ขนาด backlog สูงสุดที่อนุญาต ค่าเริ่มต้นสำหรับแพลตฟอร์มทั้งหมดคือ Socket.SOCKET_DEFAULT_MAX_BACKLOG ปัจจุบันตั้งค่าเป็น 50 สำหรับการใช้งานเซิร์ฟเวอร์อาจจำเป็นต้องเพิ่มค่านี้Bluesocket รองรับสามวิธีที่แตกต่างกันในการอ่าน Datagrams ที่เข้ามา เหล่านี้คือ (ตามลำดับการใช้งานที่แนะนำ):
readDatagram(into data: inout Data) - ฟังก์ชั่นนี้อ่านดาต้าแกรมขาเข้าและส่งคืนในวัตถุ Data ที่ผ่าน มันส่งคืน tuple ที่มีจำนวนไบต์ที่อ่านและ Address ของข้อมูลที่เกิดขึ้นreadDatagram(into data: NSMutableData) - ฟังก์ชั่นนี้อ่านดาต้าแกรมที่เข้ามาและส่งคืนในวัตถุ NSMutableData ที่ผ่าน มันส่งคืน tuple ที่มีจำนวนไบต์ที่อ่านและ Address ของข้อมูลที่เกิดขึ้นreadDatagram(into buffer: UnsafeMutablePointer<CChar>, bufSize: Int) - ฟังก์ชั่นนี้อ่านดาต้าแกรมขาเข้าและส่งคืนในวัตถุ Data ที่ผ่าน มันส่งคืน tuple ที่มีจำนวนไบต์ที่อ่านและ Address ของข้อมูลที่เกิดขึ้น หากจำนวนข้อมูลที่อ่านเป็นมากกว่า bufSize เท่านั้น bufSize จะถูกส่งคืน ส่วนที่เหลือของข้อมูลที่อ่านจะถูกยกเลิกBluesocket ยังจัดหาสี่วิธีในการเขียนดาต้าแกรมไปยังซ็อกเก็ต เหล่านี้คือ (ตามลำดับการใช้งานที่แนะนำ):
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 แสดงถึงที่อยู่สำหรับปลายทางที่คุณกำลังส่งดาต้าแกรมไป การอ่านและเขียน APIs ด้านบนที่ใช้ NSData หรือ NSMutableData อาจ จะ เลิกใช้ ในอนาคตอันไกลโพ้น
hostnameAndPort(from address: Address) - ฟังก์ชั่นคลาส นี้ให้วิธีการแยกชื่อโฮสต์และพอร์ตจาก Socket.Address ที่กำหนด เมื่อสำเร็จแล้ว tuple ที่มี hostname และ port จะถูกส่งคืนcheckStatus(for sockets: [Socket]) - ฟังก์ชั่นคลาส นี้ช่วยให้คุณสามารถตรวจสอบสถานะของอาร์เรย์ของอินสแตนซ์ Socket เก็ต เมื่อเสร็จสิ้น tuple ที่มี Socket สองอาร์เรย์จะถูกส่งคืน อาร์เรย์แรกมีอินสแตนซ์ของ Socket เก็ตคือมีข้อมูลที่จะอ่านและอาร์เรย์ที่สองมีอินสแตนซ์ Socket เก็ตที่สามารถเขียนได้ API นี้ ไม่ได้ บล็อก มันจะตรวจสอบสถานะของแต่ละอินสแตนซ์ Socket เก็ตจากนั้นส่งคืนผลลัพธ์wait(for sockets: [Socket], timeout: UInt, waitForever: Bool = false) - ฟังก์ชั่นคลาส นี้อนุญาตให้ตรวจสอบอาร์เรย์ของอินสแตนซ์ซ็ Socket เก็ตรอการหมดเวลาใด ๆ ที่จะเกิดขึ้นหรือข้อมูลที่สามารถอ่านได้ที่หนึ่งในอินสแตนซ์ Socket เก็ตที่ตรวจสอบ หากระบุการหมดเวลาเป็นศูนย์ (0) API นี้จะตรวจสอบซ็อกเก็ตแต่ละตัวและส่งคืนทันที มิฉะนั้นจะรอจนกว่าการหมดเวลาจะหมดอายุหรือข้อมูลสามารถอ่านได้จากอินสแตนซ์ของ Socket ตที่ตรวจสอบอย่างน้อยหนึ่งรายการ หากการหมดเวลาเกิดขึ้น API นี้จะกลับมา nil หากข้อมูลมีอยู่ในอินสแตนซ์ของ Socket เก็ตที่ตรวจสอบอย่างน้อยหนึ่งอินสแตนซ์เหล่านั้นจะถูกส่งกลับในอาร์เรย์ หากตั้งค่าสถานะ waitForever เป็นจริงฟังก์ชั่นจะรอข้อมูลอย่างไม่มีกำหนด โดยไม่คำนึงถึงค่าหมดเวลาที่ระบุไว้createAddress(host: String, port: Int32) - ฟังก์ชั่น คลาส นี้อนุญาตให้สร้าง Address enum ให้ host และ port ในความสำเร็จฟังก์ชั่นนี้ส่งคืน Address หรือ nil หาก host ที่ระบุไม่มีอยู่isReadableOrWritable(waitForever: Bool = false, timeout: UInt = 0) - ฟังก์ชั่นอินสแตนซ์ นี้อนุญาตให้ตรวจสอบว่าอินสแตนซ์ของ Socket สามารถอ่านได้และ/หรือเขียนได้ tuple จะถูกส่งคืนที่มีค่า Bool สองค่า ครั้งแรกถ้าเป็นจริงระบุอินสแตนซ์ Socket มีข้อมูลที่จะอ่านครั้งที่สองถ้าเป็นจริงแสดงว่าสามารถเขียนอินสแตนซ์ของ Socket ได้ waitForever ถ้าเป็นจริงทำให้รูทีนนี้รอจนกว่า Socket จะอ่านได้หรือเขียนได้หรือเกิดข้อผิดพลาด หากเท็จพารามิเตอร์ timeout จะระบุระยะเวลาที่จะรอ หากมีการระบุค่าศูนย์ (0) สำหรับค่าหมดเวลาฟังก์ชั่นนี้จะตรวจสอบสถานะ ปัจจุบัน และส่งคืน ทันที ฟังก์ชั่นนี้ส่งคืน tuple ที่มีสองบูลีน, readable ครั้งแรกและที่สอง writable พวกเขาถูกตั้งค่าเป็นจริงหาก Socket เป็นตัวแทนที่อ่านได้หรือเขียนได้ หากไม่มีการตั้งค่าเป็นจริงจะมีการหมดเวลาเกิดขึ้น หมายเหตุ: หากคุณกำลังพยายามเขียนลงใน ซ็อกเก็ต ที่เชื่อมต่อใหม่คุณควรตรวจสอบให้แน่ใจว่าเป็น เรื่องเขียนได้ ก่อนที่จะพยายามดำเนินการsetBlocking(shouldBlock: Bool) - ฟังก์ชั่นอินสแตนซ์ นี้ช่วยให้คุณสามารถควบคุมได้ว่าควรวางอินสแตนซ์ซ็ Socket นี้ไว้ในโหมดปิดกั้นหรือไม่ หมายเหตุ: อินสแตนซ์ Socket ทั้งหมดเป็น ค่าเริ่มต้น ที่สร้างขึ้นใน โหมดการปิดกั้นsetReadTimeout(value: UInt = 0) - ฟังก์ชั่นอินสแตนซ์ นี้อนุญาตให้คุณตั้งค่าการหมดเวลาสำหรับการดำเนินการอ่าน value คือ UInt ที่ระบุเวลาสำหรับการดำเนินการอ่านเพื่อรอก่อนกลับ ในกรณีที่หมดเวลาการดำเนินการอ่านจะส่งคืน 0 ไบต์อ่านและ errno จะถูกตั้งค่าเป็น EAGAINsetWriteTimeout(value: UInt = 0) - ฟังก์ชั่นอินสแตนซ์ นี้อนุญาตให้คุณตั้งค่าการหมดเวลาสำหรับการดำเนินการเขียน value คือ UInt ที่ระบุเวลาสำหรับการดำเนินการเขียนเพื่อรอก่อนกลับ ในกรณีที่มีการหมดเวลาการดำเนินการเขียนจะส่งคืน 0 ไบต์ที่เขียนและ errno จะถูกตั้งค่าเป็น EAGAIN สำหรับซ็อกเก็ต TCP และ UNIX สำหรับ UDP การดำเนินการเขียนจะ ประสบความสำเร็จ โดยไม่คำนึงถึงค่าหมดเวลาudpBroadcast(enable: Bool) - ฟังก์ชั่นอินสแตนซ์ นี้ใช้เพื่อเปิดใช้งานโหมดการออกอากาศบนซ็อกเก็ต UDP ผ่าน true เพื่อเปิดใช้งานการออกอากาศ false เพื่อปิดการใช้งาน ฟังก์ชั่นนี้จะโยนข้อยกเว้นหาก Socket ซ์ซ็อกเก็ตไม่ใช่ซ็อกเก็ต UDP ตัวอย่างต่อไปนี้แสดงวิธีสร้างเซิร์ฟเวอร์ Echo แบบมัลติเธรดที่ค่อนข้างง่ายโดยใช้ API Dispatch API GCD based ใหม่ สิ่งต่อไปนี้คือรหัสสำหรับเซิร์ฟเวอร์ Echo แบบง่ายที่เมื่อทำงานสามารถเข้าถึงได้ผ่าน 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 ( ) เซิร์ฟเวอร์นี้สามารถสร้างขึ้นได้โดยการระบุไฟล์ Package.swift ต่อไปนี้โดยใช้ 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 "
] ) ,
]
) หรือถ้าคุณยังใช้ 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 " ]
) ลำดับคำสั่งต่อไปนี้จะสร้างและเรียกใช้เซิร์ฟเวอร์ Echo บน Linux หากทำงานบน macOS หรือกับเครื่องมือใด ๆ ที่ใหม่ กว่า 8/18 toolchain คุณสามารถละเว้นสวิตช์ -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
เราชอบที่จะพูดคุยด้านเซิร์ฟเวอร์ Swift และ Kitura เข้าร่วม Slack ของเราเพื่อพบกับทีม!
ไลบรารีนี้ได้รับอนุญาตภายใต้ Apache 2.0 ข้อความใบอนุญาตเต็มรูปแบบมีอยู่ในใบอนุญาต