11 # Katan
22 A micro web server that replies * "Hello world!"* to every request
33
4- The ideia is to show the basics steps to create a web server in Swift.
4+ The idea is to show the basics steps to create a web server in Swift.
55
66 * An web server overview:*
77
8- ![ alt text] ( cloud+flow_final .png )
8+ ![ alt text] ( https://s3.amazonaws.com/marcioklepacz/ cloud%2Bflow_final .png)
99
1010
1111 ## 1. Create Socket 🐣
1212
13- ``` swift
14- let socketDescriptor = Darwin.socket (AF_INET, SOCK_STREAM, 0 )
15- ```
13+ ``` swift
14+ func startWebServer (){
1615
17- * int socket(int domain, int type, int protocol);*
18-
19- Creates an endpoint for communication and returns a descriptor.
16+ let socketDescriptor = Darwin.socket (AF_INET, SOCK_STREAM, 0 )
17+ ```
18+
19+ `socket` -- creates an endpoint for communication and returns a descriptor.
2020
2121 ** domain** : Communication domain, selects the protocol family, in our case ipv4 (AF_INET). AF_INET6 if we wanted to use ipv6.
2222
2727
2828 Returns -1 if there's an error otherwise the descriptor (a reference).
2929
30+
3031 ## 2 . Set options 🎛
31- ``` swift
32+
33+ ```swift
3234 var noSigPipe: Int32 = 1
3335 setsockopt (socketDescriptor, SOL_SOCKET, SO_NOSIGPIPE, & noSigPipe, socklen_t (MemoryLayout < Int32 > .size ))
3436```
35-
36- ` int setsockopt(int socket, int level, int option_name, const void *option_value, socklen_t option_len); `
37+ `setsockopt` -- get and set options on sockets
3738
3839 ** socket** : The socket descriptor
3940
40- ** level** : To manipulate options at
41-
42- the socket level, level is specified as SOL_SOCKET
43- option_name: The name of our the option, in our case we do not generate SIGPIPE, instead return EPIPE
41+ ** level** : To manipulate options at the socket level
42+
43+ ** option_name** : The name of our the option, in our case we do not generate SIGPIPE, instead return EPIPE
4444 A SIGPIPE is sent to a process if it tried to write to a socket that had been shutdown for writing or isn't connected (anymore).
4545
4646 ** socklen_t** : the option length
4747
4848 ## 3 . Create adress and bind 🚪➕ 🔌
4949
50- ![ alt text] ( overview.png )
51- ``` swfit
50+ ! [alt text](https : // s3.amazonaws.com/marcioklepacz/ overview.png)
51+ ```swift
5252 let port: in_port_t = 9292
5353
5454 var address = sockaddr_in (
5858 sin_addr : in_addr (s_addr : in_addr_t (0 )),
5959 sin_zero :(0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 ) // Add some padding, more info at: http://stackoverflow.com/questions/15608707/why-is-zero-padding-needed-in-sockaddr-in#15609050
6060 )
61-
61+
6262 var bindResult: Int32 = -1
6363 bindResult = withUnsafePointer (to : & address) {
6464 bind (socketDescriptor, UnsafePointer < sockaddr> (OpaquePointer ($0 )), socklen_t (MemoryLayout < sockaddr_in> .size ))
6565 }
66- ```
67-
68- bind a name to a socket
66+ ```
6967
70- ` int bind(int socket, const struct sockaddr *address, socklen_t address_len); `
68+ ` bind` -- assigns a name to an unnamed socket.
7169
72- bind() assigns a name to an unnamed socket. When a socket is created
73- with socket() it exists in a name space (address family) but has no name
74- assigned. bind() requests that address be assigned to the socket.
70+ When a socket is created with socket () it exists in a name space (address family) but has no name
71+ assigned. bind () requests that address be assigned to the socket.
7572
76- * /
77-
73+ ```swift
7874 if bindResult == -1 {
7975 fatalError (String (cString : UnsafePointer (strerror (errno))))
8076 }
8177
82- /* :
78+ ```
79+
8380 ## 4 . Listen 📡
84- * /
81+ ```swift
8582 listen (socketDescriptor, SOMAXCONN)
86- /* :
87- listen for connections on a socket
88- ` int listen(int socket, int backlog); `
83+ ```
84+ `listen` -- for connections on a socket
8985
9086 The backlog parameter defines the maximum length for the queue of pending
9187 connections. If a connection request arrives with the queue full, the
9288 client may receive an error with an indication of ECONNREFUSED.
9389
94- * /
90+
91+
9592
96- /* :
9793 ## 5 . Accept connection on socket ✅
98- * /
99-
94+
95+ ```swift
10096 print (" Starting HTTP server on port \( port ) " )
10197 repeat {
10298 var address = sockaddr ()
@@ -106,11 +102,10 @@ bind a name to a socket
106102 if clientSocket == -1 {
107103 fatalError (String (cString : UnsafePointer (strerror (errno))))
108104 }
109- /* :
110- ` int accept(int socket, struct sockaddr *restrict address, socklen_t *restrict address_len); `
111-
112- accept() extracts the first connection request on the queue
113- of pending connections, creates a new socket with the same properties of
105+ ```
106+ `accept` -- extracts the first connection request on the queue of pending connections,
107+
108+ Creates a new socket with the same properties of
114109 socket, and allocates a new file descriptor for the socket.
115110
116111 The argument address is a result parameter that is filled in with the
@@ -120,62 +115,59 @@ bind a name to a socket
120115 parameter; it should initially contain the amount of space pointed to by
121116 address; on return it will contain the actual length (in bytes) of the
122117 address returned.
123- * /
118+ ```swift
124119
125120 var characters = " "
126- var next : UInt8 = 0
121+ var received : UInt8 = 0
127122 repeat {
128123 var buffer = [UInt8 ](repeatElement (0 , count : 1 ))
129124
130125
131- / * :
126+ ```
132127## 6 . Read socket 📖
133128
134- recv -- receive a message from a socket
129+ ` recv` -- receive a message from a socket
135130
136- ` ssize_t recv(int socket, void *buffer, size_t length, int flags); `
137- * /
131+ ```swift
138132 let resp = recv (clientSocket, & buffer, Int (buffer.count ), 0 )
139133 if resp <= 0 {
140134 fatalError (String (cString : UnsafePointer (strerror (errno))))
141135 }
142136
143- next = buffer[ 0 ]
144- if next > 13 /* Carriage Return * / {
145- characters.append(Character(UnicodeScalar(next )))
137+ received = buffer. first !
138+ if received > 13 /* Carriage Return on ASCII table */ {
139+ characters.append (Character (UnicodeScalar (received )))
146140 }
147- } while next != 10 /* New Line * /
141+ } while received != 10 /* New Line on ASCII table */
148142
149143 print (" Received -> \( characters ) " )
144+ ```
145+ ## 7 . Write response 📝
146+
147+ `write` -- write output
148+ ```swift
150149 let message = " HTTP/1.1 200 OK\r\n\r\n Hello World!"
151150 print (" Response -> \( message ) " )
152151 let messageData = ArraySlice (message.utf8 )
153152
154153 _ = messageData.withUnsafeBytes {
155- /* :
156- ## 7. Write response 📝
157-
158- write -- write output
159-
160- ` ssize_t write(int fildes, const void *buf, size_t nbyte); `
161- * /
162154
163155 write (clientSocket, $0 .baseAddress , messageData.count )
164156 }
165157
166- / * :
158+ ```
167159## 8 . Close socket ⚰️
168160
169- close -- delete a descriptor
161+ `close` -- delete a descriptor
162+ ```swift
170163
171- ` int close(int fildes); `
172- * /
173164 close (clientSocket)
174165
175166 } while true
176167
177-
178-
179-
180-
181-
168+ }
169+ startWebServer ()
170+ ```
171+ # References:
172+ * https: // ruslanspivak.com/lsbaws-part1/
173+ * https: // github.com/httpswift/swifter
0 commit comments