(The lab documents are written closer to the level of detail that a software engineer will get from a boss or client. If you think something might not be fully specified, sometimes the truth is that it doesn’t matter—you could try one approach or the other and see what happens.)
$ telnet cs144.keithw.org http Trying 104.196.238.229... Connected to cs144.keithw.org. Escape character is '^]'. GET /hello HTTP/1.1 # path to the file you are asking Host: cs144.keithw.org # server host name Connection: close # This tells the server that you are finished making requests, and it should close the connection as soon as it finishes replying
HTTP/1.1 200 OK Date: Thu, 16 Dec 2021 05:49:04 GMT Server: Apache Last-Modified: Thu, 13 Dec 2018 15:45:29 GMT ETag: "e-57ce93446cb64" Accept-Ranges: bytes Content-Length: 14 Connection: close Content-Type: text/plain
if you want to do this with nc, beware that nc send the line each time you hit <Enter>, so there will be a 400 Bad Request
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17
$ nc cs144.keithw.org http GET /hello HTTP/1.1 HTTP/1.1 400 Bad Request Date: Thu, 16 Dec 2021 06:09:33 GMT Server: Apache Content-Length: 226 Connection: close Content-Type: text/html; charset=iso-8859-1
<!DOCTYPE HTML PUBLIC "-//IETF//DTD HTML 2.0//EN"> <html><head> <title>400 Bad Request</title> </head><body> <h1>Bad Request</h1> <p>Your browser sent a request that this server could not understand.<br /> </p> </body></html>
Hello! You told us that your SUNet ID was "01". Please see the HTTP headers (above) for your secret code.
$ curl cs144.keithw.org/lab0/01 --verbose * Trying 127.0.0.1... * TCP_NODELAY set * Connected to 127.0.0.1 (127.0.0.1) port 7890 (#0) > GET http://cs144.keithw.org/lab0/01 HTTP/1.1 > Host: cs144.keithw.org > User-Agent: curl/7.58.0 > Accept: */* > Proxy-Connection: Keep-Alive > < HTTP/1.1 200 OK < Connection: keep-alive < Content-Type: text/plain < Date: Thu, 16 Dec 2021 06:15:18 GMT < Keep-Alive: timeout=4 < Proxy-Connection: keep-alive < Server: Apache < Vary: Accept-Encoding < X-You-Said-Your-Sunetid-Was: 01 < X-Your-Code-Is: 109591 * no chunk, no close, no size. Assume close to signal end < Hello! You told us that your SUNet ID was "01". Please see the HTTP headers (above) for your secret code.
2.2 Send yourself an email
since we are not on stanford network and we don’t have a valid sunetid we cannot complish this part of the lab
2.3 Listening and connecting
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18
$ netcat -v -l -p 9091 Listening on [0.0.0.0] (family 0, port 9091) Connection from localhost 47546 received! hello netcat hello telnet bye bye ^C $ telnet localhost 9091 Trying ::1... Trying 127.0.0.1... Connected to localhost. Escape character is '^]'. hello netcat hello telnet bye bye Connection closed by foreign host.
3 Writing a network program using an OS stream socket
In the next part of this warmup lab, you will write a short program that fetches a Web page over the Internet.
When two stream sockets are connected, any bytes written to one socket will eventually come out in the same order from the other socket on the other computer.
Although the network tries to deliver every datagram, in practice datagrams can be (1) lost, (2) delivered out of order, (3) delivered with the contents altered, or even (4) duplicated and delivered more than once. It’s normally the job of the operating systems on either end of the connection to turn “best-effort datagrams” (the abstraction the Internet provides) into “reliable byte streams” (the abstraction that applications usually want).
The two computers have to cooperate to make sure that each byte in the stream eventually gets delivered, in its proper place in line, to the stream socket on the other side. This was done by TCP
1 2 3 4 5 6
$ git clone https://github.com/cs144/sponge $ cd sponge $ mkdir build $ cd build $ cmake .. $ make
$ cmake -DCMAKE_CXX_COMPILER=`which g++-8` -DCMAKE_C_COMPILER=`which gcc-8` .. -- The C compiler identification is GNU 8.4.0 -- The CXX compiler identification is GNU 8.4.0 -- Check for working C compiler: /usr/bin/gcc-8 -- Check for working C compiler: /usr/bin/gcc-8 -- works -- Detecting C compiler ABI info -- Detecting C compiler ABI info - done -- Detecting C compile features -- Detecting C compile features - done -- Check for working CXX compiler: /usr/bin/g++-8 -- Check for working CXX compiler: /usr/bin/g++-8 -- works -- Detecting CXX compiler ABI info -- Detecting CXX compiler ABI info - done -- Detecting CXX compile features -- Detecting CXX compile features - done -- Setting build type to 'Release' -- NOTE: You can choose a build type by calling cmake with one of: -- -DCMAKE_BUILD_TYPE=Release -- full optimizations -- -DCMAKE_BUILD_TYPE=Debug -- better debugging experience in gdb -- -DCMAKE_BUILD_TYPE=RelASan -- full optimizations plus address and undefined-behavior sanitizers -- -DCMAKE_BUILD_TYPE=DebugASan -- debug plus sanitizers -- Could NOT find Doxygen (missing: DOXYGEN_EXECUTABLE) -- Configuring done -- Generating done -- Build files have been written to: /home/vagrant/CS144/lab0/3/sponge/build $ make [100%] Built target parser_dt
voidget_URL(conststring &host, conststring &path){ // Your code here. // You will need to connect to the "http" service on // the computer whose name is in the "host" string, Address target = Address(host , "http"); TCPSocket request ; request.connect(target);
// then request the URL path given in the "path" string.
// Then you'll need to print out everything the server sends back, // (not just one call to read() -- everything) until you reach // the "eof" (end of file).
//! Bytes are written on the "input" side and read from the "output" //! side. The byte stream is finite: the writer can end the input, //! and then no more bytes can be written. classByteStream { private: // Your code here -- add private members as necessary. // Hint: This doesn't need to be a sophisticated data structure at // all, but if any of your tests are taking longer than a second, // that's a sign that you probably want to keep exploring // different approaches. constsize_t maxlen ; deque<char> slot ; bool _end = false ; size_t write_cot ; size_t read_cot ; bool _error = false ; //!< Flag indicating that the stream suffered an error.
public: //! Construct a stream with room for `capacity` bytes. ByteStream(constsize_t capacity);
//! \name "Input" interface for the writer //! Write a string of bytes into the stream. Write as many //! as will fit, and return how many were written. //! \returns the number of bytes accepted into the stream size_twrite(conststd::string &data);
//! \returns the number of additional bytes that the stream has space for size_tremaining_capacity()const;
//! Signal that the byte stream has reached its ending voidend_input();
//! Indicate that the stream suffered an error. voidset_error(){ _error = true; }
//! Peek at next "len" bytes of the stream //! \returns a string std::stringpeek_output(constsize_t len)const;
//! Remove bytes from the buffer voidpop_output(constsize_t len);
//! Read (i.e., copy and then pop) the next "len" bytes of the stream //! \returns a string std::stringread(constsize_t len);
//! \returns `true` if the stream input has ended boolinput_ended()const;
//! \returns `true` if the stream has suffered an error boolerror()const{ return _error; }
//! \returns the maximum amount that can currently be read from the stream size_tbuffer_size()const;
//! \returns `true` if the buffer is empty boolbuffer_empty()const;
//! \returns `true` if the output has reached the ending booleof()const;
//! Total number of bytes written size_tbytes_written()const;
//! Total number of bytes popped size_tbytes_read()const; }; #endif// SPONGE_LIBSPONGE_BYTE_STREAM_HH
size_tByteStream::write(conststring &data){ auto asklen = data.length(); auto end = remaining_capacity() >= asklen ? asklen : remaining_capacity() ; for (size_t i = 0 ; i < end ; i++ ){ slot.push_back(data.at(i)); } write_cot += end ; return end ; }
//! \param[in] len bytes will be copied from the output side of the buffer stringByteStream::peek_output(constsize_t len)const{ auto it = slot.cbegin(); returnstring(it , it + len) ; }
//! \param[in] len bytes will be removed from the output side of the buffer voidByteStream::pop_output(constsize_t len){ for (size_t i = 0 ; i < len ; i++){ slot.pop_front(); } read_cot += len ; }
//! Read (i.e., copy and then pop) the next "len" bytes of the stream //! \param[in] len bytes will be popped and returned //! \returns a string std::stringByteStream::read(constsize_t len){ string res = peek_output(len); pop_output(len); return res; }