Muduo 网络编程示例之四:Twisted Finger
2011-02-23 21:34
471 查看
陈硕 (giantchen_AT_gmail)
Blog.csdn.net/Solstice
这是《Muduo 网络编程示例》系列的第四篇文章。
Muduo 全系列文章列表: http://blog.csdn.net/Solstice/category/779646.aspx
Python Twisted 是一款非常好的网络库,它也采用 Reactor 作为网络编程的基本模型,所以从使用上与 muduo 颇有相似之处。(当然,muduo 没有 deferreds)Finger 是 twisted 文档的一个经典例子,本文展示如何用 muduo 来实现最简单的 finger 服务端。限于篇幅,只实现 finger01~07。代码位于 examples/twisted/finger 。
以下省略头文件和 namespace。
注意这段代码有安全问题,如果恶意客户端不断发送数据而不换行,会撑爆服务端的内存。另外,Buffer::findCRLF() 是线性查找,如果客户端每次发一个字节,服务端的时间复杂度为 O(N^2),会消耗 CPU 资源。
安全问题同上。
安全问题同上。
以上就是全部内容,可以用 telnet 扮演客户端来测试我们的简单 finger 服务端。
$ ./bin/twisted_finger07
另一个命令行运行
$ telnet localhost 1079
Trying ::1...
Trying 127.0.0.1...
Connected to localhost.
Escape character is '^]'.
muduo
No such user
Connection closed by foreign host.
再试一次
$ telnet localhost 1079
Trying ::1...
Trying 127.0.0.1...
Connected to localhost.
Escape character is '^]'.
schen
Happy and well
Connection closed by foreign host.
冒烟测试过关。
(待续)
Blog.csdn.net/Solstice
这是《Muduo 网络编程示例》系列的第四篇文章。
Muduo 全系列文章列表: http://blog.csdn.net/Solstice/category/779646.aspx
Python Twisted 是一款非常好的网络库,它也采用 Reactor 作为网络编程的基本模型,所以从使用上与 muduo 颇有相似之处。(当然,muduo 没有 deferreds)Finger 是 twisted 文档的一个经典例子,本文展示如何用 muduo 来实现最简单的 finger 服务端。限于篇幅,只实现 finger01~07。代码位于 examples/twisted/finger 。
1 拒绝连接
什么都不做,程序空等。finger01.cc#include <muduo/net/EventLoop.h>
using namespace muduo;
using namespace muduo::net;
int main()
{
EventLoop loop;
loop.loop();
}
2 接受新连接
在 1079 端口侦听新连接,接受连接之后什么都不做,程序空等。muduo 会自动丢弃收到的数据。finger02.cc#include <muduo/net/EventLoop.h>
#include <muduo/net/TcpServer.h>
using namespace muduo;
using namespace muduo::net;
int main()
{
EventLoop loop;
TcpServer server(&loop, InetAddress(1079), "Finger");
server.start();
loop.loop();
}
3 主动断开连接
接受新连接之后主动断开。finger03.cc以下省略头文件和 namespace。
void onConnection(const TcpConnectionPtr& conn)
{
if (conn->connected())
{
conn->shutdown();
}
}
int main()
{
EventLoop loop;
TcpServer server(&loop, InetAddress(1079), "Finger");
server.setConnectionCallback(onConnection);
server.start();
loop.loop();
}
4 读取用户名,然后断开连接
如果读到一行以 \r\n 结尾的消息,就断开连接。finger04.cc注意这段代码有安全问题,如果恶意客户端不断发送数据而不换行,会撑爆服务端的内存。另外,Buffer::findCRLF() 是线性查找,如果客户端每次发一个字节,服务端的时间复杂度为 O(N^2),会消耗 CPU 资源。
void onMessage(const TcpConnectionPtr& conn,
Buffer* buf,
Timestamp receiveTime)
{
if (buf->findCRLF())
{
conn->shutdown();
}
}
int main()
{
EventLoop loop;
TcpServer server(&loop, InetAddress(1079), "Finger");
server.setMessageCallback(onMessage);
server.start();
loop.loop();
}
5. 读取用户名、输出错误信息、然后断开连接
如果读到一行以 \r\n 结尾的消息,就发送一条出错信息,然后断开连接。finger05.cc安全问题同上。
void onMessage(const TcpConnectionPtr& conn,
Buffer* buf,
Timestamp receiveTime)
{
if (buf->findCRLF())
{
conn->send("No such user\r\n");
conn->shutdown();
}
}
int main()
{
EventLoop loop;
TcpServer server(&loop, InetAddress(1079), "Finger");
server.setMessageCallback(onMessage);
server.start();
loop.loop();
}
6. 从空的 UserMap 里查找用户
从一行消息中拿到用户名(第 22 行),在 UserMap 里查找,然后返回结果。finger06.cc安全问题同上。
typedef std::map<string, string> UserMap;
UserMap users;
string getUser(const string& user)
{
string result = "No such user";
UserMap::iterator it = users.find(user);
if (it != users.end())
{
result = it->second;
}
return result;
}
void onMessage(const TcpConnectionPtr& conn,
Buffer* buf,
Timestamp receiveTime)
{
const char* crlf = buf->findCRLF();
if (crlf)
{
string user(buf->peek(), crlf);
conn->send(getUser(user) + "\r\n");
buf->retrieveUntil(crlf + 2);
conn->shutdown();
}
}
int main()
{
EventLoop loop;
TcpServer server(&loop, InetAddress(1079), "Finger");
server.setMessageCallback(onMessage);
server.start();
loop.loop();
}
7. 往 UserMap 里添加一个用户
与前面几乎完全一样,只多了第 31 行。finger07.cctypedef std::map<string, string> UserMap;
UserMap users;
string getUser(const string& user)
{
string result = "No such user";
UserMap::iterator it = users.find(user);
if (it != users.end())
{
result = it->second;
}
return result;
}
void onMessage(const TcpConnectionPtr& conn,
Buffer* buf,
Timestamp receiveTime)
{
const char* crlf = buf->findCRLF();
if (crlf)
{
string user(buf->peek(), crlf);
conn->send(getUser(user) + "\r\n");
buf->retrieveUntil(crlf + 2);
conn->shutdown();
}
}
int main()
{
users["schen"] = "Happy and well";
EventLoop loop;
TcpServer server(&loop, InetAddress(1079), "Finger");
server.setMessageCallback(onMessage);
server.start();
loop.loop();
}
以上就是全部内容,可以用 telnet 扮演客户端来测试我们的简单 finger 服务端。
Telnet 测试
在一个命令行窗口运行$ ./bin/twisted_finger07
另一个命令行运行
$ telnet localhost 1079
Trying ::1...
Trying 127.0.0.1...
Connected to localhost.
Escape character is '^]'.
muduo
No such user
Connection closed by foreign host.
再试一次
$ telnet localhost 1079
Trying ::1...
Trying 127.0.0.1...
Connected to localhost.
Escape character is '^]'.
schen
Happy and well
Connection closed by foreign host.
冒烟测试过关。
(待续)
相关文章推荐
- Muduo 网络编程示例之四:Twisted Finger
- Muduo 网络编程示例之六:限制服务器的最大并发连接数
- Muduo 网络编程示例之七:“串并转换”连接服务器及其自动化测试
- Muduo 网络编程示例之八:用 Timing wheel 踢掉空闲连接
- Muduo 网络编程示例之零:前言
- Muduo 网络编程示例之五: 测量两台机器的网络延迟
- Muduo 网络编程示例之三:定时器
- Muduo 网络编程示例之三:定时器
- Muduo 网络编程示例之零:前言
- Muduo 网络编程示例之零:前言
- Muduo 网络编程示例之三:定时器
- Muduo 网络编程示例之五: 测量两台机器的网络延迟
- Muduo 网络编程示例之零:前言
- Muduo 网络编程示例之九:简单的消息广播服务
- Muduo 网络编程示例之十:socks4a 代理服务器
- Muduo 网络编程示例之五: 测量两台机器的网络延迟
- Muduo 网络编程示例之九:简单的消息广播服务
- Muduo 网络编程示例之十:socks4a 代理服务器
- Muduo 网络编程示例之一:五个简单 TCP 协议
- Muduo 网络编程示例之一:五个简单 TCP 协议