DNSServer
#include<iostream>
#include<cstdio>
#include<cstring>
#include<ctime>
#include<cstdlib>
#include<netinet/in.h>
#include<sys/socket.h>
#include<unistd.h>
#include<arpa/inet.h>
using namespace std;
const static int dns_server_port = 53; // DNS服务器的端口,DNS协议标准端口为53
const static char* dns_server_ip = "114.114.114.114"; // DNS服务器的IP地址,这里使用了114DNS
struct dns_header {
unsigned short id; // 事务ID,用于标识查询的唯一性
unsigned short flags; // 标志位,用于控制查询的行为及响应的状态
unsigned short questions; // 问题计数,指示请求中包含的问题数
unsigned short answer; // 回答记录数,指示回答部分的DNS记录数
unsigned short authority; // 授权记录数,指示授权部分的DNS记录数
unsigned short additional; // 附加记录数,指示附加部分的DNS记录数
};
struct dns_question {
int length; // 查询名长度,用于指示查询名的字节长度
unsigned short qtype; // 查询类型,指出请求的资源记录类型,如A记录、MX记录等
unsigned short qclass; // 查询类别,通常是IN,表示Internet
unsigned char *name; // 查询名,表示请求解析的域名
};
int dns_create_header(dns_header *header){
if(header == nullptr){
return -1; // 错误处理:指针为空
}
srandom(time(nullptr));
header->id = random(); // 随机生成事务ID
header->flags = htons(0x0100); // 设置标志位为标准查询
header->questions = htons(1); // 设置问题计数为1
return 0;
}
int dns_create_question(dns_question *question, const char *domain) {
if (question == nullptr || domain == nullptr) {
return -1; // 错误处理:参数为空
}
question->qtype = htons(1); // Type A
question->qclass = htons(1); // Class IN
question->name = (unsigned char *)strdup(domain); // 复制域名
question->length = strlen(domain); // 设置查询名长度
// 将域名转换为DNS格式
unsigned char *dst = question->name;
const char *src = domain;
while (*src != '\0') {
unsigned char *len = dst++;
*len = 0;
while (*src != '\0' && *src != '.') {
*dst++ = *src++;
(*len)++;
}
if (*src == '.') {
src++;
}
}
*dst++ = 0; // 字符串结束
return 0;
}
int dns_build_requestion(dns_header *header, dns_question *question, char* request) {
if (header == nullptr || question == nullptr || request == nullptr) {
return -1; // 错误处理:指针为空
}
int offset = 0;
memcpy(request, header, sizeof(*header)); // 复制头部到请求
offset = sizeof(dns_header);
// 复制查询名到请求
memcpy(request + offset, question->name, question->length);
offset += question->length;
memcpy(request + offset, &question->qtype, sizeof(question->qtype));
offset += sizeof(question->qtype);
memcpy(request + offset, &question->qclass, sizeof(question->qclass));
offset += sizeof(question->qclass);
return offset; // 返回请求总长度
}
int dns_client_commit(const char* domain){
int sockfd = socket(AF_INET, SOCK_DGRAM, 0); // 创建UDP套接字
if(sockfd < 0) {
return -1; // 错误处理:套接字创建失败
}
struct sockaddr_in servaddr{};
servaddr.sin_family = AF_INET;
servaddr.sin_port = htons(dns_server_port);
servaddr.sin_addr.s_addr = inet_addr(dns_server_ip);
dns_header header{};
dns_create_header(&header); // 创建DNS查询头
dns_question question{};
if (dns_create_question(&question, domain) != 0) { // 创建DNS查询问题
close(sockfd); // 创建问题失败时,关闭套接字
return -1;
}
char request[1024]{};
int len = dns_build_requestion(&header, &question, request); // 构建DNS查询请求
// 发送DNS查询
sendto(sockfd, request, len, 0, (struct sockaddr*)&servaddr, sizeof(servaddr));
// 接收DNS响应
char response[1024]{};
struct sockaddr_in addr;
socklen_t addr_len = sizeof(struct sockaddr_in);
int n = recvfrom(sockfd, response, sizeof(response), 0, (struct sockaddr*)&addr, &addr_len);
printf("recvfrom:%d %s\n", n, response); // 打印接收到的字节数和响应内容
close(sockfd); // 关闭套接字
return 0;
HttpServer
#include<iostream>
#include<cstdio>
#include<sys/socket.h>
#include<arpa/inet.h>
#include<netinet/in.h>
#include<unistd.h>
#include<cstdlib>
#include<cstring>
#include<string>
#include<netdb.h>
#include<sys/types.h>
#include<fcntl.h>
#include<vector>
using namespace std;
constexpr static int buffer_size=1024;
const static char* http_version="HTTP/1.1";
const static char* connection_type="connection:close\r\n";
char *host_to_ip(const char *hostname){
struct hostent *host_entry=gethostbyname(hostname);
if (host_entry) {
return inet_ntoa(*(struct in_addr*)host_entry->h_addr_list[0]);
}
return nullptr;
}
int http_create_socket(const char *ip){
int sockfd=socket(AF_INET,SOCK_STREAM,0);
struct sockaddr_in sin{};
sin.sin_family=AF_INET;
sin.sin_port=htons(80);
sin.sin_addr.s_addr=inet_addr(ip);
if(0!=connect(sockfd,(struct sockaddr*)&sin,sizeof(sockaddr_in))){
close(sockfd);
return -1;
}
fcntl(sockfd,F_SETFL,O_NONBLOCK);
return sockfd;
}
char* http_send_request(const char* hostname,const char* resource){
char *ip=host_to_ip(hostname);
int sockfd=http_create_socket(ip);
char buffer[buffer_size]{};
sprintf(buffer, "GET %s %s\r\nHost: %s\r\n%s\r\n", resource, http_version, hostname, connection_type);
send(sockfd,buffer,strlen(buffer),0);
//select
fd_set fdread;
FD_ZERO(&fdread);
FD_SET(sockfd,&fdread);
struct timeval tv;
tv.tv_sec=5;
tv.tv_usec=0;
vector<char>result;
while(1){
int selection=select(sockfd+1,&fdread,nullptr,nullptr,&tv);
if(!selection||FD_ISSET(sockfd,&fdread)){
break;
}
else{
char buffer[buffer_size]{};
int len=recv(sockfd,buffer,buffer_size,0);
if(len==0){
break;
}
result.insert(result.end(),buffer,buffer+len);
}
}
result.push_back('\0');
// 如果需要返回一个 C 风格的字符串,可以使用下面的代码将 vector 转换为字符串
result.push_back('\0'); // 确保有结束符
char* c_result = new char[result.size()];
std::memcpy(c_result, result.data(), result.size());
return c_result; // 注意:调用者负责释放这段内存
}
int main(){
const char* hostname = "httpbin.org";
const char* resource = "/get";
char* response = http_send_request(hostname, resource);
if (response) {
std::cout << "Received Response:\n" << response << std::endl;
delete[] response; // 释放内存
} else {
std::cerr << "Failed to get a response from the server." << std::endl;
}
return 0;
}