Skip to content

Commit 9c0d3ee

Browse files
committed
update
1 parent 0d63161 commit 9c0d3ee

File tree

2 files changed

+60
-8
lines changed

2 files changed

+60
-8
lines changed

code/day06/server.cpp

+58-6
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,61 @@
1-
#include "EventLoop.h"
21
#include "Server.h"
2+
#include "Socket.h"
3+
#include "InetAddress.h"
4+
#include "Channel.h"
5+
#include <functional>
6+
#include <string.h>
7+
#include <unistd.h>
38

4-
int main() {
5-
EventLoop *loop = new EventLoop();
6-
Server *server = new Server(loop);
7-
loop->loop();
8-
return 0;
9+
#define READ_BUFFER 1024
10+
11+
Server::Server(EventLoop *_loop) : loop(_loop){
12+
Socket *serv_sock = new Socket();
13+
InetAddress *serv_addr = new InetAddress("127.0.0.1", 8888);
14+
serv_sock->bind(serv_addr);
15+
serv_sock->listen();
16+
serv_sock->setnonblocking();
17+
18+
Channel *servChannel = new Channel(loop, serv_sock->getFd());
19+
std::function<void()> cb = std::bind(&Server::newConnection, this, serv_sock);
20+
servChannel->setCallback(cb);
21+
servChannel->enableReading();
22+
23+
}
24+
25+
Server::~Server()
26+
{
27+
928
}
29+
30+
void Server::handleReadEvent(int sockfd){
31+
char buf[READ_BUFFER];
32+
while(true){ //由于使用非阻塞IO,读取客户端buffer,一次读取buf大小数据,直到全部读取完毕
33+
bzero(&buf, sizeof(buf));
34+
ssize_t bytes_read = read(sockfd, buf, sizeof(buf));
35+
if(bytes_read > 0){
36+
printf("message from client fd %d: %s\n", sockfd, buf);
37+
write(sockfd, buf, sizeof(buf));
38+
} else if(bytes_read == -1 && errno == EINTR){ //客户端正常中断、继续读取
39+
printf("continue reading");
40+
continue;
41+
} else if(bytes_read == -1 && ((errno == EAGAIN) || (errno == EWOULDBLOCK))){//非阻塞IO,这个条件表示数据全部读取完毕
42+
printf("finish reading once, errno: %d\n", errno);
43+
break;
44+
} else if(bytes_read == 0){ //EOF,客户端断开连接
45+
printf("EOF, client fd %d disconnected\n", sockfd);
46+
close(sockfd); //关闭socket会自动将文件描述符从epoll树上移除
47+
break;
48+
}
49+
}
50+
}
51+
52+
void Server::newConnection(Socket *serv_sock){
53+
InetAddress *clnt_addr = new InetAddress(); //会发生内存泄露!没有delete
54+
Socket *clnt_sock = new Socket(serv_sock->accept(clnt_addr)); //会发生内存泄露!没有delete
55+
printf("new client fd %d! IP: %s Port: %d\n", clnt_sock->getFd(), inet_ntoa(clnt_addr->addr.sin_addr), ntohs(clnt_addr->addr.sin_port));
56+
clnt_sock->setnonblocking();
57+
Channel *clntChannel = new Channel(loop, clnt_sock->getFd());
58+
std::function<void()> cb = std::bind(&Server::handleReadEvent, this, clnt_sock->getFd());
59+
clntChannel->setCallback(cb);
60+
clntChannel->enableReading();
61+
}

day06-服务器与事件驱动核心类登场.md

+2-2
Original file line numberDiff line numberDiff line change
@@ -6,14 +6,14 @@
66

77
需要注意的是,事件驱动不是服务器开发的专利。事件驱动是一种设计应用的思想、开发模式,而服务器是根据客户端的不同请求提供不同的服务的一个实体应用,服务器开发可以采用事件驱动模型、也可以不采用。事件驱动模型也可以在服务器之外的其他类型应用中出现,如进程通信、k8s调度、V8引擎、Node.js等。
88

9-
理解了以上的概念,就能容易理解服务器开发的两种经典模式——Reactor和Proactor模式。详细请参考$游双《Linux高性能服务器编程》$第八章第四节、$陈硕《Linux多线程服务器编程》$第六章第六节。
9+
理解了以上的概念,就能容易理解服务器开发的两种经典模式——Reactor和Proactor模式。详细请参考游双《Linux高性能服务器编程》第八章第四节、陈硕《Linux多线程服务器编程》第六章第六节。
1010

1111
> 如何深刻理解Reactor和Proactor? - 小林coding的回答 - 知乎
1212
https://www.zhihu.com/question/26943938/answer/1856426252
1313

1414
由于Linux内核系统调用的设计更加符合Reactor模式,所以绝大部分高性能服务器都采用Reactor模式进行开发,我们的服务器也使用这种模式。
1515

16-
接下来我们要将服务器改造成Reactor模式。首先我们将整个服务器抽象成一个`Server`类,这个类中有一个main Reactor(在这个版本没有sub Reactor),里面的核心是一个`EventLoop`(libevent中叫做EventBase),这是一个事件循环,我们添加需要监听的事务到这个事件循环内,每次有事件发生时就会通知(在程序中返回给我们`Channel`),然后根据不同的描述符、事件类型进行处理(以回调函数的方式)。
16+
接下来我们要将服务器改造成Reactor模式。首先我们将整个服务器抽象成一个`Server`类,这个类中有一个main-Reactor(在这个版本没有sub-Reactor),里面的核心是一个`EventLoop`(libevent中叫做EventBase),这是一个事件循环,我们添加需要监听的事务到这个事件循环内,每次有事件发生时就会通知(在程序中返回给我们`Channel`),然后根据不同的描述符、事件类型进行处理(以回调函数的方式)。
1717
> 如果你不太清楚这个自然段在讲什么,请先看一看前面提到的两本书的具体章节。
1818
1919
EventLoop类的定义如下:

0 commit comments

Comments
 (0)