diff --git a/inc/tcpstream.hpp b/inc/tcpstream.hpp
index 63ff1fcf0c6bde66baf88f8ee0554e244fc517eb..fb3c5f4f2ba5de00a1a16c3eca3398a3068b11ca 100644
--- a/inc/tcpstream.hpp
+++ b/inc/tcpstream.hpp
@@ -167,6 +167,46 @@ public:
      */
     ssize_t readAll(void *data, size_t len);
 
+    /**
+     * @brief Same as TcpStream::read but with a millisecond timeout. If the 
+     * timeout is reached without receiving data, 0 is returned.
+     * 
+     * If receiving fails, an exception is thrown.
+     * 
+     * @param data Pointer to at least len bytes where the data received over  
+     * the tcp connection will be stored.
+     * @param len The maxiumum number of bytes that will be received over the 
+     * tcp connection.
+     * @param timeoutMs The number of milliseconds before a timeout occurs. 
+     * 
+     * @return The number of bytes that were actually received over the 
+     * connection. This can be less than len. If a timeout occurs 0 is 
+     * returned.
+     */
+    ssize_t readTimeout(void *data, size_t len, int timeoutMs);
+
+    /**
+     * @brief Same as TcpStream::readAll but with a millisecond timeout. If 
+     * the timeout is reached without receiving any data, 0 is returned. If 
+     * the timout occurs after receiving some data, the number of bytes 
+     * received before the timeout is returned as NEGATIVE. The timeout 
+     * starts from the begining if partial data is received.
+     * 
+     * If receiving failed an exception is thrown.
+     * 
+     * @param data Pointer to at least len bytes where the data received over  
+     * the tcp connection will be stored.
+     * @param len The number of bytes that will be received over the tcp 
+     * connection.
+     * @param timeoutMs The number of milliseconds before a timeout occurs.
+     *  
+     * @return The number of bytes that were actually received over the 
+     * connection. This can be less than len if the connection is closed.
+     * If a timout occurs after some data was already read, the number of 
+     * bytes is returned as negative.
+     */
+    ssize_t readAllTimeout(void *data, size_t len, int timeoutMs);
+
     /**
      * @brief Get the socket address of the connection target.
      * 
diff --git a/inc/udpsocket.hpp b/inc/udpsocket.hpp
index 7ed5df1f0cfb82ef483dd9112c607091c672f1c6..83d03a5aa17bc746afd2865627e8e66ea587882e 100644
--- a/inc/udpsocket.hpp
+++ b/inc/udpsocket.hpp
@@ -138,7 +138,7 @@ public:
      * @param remote A reference to a SockAddr that is used to store the origin 
      * of the UDP packet.
      * 
-     * @return The numbe of bytes that were actually copied.
+     * @return The number of bytes that were actually copied.
      */
     ssize_t receive(void *data, size_t len, SockAddr &remote);
 
@@ -150,10 +150,42 @@ public:
      * will be copied.
      * @param len The maximum number of bytes that can be copied into data.
      * 
-     * @return The numbe of bytes that were actually copied.
+     * @return The number of bytes that were actually copied.
      */
     ssize_t receive(void *data, size_t len);
 
+    /**
+     * @brief Receive a UDP packet and copy a maximum number of len bytes from 
+     * the packet payload into data. Store the senders origin socket address 
+     * into remote. If the timeout occurs, 0 is returned. 
+     * 
+     * @param data Pointer to at least len bytes of data in which the payload 
+     * will be copied.
+     * @param len The maximum number of bytes that can be copied into data.
+     * @param remote A reference to a SockAddr that is used to store the origin 
+     * of the UDP packet.
+     * @param timeoutMs The number of milliseconds before a timeout occurs. 
+     * 
+     * @return The number of bytes that were actually copied, or 0 if a timeout
+     * occured.
+     */
+    ssize_t receiveTimeout(void *data, size_t len, SockAddr &remote, int timeoutMs);
+
+    /**
+     * @brief Receive a UDP packet and copy a maximum number of len bytes from 
+     * the packet payload into data. The packets origin is not stored. If the 
+     * timeout occurs, 0 is returned. 
+     * 
+     * @param data Pointer to at least len bytes of data in which the payload 
+     * will be copied.
+     * @param len The maximum number of bytes that can be copied into data.
+     * @param timeoutMs The number of milliseconds before a timeout occurs. 
+     * 
+     * @return The number of bytes that were actually copied, or 0 if a timeout
+     * occured.
+     */
+    ssize_t receiveTimeout(void *data, size_t len, int timeoutMs);
+
     /**
      * @brief Check if the socket is closed or open. Open in this case means 
      * bound and ready to send / receive.
diff --git a/src/tcpstream.cpp b/src/tcpstream.cpp
index 630c928dd1affdda475ec7e9f4f954a70375c3e7..c08d40345a016cf686b0098cdc686d204aa78ff1 100644
--- a/src/tcpstream.cpp
+++ b/src/tcpstream.cpp
@@ -5,6 +5,7 @@
 #include <unistd.h>
 #include <sys/socket.h>
 #include <netinet/in.h>
+#include <poll.h>
 
 TcpStream::TcpStream(SockAddr _remote)
     : remote{_remote}, sockfd{0}
@@ -154,6 +155,81 @@ ssize_t TcpStream::readAll(void *data, size_t len)
     return bytesReadTotal;
 }
 
+ssize_t TcpStream::readTimeout(void *data, size_t len, int timeoutMs)
+{
+    if (timeoutMs <= 0) return read(data, len);
+
+    if (sockfd == 0)
+        throw std::runtime_error("Can't read from closed socket");
+
+    pollfd pfd = {0};
+    pfd.fd = sockfd;
+    pfd.events = POLLIN;
+    
+    // block until data is available or the timeout is reached
+    int res = poll(&pfd, 1, timeoutMs);
+
+    // a timout occured
+    if (res == 0) return 0;
+
+    // a poll error occured
+    if (res < 0)
+    {
+        close();
+        throw std::runtime_error("Error while reading from socket");
+    }
+
+    ssize_t bytes_read = ::read(sockfd, data, len);
+    if (bytes_read < 0)
+    {
+        close();
+        throw std::runtime_error("Error while reading from socket");
+    }
+    return bytes_read;
+}
+
+ssize_t TcpStream::readAllTimeout(void *data, size_t len, int timeoutMs)
+{
+    if (timeoutMs <= 0) return readAll(data, len);
+
+    if (sockfd == 0)
+        throw std::runtime_error("Can't read from closed socket");
+    
+    pollfd pfd = {0};
+    pfd.fd = sockfd;
+    pfd.events = POLLIN;
+    
+    
+    size_t bytesReadTotal = 0;
+    while (true)
+    {
+        // block until data is available or the timeout is reached
+        int res = poll(&pfd, 1, timeoutMs);
+
+        // a timout occured
+        if (res == 0) return -1 * bytesReadTotal;
+
+        // a poll error occured
+        if (res < 0)
+        {
+            close();
+            throw std::runtime_error("Error while reading from socket");
+        }
+
+        ssize_t bytesRead = ::read(sockfd, (uint8_t*)data + bytesReadTotal, len-bytesReadTotal);
+
+        if (bytesRead == 0) break;
+        if (bytesRead < 0)
+        {
+            close();
+            throw std::runtime_error("Error while reading from socket");
+        }
+
+        bytesReadTotal += bytesRead;
+    }
+    return bytesReadTotal;
+}
+
 const SockAddr & TcpStream::getRemoteAddr() const
 {
     return remote;
diff --git a/src/udpsocket.cpp b/src/udpsocket.cpp
index 895fabc409c6431361825d99bd5ae768a39e6d4e..91744c2c7cbfa75ec256f0bbc55451bbaea15cc6 100644
--- a/src/udpsocket.cpp
+++ b/src/udpsocket.cpp
@@ -4,6 +4,7 @@
 
 #include <unistd.h>
 #include <sys/socket.h>
+#include <poll.h>
 
 
 UdpSocket::UdpSocket(SockAddr _local)
@@ -93,9 +94,10 @@ ssize_t UdpSocket::sendTo(const std::string &remoteAddrPort, const void *data, s
 ssize_t UdpSocket::receive(void *data, size_t len, SockAddr &remote)
 {
     SockAddr::RawSockAddr remote_raw_saddr = {0};
+    socklen_t remote_raw_socklen = raw_socklen;
 
     // TODO: Lookup flags
-    ssize_t bytes_read = ::recvfrom(sockfd, data, len, 0, &remote_raw_saddr.generic, &raw_socklen);
+    ssize_t bytes_read = ::recvfrom(sockfd, data, len, 0, &remote_raw_saddr.generic, &remote_raw_socklen);
 
     if (bytes_read < 0)
     {
@@ -108,20 +110,52 @@ ssize_t UdpSocket::receive(void *data, size_t len, SockAddr &remote)
 }
 
 ssize_t UdpSocket::receive(void *data, size_t len)
+{
+    SockAddr saddr;
+    return receive(data, len, saddr);
+}
+
+ssize_t UdpSocket::receiveTimeout(void *data, size_t len, SockAddr &remote, int timeoutMs)
 {
     SockAddr::RawSockAddr remote_raw_saddr = {0};
+    socklen_t remote_raw_socklen = raw_socklen;
+
+    pollfd pfd = {0};
+    pfd.fd = sockfd;
+    pfd.events = POLLIN;
+    
+    // block until data is available or the timeout is reached
+    int res = poll(&pfd, 1, timeoutMs);
+
+    // a timout occured
+    if (res == 0) return 0;
+
+    // a poll error occured
+    if (res < 0)
+    {
+        close();
+        throw std::runtime_error("Error while reading from socket");
+    }
 
     // TODO: Lookup flags
-    ssize_t bytes_read = ::recvfrom(sockfd, data, len, 0, &remote_raw_saddr.generic, &raw_socklen);
+    ssize_t bytes_read = ::recvfrom(sockfd, data, len, 0, &remote_raw_saddr.generic, &remote_raw_socklen);
 
     if (bytes_read < 0)
     {
         throw std::runtime_error("Error while reading from socket");
     }
 
+    remote = SockAddr(&remote_raw_saddr.generic, local.address.type);
+
     return bytes_read;
 }
 
+ssize_t UdpSocket::receiveTimeout(void *data, size_t len, int timeoutMs)
+{
+    SockAddr saddr;
+    return receiveTimeout(data, len, saddr, timeoutMs);
+}
+
 void UdpSocket::close()
 {
     if (sockfd != 0)