这里就是真正涉及到代码了,我们需要用套接字实现我们刚刚第一个 telnet 发送请求的功能,这里感觉并不是很难,就是我对套接字编程不太熟悉,很多系统调用都不知道😭,然后我去看了一下 linux 高性能服务器编程里面的套接字编程,就看了几个 API 就写出来了,哈哈。
我们首先通过 gethostbyname 来获取域名对应的 ip 信息,然后创建一个套接字,并与对应的 ip 建立连接,发送我们的请求的内容,这里很简单,就是我们刚刚 telnet 之后写的内容,只需要注意一下换行符就可以了,然后从套接字里面循环读取数据到缓冲区并打印就可以了!
void get_URL(const string& host, const string& path)
{
cerr << "Function called: get_URL(" << host << ", " << path << ")\n";
// 通过域名解析获取 ip
struct hostent *server = gethostbyname(host.c_str());
if (server == NULL) {
cerr << "Error: Could not get host information for " << host << "\n";
return;
}
// 这是一个用来表示 ipv4 地址信息的结构体
// 用于套接字编程
struct sockaddr_in server_addr;
// 填充这个结构体
server_addr.sin_family = AF_INET;
server_addr.sin_addr.s_addr = *(u_long*)server->h_addr_list[0];
server_addr.sin_port = htons(80);
// 本地创建一个套接字
int sockfd = socket(AF_INET, SOCK_STREAM, 0);
if ( sockfd < 0 ) {
cerr << "Error: Could not create socket\n";
return;
}
// 连接到远程服务器
if (connect(sockfd, (struct sockaddr*) &server_addr, sizeof(server_addr)) < 0 ) {
cerr << "Error: Could not connect to server\n";
return;
}
string request = "GET " + path + " HTTP/1.1\r\nHost: " + host + "\r\nConnection: close\r\n\r\n";
if (send(sockfd, request.c_str(), request.size(), 0) < 0) {
cerr << "Error: Could not send request\n";
return;
}
char buffer[1024];
int bytes_read = 0;
while ((bytes_read = recv(sockfd, buffer, sizeof(buffer), 0)) > 0 ) {
write(1, buffer, bytes_read);
}
if (bytes_read < 0) {
cerr << "Error: Could not read response\n";
return;
}
close(sockfd);
}
结果如下:
root@r-linux:/home/rinai/project/CS144# cmake --build build --target check_webget
Test project /home/rinai/project/CS144/build
Start 1: compile with bug-checkers
1/2 Test #1: compile with bug-checkers ........ Passed 0.20 sec
Start 2: t_webget
2/2 Test #2: t_webget ......................... Passed 1.10 sec
100% tests passed, 0 tests failed out of 2
Total Test time (real) = 1.30 sec
Built target check_webget
class ByteStream
{
public:
explicit ByteStream( uint64_t capacity );
// Helper functions (provided) to access the ByteStream's Reader and Writer interfaces
Reader& reader();
const Reader& reader() const;
Writer& writer();
const Writer& writer() const;
void set_error() { error_ = true; }; // Signal that the stream suffered an error.
bool has_error() const { return error_; }; // Has the stream had an error?
protected:
// Please add any additional state to the ByteStream here, and not to the Writer and Reader interfaces.
uint64_t capacity_;
bool error_ {};
// added state:
std::string buffer_;
uint64_t read_cnt_;
uint64_t write_cnt_;
bool closed_ {};
};