您的代码片段展示了一个基本的HTTP服务器框架,使用C++和POSIX socket编程。代码实现了HttpServer
类中的几个主要功能,包括初始化监听socket、接收HTTP请求以及处理连接。以下是一些可能需要改进和注意的地方:
1. usockaddr
结构体
您提到的 usockaddr
似乎是一个自定义结构体,但在标准POSIX socket编程中并不存在该类型。如果您打算使用标准的 sockaddr
结构体,可以直接用它替换:
struct sockaddr_storage usa; // 使用 sockaddr_storage 来支持IPv4和IPv6
2. 错误检查
尽量为每个系统调用(如 setsockopt
, bind
, listen
, accept
等)添加详细的错误处理,以帮助调试。例如,在绑定或监听失败时,打印具体错误信息。
3. Port 参数
在 Init()
方法中,您将传入的端口参数保存在成员变量 port_
中,但后续使用的是常量 PORT
。建议直接使用传入参数。
4. 在接受连接时线程处理
创建新线程以处理每个连接是合适的,但要确保在线程函数中正确地处理指针。您可以通过适当的方法将文件描述符(conn_fd)封装到一个对象中,并确保其生命周期不会引起数据竞争。
static void* handle_request(void* arg) {
int conn_fd = reinterpret_cast<int>(arg);
// 这里可以处理请求...
close(conn_fd); // 请求处理完毕后关闭文件描述符
return nullptr;
}
完整示例优化后的代码
以下是修改后的代码片段,结合上述建议:
#include <iostream>
#include <cstring>
#include <sys/socket.h>
#include <netinet/in.h>
#include <unistd.h>
#include <pthread.h>
#include "http_server.h"
#include "../cJSON/cJSON.h"
void* handle_request(void* arg) {
int conn_fd = reinterpret_cast<int>(arg);
// TODO: 添加请求处理逻辑
close(conn_fd); // 完成后关闭连接
return nullptr;
}
void HttpServer::receive_response() {
fd_set lfdset;
int maxfd;
for (;;) {
FD_ZERO(&lfdset);
maxfd = -1;
int conn_fd = -1;
if (listenfd_ != -1) {
FD_SET(listenfd_, &lfdset);
if (listenfd_ > maxfd)
maxfd = listenfd_;
}
if (select(maxfd + 1, &lfdset, nullptr, nullptr, nullptr) < 0) {
perror("select");
exit(1);
}
struct sockaddr_storage usa; // 更改为sockaddr_storage以支持不同协议族
socklen_t sz = sizeof(usa);
if (listenfd_ != -1 && FD_ISSET(listenfd_, &lfdset)) {
conn_fd = accept(listenfd_, reinterpret_cast<struct sockaddr*>(&usa), &sz);
if (conn_fd < 0) {
perror("accept");
continue; // 出现错误,继续下一轮循环
}
pthread_t thread;
if (pthread_create(&thread, nullptr, handle_request, reinterpret_cast<void*>(conn_fd)) != 0) {
perror("Failed to create thread");
close(conn_fd); // 确保即使创建线程失败也能关闭连接。
continue;
}
pthread_detach(thread); // 分离线程以避免内存泄漏
}
}
}
int HttpServer::Init(const int& port) {
port_ = port;
struct sockaddr_in srv_addr;
memset(&srv_addr, 0, sizeof(srv_addr));
srv_addr.sin_family=AF_INET;
srv_addr.sin_port=htons(port_);
srv_addr.sin_addr.s_addr=htonl(INADDR_ANY);
listenfd_ = socket(AF_INET, SOCK_STREAM, 0);
if (listenfd_ < 0) {
perror("Socket creation failed");
return -1;
}
int opt = 1;
if (setsockopt(listenfd_, SOL_SOCKET, SO_REUSEADDR, &opt, sizeof(opt)) == -1) {
perror("setsockopt error");
close(listenfd_);
return -1;
}
if (bind(listenfd_, reinterpret_cast<struct sockaddr*>(&srv_addr), sizeof(srv_addr)) == -1) {
perror("bind error");
close(listenfd_);
return -1;
}
if (listen(listenfd_, 128) == -1) {
perror("listen error");
close(listenfd_);
return -1;
}
return 0;
}
void HttpServer::SendMessage(const std::string& path, const std::string& body) {
// TODO: 实现发送消息逻辑,这里留空等待实现。
}
HttpServer::~HttpServer() {
close(listenfd_);
}
总结
这段代码应该能给你一些启发,让你在实现HTTP服务器时更加顺利。如果有任何特定问题或者想了解更多,请随时询问!
内容由零声教学AI助手提供,问题来源于学员提问