Lab 12: Network streams, pipes and memory mapped files #
Network streams #
The goal of the task is to create a simple console application that allows two users to exchange messages over a network.
Starting code #
Student
- Chat.Common/
- ChatClient/
- ChatServer/
- NetworkStreams.sln
Task description #
ChatCommon #
The ChatCommon project contains shared code used by both the server and the client applications. It includes the MessageDTO class, which represents a single message transmitted over the network, as well as the MessageHandlers folder with classes responsible for handling messages.
Communication between programs is carried out using the TCP protocol. Each message consists of a 32-bit header, which is an int value encoded in big-endian format and specifies the length of the message in bytes. Immediately following the header, the message content is transmitted in JSON format, encoded in UTF-8. The maximum size of a single message must not exceed 10 kB.
As part of this project, the implementations of the following methods must be completed:
ReadMessagefrom theMessageReaderclass - in the event of a deserialization error, anInvalidMessageReceivedexception with an appropriate description should be thrown. If the message length exceeds the allowed limit, aTooLongMessageExceptionshould be thrown. If the end of the stream is reached, the method should returnnull.WriteMessagein theMessageWriterclass - before sending a message, its length must be validated. If the allowed limit is exceeded, the method should throw aTooLongMessageException.
The Newtonsoft.Json library should be used for message serialization and deserialization.
ChatClient #
In the ChatClient project, implement an asynchronous Connect method that attempts to establish a TCP connection with the server. If a connection is not established within three seconds, the method should return null. Use the provided progress object to log the progress of the operation.
ChatServer #
In the ChatServer project, an asynchronous method ForwardMessagesAsync must be implemented in the ChatServer.cs file. Until cancellation is requested via a CancellationToken, this method receives messages from one client, writes them to the standard output, and then forwards them to the other client.
In the same file, the Run method must also be implemented. Until cancellation is requested via a CancellationToken, it waits for two clients to connect and initiates message exchange between them. After the conversation ends, the method should resume waiting for the next clients. The HandleClientsAsync method should be used to handle the connected clients.
Useful links:
The client application accepts the server’s IP address and port as optional command-line arguments. As an exercise, you can try connecting to a server running on another computer within the local network.
You can check your computer’s IP address using the following commands.
ip aipconfigExample solution #
Solution
- Chat.Common/
- ChatClient/
- ChatServer/
- NetworkStreams.sln
Pipes #
Key-value databases
Key–value databases are a way of storing data in which each piece of information is saved as a pair: a unique key and its corresponding value.
Instead of using complex tables and relationships, the data is organized in a simple, dictionary-like structure, which enables very fast searching, writing, and reading of data based on the key.
This model is particularly useful in systems that require high performance and easy scalability, for example for handling caches, user sessions, or application configuration.
Starting code #
Student
Task description #
The goal of the task is to implement a simple key–value database that can respond to requests from other processes running on the same computer. For simplicity, only one client will be handled at a time.
We accept the following query syntax for the server:
- create or update a key-value pair -
SET <key> <value>, to which the server respondsOKon success. - retrieve a value -
GET <key>, to which the server returns the requested value orNOT_FOUNDif the key does not exist. - delete a key-value pair -
DELETE <key>, to which the server respondsOKon success orNOT_FOUNDif the key was not present. - for invalid queries the server returns
ERROR <msg>.
All messages are encoded with UTF-8 and separated by newline characters. Therefore, none of the message values may contain a newline.
Client #
In the Client project implement the following parts:
- In the
Mainmethod create a variableclientof typeNamedPipeClientStreamand connect to the server. If the connection takes more than three seconds - exit the program with an appropriate message. - Implement the
GetResponsemethod which sends a request to the server and waits for a response. If the connection is interrupted, returnnull.
Server #
In the Server project in class KvServer implement the following parts:
- In the
Startmethod create a variableserverof typeNamedPipeServerStreamand connect to the client. The connection can be interrupted by aCancellationToken. - Implement the
HandleClientAsyncmethod to asynchronously read requests from the client and reply to them. Take into account cancellation viaCancellationToken. Use theProcessCommandmethod to obtain a response.
Useful links:
Example solution #
Solution
Memory-mapped files #
The goal of the task is to implement a simple library for reading large CSV files. The library should allow processing files that are too large to be loaded entirely into RAM.
Starting code #
Student
- BigCSVReaders/
- BigCSVReaders.Benchmark/
- BigCSVReaders.Tests/
- MMF.sln
Task description #
The BigCSVReader project contains an abstract class BigCsvReader that is responsible for reading fragments of large CSV files. In its constructor the class creates an auxiliary file with the .offsets extension. This is a binary file where consecutive 8-byte values are written, representing the offsets of individual rows in the original CSV file. The library supports UTF-8 encoding only.
The task is to complete the implementations of derived classes StreamBigCsvReader and MmfBigCsvReader, and then compare their performance using the BigCSVReader.Benchmark project.
In
StreamBigCsvReaderyou should use the standard file reading mechanism usingFileStream.In
MmfBigCsvReaderyou should use file mapping to memory (Memory-Mapped Files).
Useful links:
Example solution #
Solution
- BigCSVReaders/
- BigCSVReaders.Benchmark/
- BigCSVReaders.Tests/
- MMF.sln