🎯 Ejemplos recomendados
Balanced sample collections from various categories for you to explore
Ejemplos de Redes macOS Swift
Ejemplos de redes macOS Swift incluyendo solicitudes HTTP, servidor HTTP y programación de sockets TCP
💻 Solicitud HTTP swift
🟡 intermediate
⭐⭐⭐
Enviar solicitudes GET y POST usando URLSession con manejo de errores y procesamiento de respuestas adecuado
⏱️ 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
⭐⭐⭐⭐
Crear sockets de cliente y servidor TCP para comunicación bidireccional
⏱️ 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.")
💻 Servidor HTTP swift
🔴 complex
⭐⭐⭐⭐⭐
Crear un servidor HTTP simple usando el framework Vapor o Swift nativo con 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.")