这次写的是一个网络版五子棋
怎么说的,这次的cpp文件文件比较多,我就贴个github代码吧
github
编译主要看 makefile里那几个文件
实现了 登录 匹配下棋。
服务器用了 epoll+线程池(模仿《linux高性能编程写的》)但这次的教训就是这个棋局的主体业务逻辑应该放在服务器(我写在客户端由客户端判断棋局是否结束),而且线程池处理也是计算密集型任务,在这种俩个用户并非同时下棋的程序中可以不用。更何况放在客户端的业务逻辑可以伪造的,这样服务器就可能收到伪造的数据。
给大家看下效果:
经验:
- 由于用的是PACK的buffer缓存给线程池的process函数执行(同样还有写缓冲), 每次EPOLLIN 读入后需要切换 EPOLLOUT,写出后再切换EPOLLIN,这样就不会多次读入到同一缓冲区了。
- c++线程中想要使用类的函数,得需要
thread(clientUser::UI, this).detach();
在参数中传入对象的指针,同时这个调用的函数必须得是类内的静态函数,且这个静态函数也只能调用类的静态成员,想要使用对象只能使用传进来的arg 通过clientUser *cu = (clientUser *) arg;
再使用cu->xxx
来使用cu内的成员
3.输入出错重新输入的c++方式
while (1) {
cin >> ch;
if (cin.fail()) {
std::cout << "输入有误" << std::endl;
cin.clear();
cin.ignore();
continue;
}
break;
}
4.condition_variable中要传锁得是unique_lock ,而不是mutex。
同时从源码可知调用条件变量的wait中可以传入的条件是while(!p)而不是if,也就是条件不满足会重新wait休眠。
template<typename _Predicate>
void
wait(unique_lock<mutex>& __lock, _Predicate __p)
{
while (!__p())
wait(__lock);
}
5.类的静态成员的初始化在类外不能在.h,放其中一个.cpp即可(最好放在类的.cpp内)
6.网络发包的pack中不能出现容器,本来很想用string!
7.make_shared_ptr 的参数是对象而不是对象指针,如果在类中有shared_ptr可以通过构造函数传入的new指针初始化,
8.ET模式下 read是一次读完后出现EAGAIN ,EWOULDBLOCK说明客户发的全部读了(是对的),而我使用包装成Readn恰好读PACK的大小可能不会执行到这一步。
9.匹配可以使用对象指针队列,匹配成功放在一个pair集合,比赛结束或者用户退出则需要在队列和集合等容器中清除对象指针
str = "SELECT * FROM information_schema.SCHEMATA where SCHEMA_NAME='chess'";
判断是有chess这个数据库,str = "select TABLE_NAME from INFORMATION_SCHEMA.TABLES where TABLE_SCHEMA='chess' and TABLE_NAME='account'";
判断chess库是否有account表。- 刚看了点设计模式,觉得这个是客户端的客户类是需要设置为单例模式的。并且这次的程序代码复用性不强,本想同时给五子棋类设计的判断胜出规则放在了Table类,而五子棋类的父类ChessBase就显的很累赘rule()没用上,之后再想方法完善,可能是因为不知道围棋的规则,没法实践c++继承体系。