一个HTTP连接要完成的任务:
class HttpConn
{
private:
int m_fd;
struct sockaddr_in m_addr;
bool m_isClosed;
int m_iovCnt;
struct iovec m_iov[2];
Buffer m_readBuff;
Buffer m_writeBuff;
HttpResponse m_response;
HttpRequest m_request;
public:
static bool isET;
static const char *srcDir;
/*原子对象的主要特征是,从不同的线程访问这个包含的值不会导致数据竞争
*(即,这样做是明确定义的行为,访问正确排序)*/
static std::atomic<int> userCount;
HttpConn();
~HttpConn();
void Close();
int GetFd() const;
sockaddr_in GetAddr() const;
const char *GetIP() const;
int GetPort() const;
/*初始化*/
void Init(int sockFd, const sockaddr_in &addr);
/*解析接收的请求报文,并准备响应报文*/
bool Process();
/*从m_fd中接收数据*/
ssize_t Read(int *saveErrno);
/*往m_fd中发送数据*/
ssize_t Write(int *saveErrno);
int ToWriteBytes() {
return m_iov[0].iov_len + m_iov[1].iov_len;
}
};
该类有两个缓冲区:
Buffer m_readBuff
,读缓冲区用于从socket接收请求报文Buffer m_writeBuff
,写缓冲区用于缓冲往socket发送的响应报文解析请求报文:
m_request.Parse(m_readBuff)
,从读缓冲区读取请求报文并解析
生成响应报文:
m_response.Respond(m_writeBuff)
,将生成的响应报文放入写缓冲区
HttpConn的读写:
这里的Read()
需要将请求报文的内容读取到读缓冲区里面来,这样m_request才能够解析报文。
然后是Write()
,这里主要是使用了writev()
连续写来将写缓冲区中的响应报文写到socket中。
注意由于生成响应报文的响应正文里面只是生成了Content-length
,并没有将文件也放进缓冲区,因为如果文件太大,缓冲区可能会装不下。所以我们在传输的时候,采用了集中写的方式,一块传输buff里面的内容,另一块传输内存映射的文件指针。