echo 服务器测试
/*
muduo网络库给用户提供了两个主要的类
TCPServer:用于编写服务器程序
TCPClient:用于编写客户端程序
epoll+线程池
好处:能够把网络I/O的代码和业务代码区分开,主要开发业务,网络库代码封装了
业务代码暴漏:1。用户的连接和断开2.用户可读写事件
*/
#include<muduo/net/TcpServer.h>
#include<muduo/net/EventLoop.h>
#include<string>
#include<iostream>
#include<functional>
using namespace muduo;
using namespace muduo::net;
using namespace std;
//基于muduo网络库开发服务器程序
/*
1.组合TcpServer对象
2.创建EventLoop事件循环对象的指针
3.明确TcpServer构造函数需要什么参数,输出ChatServer的构造函数
4.在当前服务器类的构造函数中,注册处理链接的回调函数和处理读写事件的回调函数
5.设置合适的服务端线程数量,muduo库会自己划分I/O和woker线程
*/
class ChatServer
{
public:
ChatServer(EventLoop* loop,
const InetAddress& listenAddr,
const string& nameArg)
:_server(loop,listenAddr,nameArg)
,_loop(loop)
{
//将网络代码和业务代码区分开
//普通函数 我知道这个函数就要在这里发生,也知道会发生什么(在什么地方发生,在发生之后怎么做)
//给服务器注册用户连接创建和断开回调(回调 模块解耦的重点)
//知道了该怎么做,但是不知道什么时候会发生,对端发送消息才知道用户连接的创建和断开,数据读写请求,网络库来监听,接听到对端发送的业务请求,注册回调,相应的事件发生后,帮我们调用相应的回调函数,在回调中开发业务
//连接的创建和断开 setConnectionCallback 返回值<void (const TcpConnectionPtr&) 没有返回值,一个成员变量
//消息的读写的事件 setMessageCallback
//成员方法自带this指针,使用绑定器处理问题,底层监听到就会帮我们调用
_server.setConnectionCallback(std::bind(&ChatServer::onConnection,this,_1));
//给服务器注册用户读写事件回调
_server.setMessageCallback(std::bind(&ChatServer::onMessage,this,_1,_2,_3));
//设置服务端的线程数量 1个I/O 3个工作线程
_server.setThreadNum(4);
}
//开启事件循环
void start()
{
_server.start();
}
private:
//专门处理用户的连接创建和断开 (自行在muduo库上注册了)
//从epoll拿来事件 listenfd 从listenfd上accept表示有新用户连接 拿出来一个和socket专门和用户通信
//当有新用户创建或者原来连接用户断开连接,这个方法就会响应
void onConnection(const TcpConnectionPtr& conn)
{
//是否连接成功
//toip 打印ip toport 打印端口
if(conn->connected())
{
//对端地址信息
cout << conn->peerAddress().toIpPort() << "->" << conn->localAddress().toIpPort() << "STATE :online" <<endl;
}
else
{
cout << conn->peerAddress().toIpPort() << "->" << conn->localAddress().toIpPort() << "STATE :offline" <<endl;
//相当于close 释放 socket资源
conn->shutdown();
//连接断开,回收资源
_loop->quit();
}
}
//专门处理用户读写事件
void onMessage(const TcpConnectionPtr& conn,
Buffer* buffer,
Timestamp time)
{
/*
1.第一个参数是连接,可以通过它读写数据
2.缓冲区
3.接收到数据的时间细节
*/
//把接收到的全部数据放到字符串中
string buf = buffer->retrieveAllAsString();
cout << "recv data" << buf << "Time:" << time.toString() << endl;
conn->send(buf);
}
TcpServer _server; //#1 对象需要构造,不指定构造就需要默认构造,没有默认构造,不指定相应的构造就无法创建对象
/*
参数有四个
1.事件循环EventLoop, EventLoop* loop 事件循环Reactor反应堆
2.绑定的IP地址和端口号, const InetAddress& listenAddr IP地址加端口
3.给TcpServer一个名字, const string& nameArg 服务器的名字,给线程绑定名字
4.TCP协议的选项 Option option = kNoReusePort
*/
EventLoop* _loop; //#2 保存事件循环 操作epoll
};
int main()
{
EventLoop loop;
InetAddress addr("127.0.0.1",6000);
ChatServer server(&loop,addr,"Charserver");
//listenfd 将epoll_ctl添加到epoll上
server.start();
//epoll_wait 以阻塞方式等待新用户连接,已连接用户的读写事件
loop.loop();
return 0;
}
调试文件
ctrl+shift+b
task.json
{
"tasks": [
{
"type": "shell",
"label": "g++ build active file",
"command": "/usr/bin/g++",
"args": [
"-g",
"-std=c++11",
"${file}",
"-o",
"${fileDirname}/${fileBasenameNoExtension}",
"-lmuduo_net",
"-lmuduo_base",
"-lpthread"
],
"options": {
"cwd": "/usr/bin"
},
"problemMatcher": [
"$gcc"
],
"group": "build"
}
],
"version": "2.0.0"
}