一、在TcpConnection 中多添加和http協(xié)議相關(guān)的request和response
struct TcpConnection {
struct EventLoop* evLoop;
struct Channel* channel;
struct Buffer* readBuf;
struct Buffer* writeBuf;
char name[32];
// http協(xié)議
struct HttpRequest* request;
struct HttpResponse* response;
};
二、給客戶端回復(fù)數(shù)據(jù)(方法一)
1.在Buffer.h文件中添加bufferSendData函數(shù):
// 發(fā)送數(shù)據(jù)
int bufferSendData(struct Buffer* buf,int socket);
// 發(fā)送數(shù)據(jù)
int bufferSendData(struct Buffer* buf,int socket) {
// 判斷有無(wú)數(shù)據(jù)
int readableSize = bufferReadableSize(buf);// 這些未讀的數(shù)據(jù)就是待發(fā)送的數(shù)據(jù)
if(readableSize > 0) {
int count = send(socket,buf->data + buf->readPos,readableSize,MSG_NOSIGNAL);
if(count > 0) {
buf->readPos += count;
usleep(1);
}
return count;
}
return 0;
}
?2.在TcpConnection.c文件中添加processWrite函數(shù):
int processWrite(void* arg) {
struct TcpConnection* conn = (struct TcpConnection*)arg;
// 發(fā)送數(shù)據(jù)
int count = bufferSendData(conn->writeBuf,conn->channel->fd);
if(count > 0) {
// 判斷數(shù)據(jù)是否被全部發(fā)送出去了
if(bufferReadableSize(conn->writeBuf) == 0){
// 1.不再檢測(cè)寫事件 -- 修改channel中保存的事件
writeEventEnable(conn->channel,false);
// 2.修改dispatcher檢測(cè)的集合 -- 添加任務(wù)節(jié)點(diǎn)
eventLoopAddTask(conn->evLoop,conn->channel,MODIFY);
// 3.刪除這個(gè)節(jié)點(diǎn)
eventLoopAddTask(conn->evLoop,conn->channel,DELETE);
}
}
return 0;
}
3.修改tcpConnectionInit函數(shù)中調(diào)用的channelInit函數(shù)的寫回調(diào)函數(shù)為processWrite函數(shù)
?// 初始化
struct TcpConnection* tcpConnectionInit(int fd,struct EventLoop* evLoop) {
struct TcpConnection* conn = (struct TcpConnection*)malloc(sizeof(struct TcpConnection));
conn->evLoop = evLoop;
struct Channel* channel = channelInit(fd,ReadEvent,processRead,processWrite,tcpConnectionDestroy,conn);
conn->channel = channel;
conn->readBuf = bufferInit(10240); // 10k
conn->writeBuf = bufferInit(10240); // 10k
sprintf(conn->name,"TcpConnection-%d",fd);
// http協(xié)議
conn->request = httpRequestInit();
conn->response = httpResponseInit();
// 把channel添加到事件循環(huán)對(duì)應(yīng)的任務(wù)隊(duì)列里邊
eventLoopAddTask(evLoop,conn->channel,ADD);
return conn;
}
三、給客戶端回復(fù)數(shù)據(jù)(方法二)
- 在TcpConnection.h中添加?
// #define MSG_SEND_AUTO
- TcpConnection.c
// 接收客戶端數(shù)據(jù)
int processRead(void* arg) {
struct TcpConnection* conn = (struct TcpConnection*)arg;
// 接收數(shù)據(jù)
int count = bufferSocketRead(conn->readBuf,conn->channel->fd);
if(count > 0) {
// 接收到了Http請(qǐng)求,解析Http請(qǐng)求
int socket = conn->channel->fd;
#ifdef MSG_SEND_AUTO // 給客戶端回復(fù)數(shù)據(jù)的方式一
writeEventEnable(conn->channel,true);
eventLoopAddTask(conn->evLoop,conn->channel,MODIFY);
#endif
bool flag = parseHttpRequest(conn->request,conn->readBuf,conn->response,conn->writeBuf,socket);
if(!flag) {
// 解析失敗,回復(fù)一個(gè)簡(jiǎn)單的html
char* errMsg = "Http/1.1 400 Bad Request\r\n\r\n";
bufferAppendString(conn->writeBuf,errMsg);
}
}
else{
#ifdef MSG_SEND_AUTO
// 斷開連接
eventLoopAddTask(conn->evLoop,conn->channel,DELETE);
#endif
}
#ifndef MSG_SEND_AUTO
// 斷開連接
eventLoopAddTask(conn->evLoop,conn->channel,DELETE);
#endif
return 0;
}
1.修改HttpRequest.c文件中的sendFile函數(shù)和sendDir函數(shù)
void sendFile(const char* fileName,struct Buffer* sendBuf,int cfd) {
// 打開文件
int fd = open(fileName,O_RDONLY);
if(fd < 0) {
perror("open");
return;
}
// assert(fd > 0);
#if 1
while (1) {
char buf[1024];
int len = read(fd,buf,sizeof(buf));
if(len > 0) {
// send(cfd,buf,len,0);
bufferAppendData(sendBuf,buf,len);
#ifndef MSG_SEND_AUTO // 給客戶端回復(fù)數(shù)據(jù)(方法二)
bufferSendData(sendBuf,cfd);
#endif
}
else if(len == 0) {
break;
}
else{
close(fd);
perror("read");
}
}
#else
// 把文件內(nèi)容發(fā)送給客戶端
off_t offset = 0;
int size = lseek(fd,0,SEEK_END);// 文件指針移動(dòng)到了尾部
lseek(fd,0,SEEK_SET);// 移動(dòng)到文件頭部
while (offset < size){
int ret = sendfile(cfd,fd,&offset,size - offset);
printf("ret value: %d\n",ret);
if (ret == -1 && errno == EAGAIN) {
printf("沒數(shù)據(jù)...\n");
}
}
#endif
close(fd);
}
void sendDir(const char* dirName,struct Buffer* sendBuf,int cfd) {
char buf[4096] = {0};
sprintf(buf,"<html><head><title>%s</title></head><body><table>",dirName);
struct dirent** nameList;
int num = scandir(dirName,&nameList,NULL,alphasort);
for(int i=0;i<num;i++) {
// 取出文件名 nameList 指向的是一個(gè)指針數(shù)組 struct dirent* tmp[]
char* name = nameList[i]->d_name;
struct stat st;
char subPath[1024] = {0};
sprintf(subPath,"%s/%s",dirName,name);
stat(subPath,&st);
if(S_ISDIR(st.st_mode)) {
// 從當(dāng)前目錄跳到子目錄里邊,/
sprintf(buf+strlen(buf),
"<tr><td><a href=\"%s/\">%s</a></td><td>%ld</td></tr>",
name,name,st.st_size);
}else{
sprintf(buf+strlen(buf),
"<tr><td><a href=\"%s\">%s</a></td><td>%ld</td></tr>",
name,name,st.st_size);
}
// send(cfd,buf,strlen(buf),0);
bufferAppendString(sendBuf,buf);
#ifndef MSG_SEND_AUTO // 給客戶端回復(fù)數(shù)據(jù)(方法二)
bufferSendData(sendBuf,cfd);
#endif
memset(buf,0,sizeof(buf));
free(nameList[i]);
}
sprintf(buf,"</table></body></html>");
// send(cfd,buf,strlen(buf),0);
bufferAppendString(sendBuf,buf);
#ifndef MSG_SEND_AUTO // 給客戶端回復(fù)數(shù)據(jù)(方法二)
bufferSendData(sendBuf,cfd);
#endif
free(nameList);
}
2.修改HttpResponse.c文件的httpResponsePrepareMsg函數(shù)
// 組織http響應(yīng)數(shù)據(jù)
void httpResponsePrepareMsg(struct HttpResponse* response,struct Buffer* sendBuf,int socket) {
// 狀態(tài)行
char tmp[1024] = {0};
sprintf(tmp,"HTTP/1.1 %d %s\r\n",response->statusCode,response->statusMsg);
bufferAppendString(sendBuf,tmp);
// 響應(yīng)頭
for(int i=0;i<response->headerNum;++i) {
// memset(tmp,0,sizeof(tmp)); ?????????
sprintf(tmp,"%s: %s\r\n",response->headers[i].key,response->headers[i].value);
bufferAppendString(sendBuf,tmp);
}
// 空行
bufferAppendString(sendBuf,"\r\n");
#ifndef MSG_SEND_AUTO // 給客戶端回復(fù)數(shù)據(jù)(方法二)
bufferSendData(sendBuf,socket);
#endif
// 回復(fù)的數(shù)據(jù)
response->sendDataFunc(response->fileName,sendBuf,socket);
}
?四、釋放資源 tcpConnectionDestroy
// 釋放資源
int tcpConnectionDestroy(void* arg);
// 釋放資源
int tcpConnectionDestroy(void* arg) {
struct TcpConnection* conn = (struct TcpConnection*)arg;
if(conn!=NULL) {
if (conn->readBuf && bufferReadableSize(conn->readBuf) == 0 &&
conn->writeBuf && bufferReadableSize(conn->writeBuf) == 0) {
destroyChannel(conn->evLoop,conn->channel);
bufferDestroy(conn->readBuf);
bufferDestroy(conn->writeBuf);
httpRequestDestroy(conn->request);
httpResponseDestroy(conn->response);
free(conn);
}
}
return 0;
}
五、日志功能文章來源:http://www.zghlxwxcb.cn/news/detail-818744.html
#pragma once
#include <stdarg.h>
#include <stdio.h>
#define DEBUG 1
#if DEBUG
/*
* 如果不加 do ... while(0) 在進(jìn)行條件判斷的時(shí)候(只有一句話), 省略了{(lán)}, 就會(huì)出現(xiàn)語(yǔ)法錯(cuò)誤
* if
* xxxxx
* else
* xxxxx
* 宏被替換之后, 在 else 前面會(huì)出現(xiàn)一個(gè) ; --> 語(yǔ)法錯(cuò)誤
*/
#define LOG(type, fmt, args...) \
do{\
printf("%s: %s@%s, line: %d\n***LogInfo[", type, __FILE__, __FUNCTION__, __LINE__);\
printf(fmt, ##args);\
printf("]\n\n");\
}while(0)
#define Debug(fmt, args...) LOG("DEBUG", fmt, ##args)
#define Error(fmt, args...) do{LOG("ERROR", fmt, ##args);exit(0);}while(0)
#else
#define LOG(fmt, args...)
#define Debug(fmt, args...)
#define Error(fmt, args...)
#endif
?文章來源地址http://www.zghlxwxcb.cn/news/detail-818744.html
到了這里,關(guān)于基于多反應(yīng)堆的高并發(fā)服務(wù)器【C/C++/Reactor】(中)在TcpConnection 中接收并解析Http請(qǐng)求消息的文章就介紹完了。如果您還想了解更多內(nèi)容,請(qǐng)?jiān)谟疑辖撬阉鱐OY模板網(wǎng)以前的文章或繼續(xù)瀏覽下面的相關(guān)文章,希望大家以后多多支持TOY模板網(wǎng)!