🎯 Exemples recommandés
Balanced sample collections from various categories for you to explore
Exemples de Réseau macOS Swift
Exemples de réseau macOS Swift incluant les requêtes HTTP, serveur HTTP et programmation de sockets TCP
💻 Requête HTTP swift
🟡 intermediate
⭐⭐⭐
Envoyer des requêtes GET et POST en utilisant URLSession avec une gestion appropriée des erreurs et du traitement des réponses
⏱️ 25 min
🏷️ swift, macos, networking, http
Prerequisites:
Basic Swift knowledge, Foundation framework, Networking concepts
// macOS Swift HTTP Request Examples
// Using Foundation framework
import Foundation
// 1. Simple GET Request
class SimpleGETRequest {
static func fetch(url: String) {
print("\n--- Simple GET Request ---")
guard let url = URL(string: url) else {
print("Invalid URL")
return
}
let task = URLSession.shared.dataTask(with: url) { data, response, error in
if let error = error {
print("Error: \(error.localizedDescription)")
return
}
guard let httpResponse = response as? HTTPURLResponse else {
print("Invalid response")
return
}
print("Status Code: \(httpResponse.statusCode)")
if let data = data, let content = String(data: data, encoding: .utf8) {
print("Response (first 200 chars): \(String(content.prefix(200)))")
}
}
task.resume()
}
}
// 2. GET Request with Parameters
class GETWithParameters {
static func fetchWithParams(baseUrl: String, params: [String: String]) {
print("\n--- GET with Parameters ---")
guard var urlComponents = URLComponents(string: baseUrl) else {
print("Invalid URL")
return
}
urlComponents.queryItems = params.map { key, value in
URLQueryItem(name: key, value: value)
}
guard let url = urlComponents.url else {
print("Invalid URL with parameters")
return
}
print("Request URL: \(url.absoluteString)")
let task = URLSession.shared.dataTask(with: url) { data, response, error in
if let error = error {
print("Error: \(error.localizedDescription)")
return
}
if let httpResponse = response as? HTTPURLResponse {
print("Status Code: \(httpResponse.statusCode)")
}
}
task.resume()
}
}
// 3. POST Request with JSON Body
class POSTRequest {
static func postJSON(url: String, body: [String: Any]) {
print("\n--- POST JSON Request ---")
guard let url = URL(string: url) else {
print("Invalid URL")
return
}
var request = URLRequest(url: url)
request.httpMethod = "POST"
request.setValue("application/json", forHTTPHeaderField: "Content-Type")
do {
let jsonData = try JSONSerialization.data(withJSONObject: body, options: .prettyPrinted)
request.httpBody = jsonData
if let jsonString = String(data: jsonData, encoding: .utf8) {
print("Request Body: \(jsonString)")
}
let task = URLSession.shared.dataTask(with: request) { data, response, error in
if let error = error {
print("Error: \(error.localizedDescription)")
return
}
if let httpResponse = response as? HTTPURLResponse {
print("Status Code: \(httpResponse.statusCode)")
}
if let data = data, let responseString = String(data: data, encoding: .utf8) {
print("Response: \(responseString)")
}
}
task.resume()
} catch {
print("JSON serialization error: \(error)")
}
}
}
// 4. POST Request with Form Data
class POSTFormData {
static func postForm(url: String, params: [String: String]) {
print("\n--- POST Form Data ---")
guard let url = URL(string: url) else {
print("Invalid URL")
return
}
var request = URLRequest(url: url)
request.httpMethod = "POST"
let formString = params.map { key, value in
"\(key)=\(value.addingPercentEncoding(withAllowedCharacters: .urlQueryAllowed) ?? value)"
}.joined(separator: "&")
request.setValue("application/x-www-form-urlencoded", forHTTPHeaderField: "Content-Type")
request.httpBody = formString.data(using: .utf8)
print("Form Data: \(formString)")
let task = URLSession.shared.dataTask(with: request) { data, response, error in
if let error = error {
print("Error: \(error.localizedDescription)")
return
}
if let httpResponse = response as? HTTPURLResponse {
print("Status Code: \(httpResponse.statusCode)")
}
}
task.resume()
}
}
// 5. Request with Custom Headers
class RequestWithHeaders {
static func fetchWithHeaders(url: String, headers: [String: String]) {
print("\n--- Request with Custom Headers ---")
guard let url = URL(string: url) else {
print("Invalid URL")
return
}
var request = URLRequest(url: url)
for (key, value) in headers {
request.setValue(value, forHTTPHeaderField: key)
print("\(key): \(value)")
}
let task = URLSession.shared.dataTask(with: request) { data, response, error in
if let error = error {
print("Error: \(error.localizedDescription)")
return
}
if let httpResponse = response as? HTTPURLResponse {
print("Status Code: \(httpResponse.statusCode)")
print("Response Headers:")
if let allHeaders = httpResponse.allHeaderFields as? [String: String] {
for (key, value) in allHeaders {
print(" \(key): \(value)")
}
}
}
}
task.resume()
}
}
// 6. Download File
class DownloadFile {
static func downloadFile(url: String, destination: String) {
print("\n--- Download File ---")
guard let url = URL(string: url) else {
print("Invalid URL")
return
}
let task = URLSession.shared.downloadTask(with: url) { tempURL, response, error in
if let error = error {
print("Error: \(error.localizedDescription)")
return
}
guard let tempURL = tempURL else {
print("Invalid temp URL")
return
}
do {
let fileManager = FileManager.default
let destURL = URL(fileURLWithPath: destination)
// Create directory if needed
let destDir = destURL.deletingLastPathComponent()
if !fileManager.fileExists(atPath: destDir.path) {
try fileManager.createDirectory(atPath: destDir.path, withIntermediateDirectories: true)
}
// Remove existing file
if fileManager.fileExists(atPath: destination) {
try fileManager.removeItem(atPath: destination)
}
// Move file
try fileManager.moveItem(at: tempURL, to: destURL)
let attributes = try fileManager.attributesOfItem(atPath: destination)
if let fileSize = attributes[.size] as? UInt64 {
print("Downloaded: \(destination)")
print("File size: \(fileSize) bytes")
}
} catch {
print("File save error: \(error)")
}
}
task.resume()
}
}
// 7. Upload File with Progress
class UploadFile {
static func uploadFile(url: String, filePath: String) {
print("\n--- Upload File ---")
guard let url = URL(string: url) else {
print("Invalid URL")
return
}
guard let fileData = try? Data(contentsOf: URL(fileURLWithPath: filePath)) else {
print("Cannot read file")
return
}
var request = URLRequest(url: url)
request.httpMethod = "POST"
let boundary = "Boundary-\(UUID().uuidString)"
request.setValue("multipart/form-data; boundary=\(boundary)", forHTTPHeaderField: "Content-Type")
var body = Data()
// Add file data
body.append("--\(boundary)\r\n".data(using: .utf8)!)
body.append("Content-Disposition: form-data; name=\"file\"; filename=\"\((filePath as NSString).lastPathComponent)\"\r\n".data(using: .utf8)!)
body.append("Content-Type: application/octet-stream\r\n\r\n".data(using: .utf8)!)
body.append(fileData)
body.append("\r\n".data(using: .utf8)!)
body.append("--\(boundary)--\r\n".data(using: .utf8)!)
request.httpBody = body
let task = URLSession.shared.dataTask(with: request) { data, response, error in
if let error = error {
print("Error: \(error.localizedDescription)")
return
}
if let httpResponse = response as? HTTPURLResponse {
print("Status Code: \(httpResponse.statusCode)")
}
print("Upload completed")
}
task.resume()
}
}
// 8. Request with Timeout
class RequestWithTimeout {
static func fetchWithTimeout(url: String, timeout: TimeInterval) {
print("\n--- Request with Timeout ---")
guard let url = URL(string: url) else {
print("Invalid URL")
return
}
let configuration = URLSessionConfiguration.default
configuration.timeoutIntervalForRequest = timeout
let session = URLSession(configuration: configuration)
let task = session.dataTask(with: url) { data, response, error in
if let error = error {
print("Error: \(error.localizedDescription)")
return
}
if let httpResponse = response as? HTTPURLResponse {
print("Status Code: \(httpResponse.statusCode)")
}
}
task.resume()
}
}
// 9. Async/Await HTTP Request (Swift 5.5+)
@available(macOS 12.0, *)
class ModernHTTPRequest {
static func fetchAsync(url: String) async {
print("\n--- Async/Await Request ---")
guard let url = URL(string: url) else {
print("Invalid URL")
return
}
do {
let (data, response) = try await URLSession.shared.data(from: url)
if let httpResponse = response as? HTTPURLResponse {
print("Status Code: \(httpResponse.statusCode)")
}
if let content = String(data: data, encoding: .utf8) {
print("Response (first 200 chars): \(String(content.prefix(200)))")
}
} catch {
print("Error: \(error.localizedDescription)")
}
}
}
// 10. Request with Response Decoding
struct User: Codable {
let id: Int
let name: String
let email: String
}
class RequestWithDecoding {
static func fetchAndDecode<T: Decodable>(url: String, type: T.Type) {
print("\n--- Request with Decoding ---")
guard let url = URL(string: url) else {
print("Invalid URL")
return
}
let task = URLSession.shared.dataTask(with: url) { data, response, error in
guard let data = data else {
if let error = error {
print("Error: \(error.localizedDescription)")
}
return
}
do {
let decoder = JSONDecoder()
let result = try decoder.decode(type, from: data)
print("Decoded result: \(result)")
} catch {
print("Decoding error: \(error)")
}
}
task.resume()
}
}
// Main demonstration
func demonstrateHTTPRequests() {
print("=== macOS Swift HTTP Request Examples ===")
// Note: Using example.com for demonstration
// In real usage, replace with actual API endpoints
// 1. Simple GET
SimpleGETRequest.fetch(url: "https://example.com")
Thread.sleep(forTimeInterval: 1)
// 2. GET with parameters
GETWithParameters.fetchWithParams(
baseUrl: "https://httpbin.org/get",
params: ["param1": "value1", "param2": "value2"]
)
Thread.sleep(forTimeInterval: 1)
// 3. POST JSON
POSTRequest.postJSON(
url: "https://httpbin.org/post",
body: ["name": "John Doe", "email": "[email protected]", "age": 30]
)
Thread.sleep(forTimeInterval: 1)
// 4. POST Form Data
POSTFormData.postForm(
url: "https://httpbin.org/post",
params: ["username": "testuser", "password": "testpass"]
)
Thread.sleep(forTimeInterval: 1)
// 5. Custom Headers
RequestWithHeaders.fetchWithHeaders(
url: "https://httpbin.org/headers",
headers: [
"User-Agent": "SwiftNetworking/1.0",
"Accept": "application/json",
"Authorization": "Bearer token123"
]
)
Thread.sleep(forTimeInterval: 1)
// 6. Download File
DownloadFile.downloadFile(
url: "https://example.com",
destination: "/tmp/downloaded_file.html"
)
Thread.sleep(forTimeInterval: 1)
// 7. Request with Timeout
RequestWithTimeout.fetchWithTimeout(url: "https://example.com", timeout: 5)
Thread.sleep(forTimeInterval: 1)
// 8. Async Request (if available)
if #available(macOS 12.0, *) {
Task {
await ModernHTTPRequest.fetchAsync(url: "https://example.com")
}
Thread.sleep(forTimeInterval: 1)
}
// 9. Request with Decoding
RequestWithDecoding.fetchAndDecode(
url: "https://jsonplaceholder.typicode.com/users/1",
type: User.self
)
Thread.sleep(forTimeInterval: 2)
print("\n=== All HTTP Request Examples Completed ===")
}
// Run demonstration
demonstrateHTTPRequests()
💻 Socket TCP swift
🟡 intermediate
⭐⭐⭐⭐
Créer des sockets client et serveur TCP pour une communication bidirectionnelle
⏱️ 40 min
🏷️ swift, macos, networking, tcp
Prerequisites:
Intermediate Swift, Socket programming, Networking concepts
// macOS Swift TCP Socket Examples
// Using Foundation and Network framework
import Foundation
// 1. TCP Server
class TCPServer {
private var serverSocket: Int32 = -1
private var isRunning = false
private var clientHandlers: [Thread] = []
func start(port: UInt16) {
print("\n--- Starting TCP Server on port \(port) ---")
// Create socket
serverSocket = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP)
guard serverSocket != -1 else {
print("Failed to create socket")
return
}
// Set socket options
var yes: Int32 = 1
setsockopt(serverSocket, SOL_SOCKET, SO_REUSEADDR, &yes, socklen_t(MemoryLayout<Int32>.size))
// Bind to address
var address = sockaddr_in()
address.sin_family = sa_family_t(AF_INET)
address.sin_port = port.bigEndian
address.sin_addr.s_addr = INADDR_ANY
let bindResult = withUnsafePointer(to: &address) {
$0.withMemoryRebound(to: sockaddr.self, capacity: 1) {
bind(serverSocket, $0, socklen_t(MemoryLayout<sockaddr_in>.size))
}
}
guard bindResult == 0 else {
print("Failed to bind to port: \(errno)")
close(serverSocket)
return
}
// Listen
guard listen(serverSocket, 5) == 0 else {
print("Failed to listen")
close(serverSocket)
return
}
isRunning = true
print("Server listening on port \(port)")
// Accept connections
DispatchQueue.global(qos: .background).async { [weak self] in
self?.acceptConnections()
}
}
private func acceptConnections() {
while isRunning {
var clientAddress = sockaddr_in()
var addressLength = socklen_t(MemoryLayout<sockaddr_in>.size)
let clientSocket = withUnsafeMutablePointer(to: &clientAddress) {
$0.withMemoryRebound(to: sockaddr.self, capacity: 1) {
accept(serverSocket, $0, &addressLength)
}
}
guard clientSocket != -1 else {
continue
}
// Get client info
let clientIP = getIPAddress(from: &clientAddress)
print("Client connected from \(clientIP)")
// Handle client
handleClient(socket: clientSocket)
}
}
private func handleClient(socket: Int32) {
DispatchQueue.global(qos: .background).async {
var buffer = [UInt8](repeating: 0, count: 1024)
while true {
let bytesRead = read(socket, &buffer, buffer.count)
if bytesRead <= 0 {
close(socket)
print("Client disconnected")
return
}
if let message = String(bytes: buffer.prefix(bytesRead), encoding: .utf8) {
print("Received: \(message)")
// Echo back
let response = "Echo: \(message)"
response.withCString { ptr in
write(socket, ptr, response.count)
}
}
}
}
}
private func getIPAddress(from address: inout sockaddr_in) -> String {
var ipAddress = [CChar](repeating: 0, count: Int(INET_ADDRSTRLEN))
withUnsafePointer(to: &address.sin_addr) {
inet_ntop(AF_INET, $0, &ipAddress, socklen_t(INET_ADDRSTRLEN))
}
return String(cString: ipAddress)
}
func broadcast(_ message: String) {
// Broadcast to all connected clients
// Implementation depends on how you track clients
}
func stop() {
isRunning = false
if serverSocket != -1 {
close(serverSocket)
}
print("Server stopped")
}
}
// 2. TCP Client
class TCPClient {
private var clientSocket: Int32 = -1
func connect(host: String, port: UInt16) -> Bool {
print("\n--- Connecting to \(host):\(port) ---")
// Create socket
clientSocket = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP)
guard clientSocket != -1 else {
print("Failed to create socket")
return false
}
// Resolve host
var hints = addrinfo()
hints.ai_family = AF_INET
hints.ai_socktype = SOCK_STREAM
var result: UnsafeMutablePointer<addrinfo>?
let status = getaddrinfo(host, String(port), &hints, &result)
guard status == 0, let info = result else {
print("Failed to resolve host")
close(clientSocket)
return false
}
defer { freeaddrinfo(info) }
// Connect
guard connect(clientSocket, info.pointee.ai_addr, info.pointee.ai_addrlen) == 0 else {
print("Failed to connect: \(errno)")
close(clientSocket)
return false
}
print("Connected to server")
return true
}
func send(_ message: String) -> Bool {
guard clientSocket != -1 else {
print("Not connected")
return false
}
let bytesSent = message.withCString { ptr in
write(clientSocket, ptr, message.count)
}
if bytesSent > 0 {
print("Sent: \(message)")
return true
}
print("Failed to send")
return false
}
func receive() -> String? {
guard clientSocket != -1 else {
return nil
}
var buffer = [UInt8](repeating: 0, count: 1024)
let bytesRead = read(clientSocket, &buffer, buffer.count)
guard bytesRead > 0 else {
return nil
}
return String(bytes: buffer.prefix(bytesRead), encoding: .utf8)
}
func disconnect() {
if clientSocket != -1 {
close(clientSocket)
clientSocket = -1
}
print("Disconnected")
}
}
// 3. Chat Server
class ChatServer {
private var server = TCPServer()
private var clients: [Int32] = []
private let clientsLock = NSLock()
func start(port: UInt16) {
print("\n--- Starting Chat Server on port \(port) ---")
// Start TCP server
server.start(port: port)
print("Chat server running. Connect clients to chat!")
}
func broadcast(_ message: String, from socket: Int32) {
clientsLock.lock()
let clientList = clients
clientsLock.unlock()
for client in clientList {
if client != socket {
message.withCString { ptr in
write(client, ptr, message.count)
}
}
}
}
func addClient(_ socket: Int32) {
clientsLock.lock()
clients.append(socket)
clientsLock.unlock()
broadcast("User joined", from: socket)
}
func removeClient(_ socket: Int32) {
clientsLock.lock()
clients.removeAll { $0 == socket }
clientsLock.unlock()
close(socket)
}
}
// 4. TCP Client with Reconnect
class TCPClientWithReconnect {
private var client = TCPClient()
private var isConnected = false
private var reconnectAttempts = 0
private let maxAttempts = 5
func connect(host: String, port: UInt16) {
while reconnectAttempts < maxAttempts && !isConnected {
if client.connect(host: host, port: port) {
isConnected = true
reconnectAttempts = 0
return
}
reconnectAttempts += 1
print("Reconnect attempt \(reconnectAttempts) in 2 seconds...")
Thread.sleep(forTimeInterval: 2)
}
print("Failed to connect after \(maxAttempts) attempts")
}
func sendWithRetry(_ message: String) -> Bool {
if isConnected {
return client.send(message)
} else {
print("Not connected, attempting to reconnect...")
return false
}
}
func disconnect() {
isConnected = false
client.disconnect()
}
}
// 5. Non-blocking Socket
class NonBlockingSocket {
private var socket: Int32 = -1
func connect(host: String, port: UInt16) {
socket = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP)
guard socket != -1 else { return }
// Set non-blocking
var flags = fcntl(socket, F_GETFL, 0)
fcntl(socket, F_SETFL, flags | O_NONBLOCK)
// Connect (non-blocking)
var address = sockaddr_in()
address.sin_family = sa_family_t(AF_INET)
address.sin_port = port.bigEndian
let result = connect(socket, nil, 0)
if result == -1 && errno != EINPROGRESS {
print("Connection error")
close(socket)
return
}
print("Non-blocking connection initiated")
}
func sendNonBlocking(_ data: Data) {
var buffer = [UInt8](data)
let sent = write(socket, &buffer, buffer.count)
print("Sent \(sent) bytes")
}
func receiveNonBlocking() -> Data? {
var buffer = [UInt8](repeating: 0, count: 1024)
let received = read(socket, &buffer, buffer.count)
if received > 0 {
return Data(bytes: buffer, count: received)
}
return nil
}
}
// 6. Socket with Timeout
class SocketWithTimeout {
private var socket: Int32 = -1
func connectWithTimeout(host: String, port: UInt16, timeout: TimeInterval) -> Bool {
socket = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP)
guard socket != -1 else { return false }
// Set timeout
var tv = timeval(tv_sec: Int(timeout), tv_usec: 0)
setsockopt(socket, SOL_SOCKET, SO_RCVTIMEO, &tv, socklen_t(MemoryLayout<timeval>.size))
setsockopt(socket, SOL_SOCKET, SO_SNDTIMEO, &tv, socklen_t(MemoryLayout<timeval>.size))
// Connect and read with timeout
// ... connection logic ...
return true
}
}
// 7. Data Stream over TCP
class TCPDataStream {
private var client = TCPClient()
func sendStream(host: String, port: UInt16, data: [Data]) {
guard client.connect(host: host, port: port) else {
return
}
defer { client.disconnect() }
for (index, chunk) in data.enumerated() {
// Send header with chunk size
let header = "\(chunk.count);"
_ = header.withCString { ptr in
write(client.clientSocket, ptr, header.count)
}
// Send data
chunk.withUnsafeBytes { ptr in
write(client.clientSocket, ptr.baseAddress, chunk.count)
}
print("Sent chunk \(index + 1)/\(data.count): \(chunk.count) bytes")
Thread.sleep(forTimeInterval: 0.1)
}
// Send end marker
let endMarker = "0;"
_ = endMarker.withCString { ptr in
write(client.clientSocket, ptr, endMarker.count)
}
print("Stream completed")
}
func receiveStream() -> [Data] {
var receivedData: [Data] = []
var buffer = [UInt8](repeating: 0, count: 1024)
while true {
// Read chunk size
var sizeBuffer = [UInt8]()
while true {
let count = read(client.clientSocket, &buffer, 1)
guard count > 0 else { return receivedData }
if buffer[0] == UInt8(ascii: ";") {
break
}
sizeBuffer.append(buffer[0])
}
guard let sizeString = String(bytes: sizeBuffer, encoding: .utf8),
let size = Int(sizeString) else {
continue
}
if size == 0 {
print("End of stream")
break
}
// Read data
var chunk = [UInt8](repeating: 0, count: size)
var totalReceived = 0
while totalReceived < size {
let count = read(client.clientSocket, &chunk[totalReceived], size - totalReceived)
guard count > 0 else { break }
totalReceived += count
}
receivedData.append(Data(chunk))
print("Received chunk: \(totalReceived) bytes")
}
return receivedData
}
}
// 8. Protocol Buffer over TCP
class ProtocolBufferSocket {
func sendProtobufMessage<T: Encodable>(_ message: T, socket: Int32) {
// Encode message
// Send length prefix followed by message data
// Implementation depends on protobuf library
}
}
// 9. Heartbeat Connection
class HeartbeatConnection {
private var client = TCPClient()
private var heartbeatTimer: Timer?
private var isRunning = false
func connectWithHeartbeat(host: String, port: UInt16, interval: TimeInterval = 5) {
guard client.connect(host: host, port: port) else {
return
}
isRunning = true
// Start heartbeat
heartbeatTimer = Timer.scheduledTimer(withTimeInterval: interval, repeats: true) { [weak self] _ in
self?.sendHeartbeat()
}
// Listen for responses
DispatchQueue.global(qos: .background).async { [weak self] in
self?.listen()
}
}
private func sendHeartbeat() {
guard isRunning else { return }
_ = client.send("HEARTBEAT")
}
private func listen() {
while isRunning {
if let response = client.receive() {
print("Received: \(response)")
}
Thread.sleep(forTimeInterval: 0.1)
}
}
func disconnect() {
isRunning = false
heartbeatTimer?.invalidate()
client.disconnect()
}
}
// Main demonstration
func demonstrateTCPSockets() {
print("=== macOS Swift TCP Socket Examples ===")
// 1. Start server in background
let serverThread = Thread {
let server = TCPServer()
server.start(port: 9999)
// Keep running
RunLoop.current.run()
}
serverThread.start()
Thread.sleep(forTimeInterval: 1)
// 2. Connect client
print("\n--- Client Connection ---")
let client = TCPClient()
if client.connect(host: "localhost", port: 9999) {
// Send messages
_ = client.send("Hello, Server!")
Thread.sleep(forTimeInterval: 0.5)
// Receive response
if let response = client.receive() {
print("Server response: \(response)")
}
// Send more messages
_ = client.send("Message 2")
Thread.sleep(forTimeInterval: 0.5)
_ = client.send("Message 3")
Thread.sleep(forTimeInterval: 0.5)
client.disconnect()
}
Thread.sleep(forTimeInterval: 1)
print("\n=== TCP Socket Examples Completed ===")
print("Note: In production, implement proper signal handling for cleanup")
}
// Uncomment to run demonstration
// demonstrateTCPSockets()
print("\nNote: TCP socket examples provided. Uncomment demonstrateTCPSockets() to run.")
💻 Serveur HTTP swift
🔴 complex
⭐⭐⭐⭐⭐
Créer un serveur HTTP simple en utilisant le framework Vapor ou Swift natif avec des sockets
⏱️ 45 min
🏷️ swift, macos, networking, server
Prerequisites:
Advanced Swift, Networking, Socket programming
// macOS Swift HTTP Server Examples
// Using Foundation and Network framework
import Foundation
// 1. Simple HTTP Server using sockets
class SimpleHTTPServer {
private var listenerSocket: Int32 = -1
private var isRunning = false
func start(port: UInt16) {
print("\n--- Starting HTTP Server on port \(port) ---")
// Create socket
listenerSocket = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP)
guard listenerSocket != -1 else {
print("Failed to create socket")
return
}
// Set socket options
var yes: Int32 = 1
setsockopt(listenerSocket, SOL_SOCKET, SO_REUSEADDR, &yes, socklen_t(MemoryLayout<Int32>.size))
// Bind to port
var addr = sockaddr_in()
addr.sin_family = sa_family_t(AF_INET)
addr.sin_port = port.bigEndian
addr.sin_addr.s_addr = INADDR_ANY
let bindResult = withUnsafePointer(to: &addr) {
$0.withMemoryRebound(to: sockaddr.self, capacity: 1) {
bind(listenerSocket, $0, socklen_t(MemoryLayout<sockaddr_in>.size))
}
}
guard bindResult == 0 else {
print("Failed to bind to port")
close(listenerSocket)
return
}
// Listen
guard listen(listenerSocket, 5) == 0 else {
print("Failed to listen")
close(listenerSocket)
return
}
isRunning = true
print("Server started on http://localhost:\(port)")
// Accept connections in background thread
DispatchQueue.global(qos: .background).async { [weak self] in
self?.acceptConnections()
}
}
private func acceptConnections() {
while isRunning {
var clientAddr = sockaddr_in()
var clientLen = socklen_t(MemoryLayout<sockaddr_in>.size)
let clientSocket = withUnsafeMutablePointer(to: &clientAddr) {
$0.withMemoryRebound(to: sockaddr.self, capacity: 1) {
accept(listenerSocket, $0, &clientLen)
}
}
guard clientSocket != -1 else {
continue
}
// Handle client in background
DispatchQueue.global(qos: .background).async { [weak self] in
self?.handleClient(clientSocket: clientSocket)
}
}
}
private func handleClient(clientSocket: Int32) {
defer { close(clientSocket) }
// Read request
var buffer = [UInt8](repeating: 0, count: 4096)
let bytesRead = read(clientSocket, &buffer, buffer.count)
guard bytesRead > 0 else {
return
}
let request = String(bytes: buffer.prefix(bytesRead), encoding: .utf8) ?? ""
print("\nRequest received:")
print(request.prefix(500))
// Parse request
let lines = request.components(separatedBy: "\r\n")
guard let requestLine = lines.first,
let parts = requestLine.components(separatedBy: " ").split(separator: " ").map(String.init),
parts.count >= 2,
let method = parts.first,
let path = parts.dropFirst().first else {
sendResponse(clientSocket: clientSocket, statusCode: 400, body: "Bad Request")
return
}
print("Method: \(method), Path: \(path)")
// Handle different paths
let response: String
switch path {
case "/":
response = createHTMLResponse("<h1>Welcome to Swift HTTP Server</h1><p>This is a simple HTTP server built with Swift.</p>")
case "/about":
response = createHTMLResponse("<h1>About</h1><p>Swift HTTP Server v1.0</p>")
case "/json":
let json = "{\"message\": \"Hello from Swift\", \"status\": \"success\"}"
response = createJSONResponse(json)
case "/time":
let time = Date().description
response = createJSONResponse("{\"time\": \"\(time)\"}")
default:
response = createHTMLResponse("<h1>404 Not Found</h1><p>The page \(path) was not found.</p>", statusCode: 404)
}
// Send response
_ = write(clientSocket, response, response.count)
print("Response sent")
}
private func createHTMLResponse(_ body: String, statusCode: Int = 200) -> String {
let statusText: String
switch statusCode {
case 200: statusText = "OK"
case 404: statusText = "Not Found"
default: statusText = "OK"
}
let html = """
<!DOCTYPE html>
<html>
<head>
<title>Swift Server</title>
<style>
body { font-family: Arial, sans-serif; margin: 40px; }
h1 { color: #333; }
</style>
</head>
<body>
\(body)
</body>
</html>
"""
return """
HTTP/1.1 \(statusCode) \(statusText)\r
Content-Type: text/html\r
Content-Length: \(html.count)\r
Connection: close\r
\r
\(html)
"""
}
private func createJSONResponse(_ json: String) -> String {
return """
HTTP/1.1 200 OK\r
Content-Type: application/json\r
Content-Length: \(json.count)\r
Connection: close\r
\r
\(json)
"""
}
private func sendResponse(clientSocket: Int32, statusCode: Int, body: String) {
let response = createHTMLResponse(body, statusCode: statusCode)
_ = write(clientSocket, response, response.count)
}
func stop() {
isRunning = false
if listenerSocket != -1 {
close(listenerSocket)
}
print("Server stopped")
}
}
// 2. Request Handler
class RequestHandler {
struct HTTPRequest {
let method: String
let path: String
let headers: [String: String]
let body: String
}
struct HTTPResponse {
let statusCode: Int
let headers: [String: String]
let body: String
}
static func parseRequest(_ data: String) -> HTTPRequest? {
let lines = data.components(separatedBy: "\r\n")
guard let requestLine = lines.first,
let parts = requestLine.components(separatedBy: " ").split(separator: " ").map(String.init),
parts.count >= 2 else {
return nil
}
let method = parts[0]
let path = parts[1]
var headers: [String: String] = [:]
var headerEndIndex = 1
for (index, line) in lines.dropFirst().enumerated() {
if line.isEmpty {
headerEndIndex = index + 2
break
}
let headerParts = line.components(separatedBy: ": ")
if headerParts.count == 2 {
headers[headerParts[0]] = headerParts[1]
}
}
let body = lines.dropFirst(headerEndIndex).joined(separator: "\r\n")
return HTTPRequest(method: method, path: path, headers: headers, body: body)
}
static func routeRequest(_ request: HTTPRequest) -> HTTPResponse {
switch request.method {
case "GET":
return handleGET(request)
case "POST":
return handlePOST(request)
default:
return HTTPResponse(statusCode: 405, headers: [:], body: "Method Not Allowed")
}
}
private static func handleGET(_ request: HTTPRequest) -> HTTPResponse {
switch request.path {
case "/":
return HTMLResponse("<h1>Welcome</h1><p>Use /json for JSON response</p>")
case "/json":
return JSONResponse(["message": "Hello", "status": "success"])
case "/users":
let users = [
["id": 1, "name": "John"],
["id": 2, "name": "Jane"]
]
return JSONResponse(users)
default:
return HTMLResponse("<h1>404</h1>", statusCode: 404)
}
}
private static func handlePOST(_ request: HTTPRequest) -> HTTPResponse {
switch request.path {
case "/echo":
return JSONResponse(["echo": request.body])
default:
return HTMLResponse("<h1>POST received</h1>")
}
}
private static func HTMLResponse(_ body: String, statusCode: Int = 200) -> HTTPResponse {
return HTTPResponse(
statusCode: statusCode,
headers: ["Content-Type": "text/html"],
body: body
)
}
private static func JSONResponse(_ data: Any) -> HTTPResponse {
guard let jsonData = try? JSONSerialization.data(withJSONObject: data, options: []),
let jsonString = String(data: jsonData, encoding: .utf8) else {
return HTTPResponse(statusCode: 500, headers: [:], body: "Internal Server Error")
}
return HTTPResponse(
statusCode: 200,
headers: ["Content-Type": "application/json"],
body: jsonString
)
}
}
// 3. Router with Middleware
class Router {
typealias Middleware = (URLRequest) -> URLRequest?
typealias Handler = (URLRequest) -> String
struct Route {
let method: String
let path: String
let handler: Handler
}
private var routes: [Route] = []
private var middlewares: [Middleware] = []
func addMiddleware(_ middleware: @escaping Middleware) {
middlewares.append(middleware)
}
func addRoute(method: String, path: String, handler: @escaping Handler) {
routes.append(Route(method: method, path: path, handler: handler))
}
func handle(method: String, path: String, headers: [String: String], body: String) -> (Int, [String: String], String)? {
// Apply middlewares
for middleware in middlewares {
// Middleware processing (simplified)
}
// Find matching route
for route in routes {
if route.method == method && route.path == path {
let responseBody = route.handler(
URLRequest(url: URL(string: "http://localhost\(path)")!)
)
return (200, ["Content-Type": "text/html"], responseBody)
}
}
// No matching route
return (404, [:], "<h1>404 Not Found</h1>")
}
}
// 4. Static File Server
class StaticFileServer {
func serve(file: String, from documentRoot: String) -> (Int, [String: String], String)? {
let filePath = documentRoot + file
guard FileManager.default.fileExists(atPath: filePath) else {
return nil
}
guard let fileData = try? Data(contentsOf: URL(fileURLWithPath: filePath)),
let content = String(data: fileData, encoding: .utf8) else {
return (500, [:], "Internal Server Error")
}
let ext = (filePath as NSString).pathExtension
let contentType = getContentType(for: ext)
return (200, ["Content-Type": contentType], content)
}
private func getContentType(for extension: String) -> String {
switch `extension`.lowercased() {
case "html": return "text/html"
case "css": return "text/css"
case "js": return "application/javascript"
case "json": return "application/json"
case "png": return "image/png"
case "jpg", "jpeg": return "image/jpeg"
case "gif": return "image/gif"
default: return "text/plain"
}
}
}
// 5. Server with Logging
class ServerWithLogging {
private var server: SimpleHTTPServer
init() {
server = SimpleHTTPServer()
}
func start(port: UInt16) {
print("Starting server with logging...")
server.start(port: port)
}
private func logRequest(_ method: String, _ path: String, _ statusCode: Int) {
let timestamp = Date()
print("[\(timestamp)] \(method) \(path) - \(statusCode)")
}
}
// 6. REST API Server Example
class RESTAPIServer {
private var data: [String: Any] = [
"users": [
["id": 1, "name": "John Doe", "email": "[email protected]"],
["id": 2, "name": "Jane Smith", "email": "[email protected]"]
]
]
func handleRequest(method: String, path: String, body: String?) -> (Int, String)? {
let pathComponents = path.components(separatedBy: "/").filter { !$0.isEmpty }
guard pathComponents.count >= 2 else {
return (400, "Invalid path")
}
let resource = pathComponents[1]
switch (method, resource) {
case ("GET", "users"):
return handleGetUsers()
case ("GET", "users"):
if pathComponents.count == 3,
let id = Int(pathComponents[2]) {
return handleGetUser(id: id)
}
return (400, "Invalid user ID")
case ("POST", "users"):
return handleCreateUser(body: body)
default:
return (404, "Not Found")
}
}
private func handleGetUsers() -> (Int, String) {
if let users = data["users"] as? [[String: Any]],
let jsonData = try? JSONSerialization.data(withJSONObject: users, options: .prettyPrinted),
let jsonString = String(data: jsonData, encoding: .utf8) {
return (200, jsonString)
}
return (500, "Internal Server Error")
}
private func handleGetUser(id: Int) -> (Int, String) {
if let users = data["users"] as? [[String: Any]],
let user = users.first(where: { ($0["id"] as? Int) == id }),
let jsonData = try? JSONSerialization.data(withJSONObject: user, options: .prettyPrinted),
let jsonString = String(data: jsonData, encoding: .utf8) {
return (200, jsonString)
}
return (404, "User not found")
}
private func handleCreateUser(body: String?) -> (Int, String) {
guard let body = body,
let bodyData = body.data(using: .utf8),
let user = try? JSONSerialization.jsonObject(with: bodyData) as? [String: Any] else {
return (400, "Invalid request body")
}
var users = (data["users"] as? [[String: Any]]) ?? []
let newUser = user.merging(["id": users.count + 1]) { _, new in new }
users.append(newUser)
data["users"] = users
if let jsonData = try? JSONSerialization.data(withJSONObject: newUser, options: .prettyPrinted),
let jsonString = String(data: jsonData, encoding: .utf8) {
return (201, jsonString)
}
return (500, "Internal Server Error")
}
}
// Main demonstration
func demonstrateHTTPServer() {
print("=== macOS Swift HTTP Server Examples ===")
let server = SimpleHTTPServer()
// Start server on port 8080
server.start(port: 8080)
print("\nServer is running. Test with:")
print(" curl http://localhost:8080/")
print(" curl http://localhost:8080/about")
print(" curl http://localhost:8080/json")
print(" curl http://localhost:8080/time")
// Keep server running
print("\nPress Ctrl+C to stop the server")
RunLoop.current.run()
// Server cleanup on exit (in practice, use signal handlers)
// server.stop()
}
// Uncomment to run server
// demonstrateHTTPServer()
print("\nNote: HTTP server examples provided. Uncomment demonstrateHTTPServer() to start server.")