Skip to content

Commit be64996

Browse files
committed
Merge branch 'master' of github.com:marciok/katan
* 'master' of github.com:marciok/katan: Add images Add breakline Add references Remove header Update README.md Update README
2 parents 1932b2f + 6ba3124 commit be64996

File tree

1 file changed

+59
-67
lines changed

1 file changed

+59
-67
lines changed

README.md

Lines changed: 59 additions & 67 deletions
Original file line numberDiff line numberDiff line change
@@ -1,22 +1,22 @@
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

@@ -27,28 +27,28 @@
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(
@@ -58,45 +58,41 @@
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

Comments
 (0)