- At root level of the project, run:
cmake . -B buildcmake --build build
 
- Then in one terminal window/session, run the server 
./build/src/server - Open a new terminal window/session, run the client with arguments: 
./build/src/client <args>- one example is to run the Python test script itself: 
./src/test_commands.py 
 - one example is to run the Python test script itself: 
 
- server-side vs. client-side
 - Two kinds of mainstream sockets:
- DARPA Internet Socket
 - Unix Socket
 
 
- Two mainstream types:
- Stream Sockets - 
SOCK_STREAM- reliable two-way connected communication streams
 - uses TCP
 
 - Datagram Sockets - 
SOCK_DGRAM- a.k.a. connectionless socket
 - uses UDP
 
 
 - Stream Sockets - 
 
socket()- syscall that returns an fdbind()- associates an address to a socket fdlisten()- enables user to accept connections to that addressaccept()- takes a listening fd- when a client makes a connection to the listening address,
 accept()returns an fd that represents the connection socket
read()- receives data from a TCP connectionwrite()- sends dataclose()- destroys the resource referred by the fd and recycles fdsend()andrecv()might offer better control over data transmission thanread()andwrite()
connect()- takes a socket fd and address
 - makes a TCP connection to that address
 
- Used to spilt requests apart from the TCP byte stream
 - Current scheme:
 
+-----+-----+-----+-----+----------
| len | msg1 | len | msg2 | more...
+-----+-----+-----+-----+----------- Two parts:
- 4-byte little-endian integer - length of the request
 - variable-length request
 
 
- Text
- human-readable
 - HTTP
 - hard to parse - variable-length strings
 
 - Avoid unnecessary variable-length components
 - protocol parsing currently uses 2 
read()syscalls- could use a buffered I/O
 
 
- Three ways to handle concurrent connections in server-side network programming
- forking
- creates new processes for each client connection
 
 - multi-threading
- uses threads instead of processes
 
 - event loops
- polling
 - non-blocking I/O
 
 
 - forking
 - Use 
pollto determine which fd can be operated without blocking - when an I/O operation is done on an fd, it should be non-blocking
 - In blocking mode,
readblocks the caller when there are no data in the kernelwriteblocks when the write buffer is fullacceptblocks when there are no new connections in the kernel queue
 - In non-blocking mode
- operations either success without blocking, or
 - fail with errno 
EAGAIN- not ready - non-blocking operations that fail with 
EAGAINmust be retried after the readiness was notified bypoll 
 pollis the SOLE blocking operation in an event loop- All blocking networking IO APIs (
read,write,accept) have a nonblocking mode - APIs that do not have a non-blocking mode (
gethostbyname, disk IOs) should be performed in thread pools - Timers should also implemented within the event loop since we cannot 
sleepinside - Also 
selectandepollon Linuxepollconsists of 3 syscalls:epoll_createepoll_waitepoll_ctl
- stateful API
 - used to manipulate an fd set create by 
epoll_create, which is operated upon byepoll_wait 
 
- Need buffers for reading/writing
- in nonblocking mode, IO operations are often deferred
 
 poll()poll()is actually horribly slow for large number of connections- Use a dedicated event lib such as 
libeventinstead - ask the OS to let us know when some data is ready to read on which sockets
 
- Plan of using 
poll():- Keep an array of 
struct pollfds with info about:- which socket descriptors should be monitored
 - what kind of events we want to monitor for
 
 - OS will block on the 
poll()call until one of the events occurs or user-specified timeout occurs 
 - Keep an array of 
 - For a request/response protocol, clients are not limited to sending one request and waiting for the response at a time
- could save some latency
 - **pipelining**
 
 
- command: list of strings, such as 
set key val - Scheme of the command:
nstr- number of strings - 4 byteslen- length of the following string - 4 bytes
 
+------+-----+------+-----+------+-----+-----+------+
| nstr | len | str1 | len | str2 | ... | len | strn |
+------+-----+------+-----+------+-----+-----+------+- Scheme of the response:
res- 4-byte status codedata- response string
 
+-----+---------
| res | data...
+-----+---------- Tow kinds of hashtables:
- chaining
 - open addressing
 
 - Main difference: collision resolution
- open addressing: seeks another free slot in the event of a collision
 - chaining: groups conflicting keys with a linked list
 
 
- When needing more space for the hashtable, we resize
 - To avoid stalling the server, keep two hashtables and gradually move nodes between them
 
- The **Type-Length-Value (TLV)** scheme
 
- Redis supports querying sorted data by rank
 - Redis actually uses skiplist for storing sorted data
 - Resources:
 
- Rank-Based Queries
- the primary use case of sorted sets
 - range query - just a regular binary tree look-up, followed by an offset operation
 - however, the offset operation is not a regular binary tree walk
 
 - Sorted Set
- a Redis data type
 - https://redis.io/docs/data-types/sorted-sets/
 
 
- Every networked application needs to handle timeouts
 - we need timers
- timeout value of 
pollshould be the timeout value of the nearest timer (why..?) 
 - timeout value of 
 - Add timers to kick out idle TCP connections
 - For each connection there is a timer, set to a fixed timeout into the future
- every time I/O activities occur on the connection, timer is renewed to a fixed timeout
 
 - When a timer is renewed, it becomes the most distant one
 
- TTL - one way to manage the size of cache
 - Heap data structure
- binary tree, packed in to array
 - parent is no bigger than children
 
 
- thread from the thread pool consumes tasks form a queue and executes them
 pthreadAPIpthread_mutex_tpthread_cond_t- wakes up consumer threads only when the queue is not empty
 - consumer threads should be sleeping when idle