#include <iostream>
#include ".. estalS_utinity.h"
#include <list>
#include <vector>
#include "stdio.h"
#include <map>
//代理类,可以默认,就可以用对象数组,成员为指针,可以为0.有copy3件套.代理行为,检测0,
//什么时候需要写继承.感觉应该必须满足一个条件.就是需要多态.如果不需要多态.就算是is a,关系.也没有必要非整出一个基类.
//只要继承,就会使用指针来表示多态.只要有指针,就必须用代理类.
//所以只要继承就必须代理.
using namespace std;
class vehicle
{
public:
virtual double weight()=0;
virtual void start()=0;
};
class bike:public vehicle
{
public:
double weight();
void start();
};
class bus:public vehicle
{
public:
double weight();
void start();
};
class car:public vehicle
{
public:
double weight();
void start();
};
double bike::weight()
{
return 200;
}
void bike::start()
{
}
double bus::weight()
{
return 2000;
}
void bus::start()
{
}
double car::weight()
{
return 400;
}
void car::start()
{
}
class pm
{
public:
pm(vehicle*);
vehicle* getP();
~pm();
private:
pm();
pm(const pm&);
pm operator=(const pm&);
vehicle * pveh;
};
pm::pm(vehicle* _p):pveh(_p){}
pm::~pm(){delete pveh;}
vehicle* pm::getP(){return pveh;}
//一,对于单资源(狭义上就是内存,再狭义就是堆内存)的使用和管理.
//1,资源的建立和托管必须是一个步骤.2)托管对象必须保证和资源同生死.
//对于栈内存,.bike mybike1; 对于堆内存.bike * mybike2=new bike();
//第一种,很可靠.
//第二种,需要显示维护内存,和保护指针变量.所以引出一条款(effect c++),用对象管理资源.
//而资源管理对象和资源同生死.就必须保证资源建立和对象建立是原子操作.也是另一条款.
//并且资管,由于资源入对象是原操,那么资管必须负责资源的delete.
//1)资管必须负责资源的delete.
//2)负责delete,也就必须考虑资源copy三函数,构造,赋值,析构.
//3)资管可以没有默认的构造函数,
//4)可以直接用方法提供只读的资源地址,供外部使用
//对于第2条.如果是资源地址copy.资管转化为智能指针类.
//如果是资源copy.提供正确的构造,赋值,析构.
//如果是禁止资源copy,构造,赋值,析构.设置为private.
//如果是资源转移.提供正确的构造,赋值,析构.
//所以最终对于单资源的资源的使用.在c++中有2种比较可靠的方法.
//1)栈内存, bike mybike1;
//2)堆内存,pm mypm(new bike());
//对于多资源的统一使用和管理.
//基本是对于含有继承关系的对象而言.没有继承关系,谈不上统一管理.
//那么必须是管理指针.参考上面分析.必须建立对象.
//那么必须要求资源有默认的构造函数.
void showWeight(vehicle * _p)
{
cout<<_p->weight()<<endl;
}
int main()
{
//地址copy,使用智能指针类.
bike mybike1;
cout<<"**auto p***"<<endl;
showWeight(&mybike1);
//地址copy,使用智能指针类.
cout<<"**copy p***"<<endl;
pm_copyP<bike> mypm(new bike());
pm_copyP<bike> mypm2=mypm;
pm_copyP<bike> mypm3(new bike());
mypm3=mypm;
showWeight(mypm.getP());
showWeight(mypm2.getP());
showWeight(mypm3.getP());
//禁止copy值或地址.使用禁止类.
cout<<"**forbiden***"<<endl;
pm_forbidP<bike> mypm4(new bike());
showWeight(mypm4.getP());
//pm_forbidP<bike> mypm5=mypm4;//禁止复制,赋值.
//value copy,使用value-copy类.
cout<<"**copy value***"<<endl;
pm_copyValue<bike> mypm5(new bike());
pm_copyValue<bike> mypm6=mypm5;
pm_copyValue<bike> mypm7(new bike());
mypm7=mypm5;
showWeight(mypm5.getP());
showWeight(mypm6.getP());
showWeight(mypm7.getP());
//转移资源所有权, 使用transforP类. 这个和其他有不同.使用指针必须先判断,指针是否已经转移,为0了.
cout<<"**transforP***"<<endl;
pm_transforP<bike> mypm8(new bike());
pm_transforP<bike> mypm9=mypm8;
pm_transforP<bike> mypm10(new bike());
mypm10=mypm8;
if(mypm8.getP()!=0)
{
showWeight(mypm8.getP());
}
if(mypm9.getP()!=0)
{
showWeight(mypm9.getP());
}
if(mypm10.getP()!=0)
{
showWeight(mypm10.getP());
}
// vehicle* allCar[100]={0};
//
// bike mybike1;
// bus mybus1;
// car mycar1;
//
// allCar[0]=&mybike1;//这里是函数内,如果是外部参数,那么会有悬指针问题.所以条款,对象管理资源很必要.
// allCar[1]=&mybus1;
// allCar[2]=new car;//这里必须管理内存.
//
//
// for(int i=0;i!=100;++i)
// {
// if(allCar[i]!=0)
// {
// cout<< allCar[i]->weight()<<endl;
// }
// }
return 0;
}
#ifndef LS_UTINITY_H_INCLUDED #define LS_UTINITY_H_INCLUDED #include <iostream> #include <list> #include <vector> using namespace std; //智能指针 template<typename T> class auto_MyP { public: auto_MyP<T>(); auto_MyP<T>(T const* _p); auto_MyP<T>(const auto_MyP&); auto_MyP<T>& operator=(const auto_MyP&); T* getP()const; ~auto_MyP<T>(); void del(); private: int * count_ref; const T* autop; }; template<typename T> auto_MyP<T>::auto_MyP() { autop=0x0; count_ref=new int(1); } template<typename T> auto_MyP<T>::auto_MyP(T const* _p) { cout<<"p con:"<<_p<<endl; autop=_p; count_ref=new int(1); } template<typename T> auto_MyP<T>::auto_MyP(const auto_MyP& _lht) { autop=_lht.autop; ++(*_lht.count_ref); count_ref=_lht.count_ref; } template<typename T> auto_MyP<T>& auto_MyP<T>::operator=(const auto_MyP& _lht) { if(this!=&_lht) { del(); this->autop=_lht.autop; *_lht.count_ref=*_lht.count_ref+1; this->count_ref=_lht.count_ref; } return *this; } template<typename T> auto_MyP<T>::~auto_MyP() { del(); } template<typename T> void auto_MyP<T>:: del() { cout<<"false del:"<<*(this->count_ref)<<". add"<<autop<<endl; *(this->count_ref)=*(this->count_ref)-1;//前后自增加,就是此语句取值是取+1变量,还是把+1给临时变量,取值去取未+1的符号变量. if(*(this->count_ref)==0) { cout<<"del:"<<autop<<endl; //if(autop!=0x0) //{ delete autop; //} } } template<typename T> T* auto_MyP<T>::getP()const { return const_cast<T*>(autop); } //Merge sort template<typename T> list<T> mergeSort(const list<T>& source); template<typename T> list<T> mergeSort(const list<T>& source) { list<T> ret; if(source.size()==1) { ret=source; } else if(source.size()==2) { typename list<T>::const_iterator firstit=source.begin(); T firstvalue=*firstit; typename list<T>::const_iterator secondit=++firstit; T secondvalue=*secondit; if(firstvalue<=secondvalue) { ret=source; } else { ret.push_back(secondvalue); ret.push_back(firstvalue); } } else { unsigned int count_list=source.size(); unsigned int modN= count_list%2; unsigned int subret=count_list/2; typename list<T>::const_iterator it=source.begin(); list<T> leftS; list<T> rightS; for(int i=0;i!=subret+modN;++i) { leftS.push_back(*it); ++it; } for(int i=0;i!=subret;++i) { rightS.push_back(*it); ++it; } leftS=mergeSort(leftS);//lefts 传递const 引用,效率和安全,不会改动.返回对象.lefts被copy赋值函数处理. rightS=mergeSort(rightS); typename list<T>::const_iterator lefttop=leftS.begin(); typename list<T>::const_iterator righttop=rightS.begin(); while(lefttop!=leftS.end() || righttop!=rightS.end()) { // check each top if(*lefttop<=*righttop) { ret.push_back(*lefttop); ++lefttop; } else { ret.push_back(*righttop); ++righttop; } } if(lefttop!=leftS.end()) { //push no process data for(lefttop;lefttop!=leftS.end();++lefttop) { ret.push_back(*lefttop); } } else if(righttop!=rightS.end()) { for(righttop;righttop!=rightS.end();++righttop) { ret.push_back(*righttop); } } return ret; } return ret; } // template<typename T> void quickSort(vector<T>& source, int startIndex, int endIndex) { if(startIndex<endIndex) { int centerIndex=startIndex; for( int i=startIndex+1;i!=endIndex+1;++i) { if(source[i]<source[centerIndex]) { T tempT=source[i]; for( int j=i-1;j!=centerIndex-1;--j) { source[j+1]=source[j]; } source[centerIndex]=tempT; ++centerIndex; } } quickSort(source,startIndex,centerIndex-1); quickSort(source,centerIndex+1,endIndex); } } template<typename T> int centerFind(const vector<T>& source,const T& finder) { int ret=-2; int startIndex=0; int endIndex=source.size()-1; int CenterIndex=startIndex+(endIndex-startIndex)/2; while(ret==-2) { if(CenterIndex==startIndex&&startIndex==endIndex)//1个数 { if(source[CenterIndex]==finder) { ret=CenterIndex; } else { ret=-1; } } else { if(source[CenterIndex]==finder) { ret=CenterIndex; } else if(source[CenterIndex]>finder) { endIndex=CenterIndex-1; CenterIndex=startIndex+(endIndex-startIndex)/2; if(startIndex>endIndex) { ret=-2; } } else { startIndex=CenterIndex+1; CenterIndex=startIndex+(endIndex-startIndex)/2; if(startIndex>endIndex) { ret=-2; } } } } return ret; } template<typename T> class pm_copyP{ public: pm_copyP(T* _p); pm_copyP(const pm_copyP&); pm_copyP& operator=(const pm_copyP&); ~pm_copyP(); T* getP(); private: pm_copyP(); T* myp; int * count_ref; del(); }; template<typename T> pm_copyP<T>::pm_copyP(T* _p):myp(_p),count_ref(new int(1)){} template<typename T> pm_copyP<T>::pm_copyP(const pm_copyP& _pm) { myp=_pm.myp; count_ref=_pm.count_ref; ++(*count_ref); } template<typename T> pm_copyP<T>& pm_copyP<T>::operator=(const pm_copyP& _pm) { if(&_pm!=this) { del(); myp=_pm.myp; count_ref=_pm.count_ref; ++(*count_ref); } return *this; } template<typename T> pm_copyP<T>::~pm_copyP() { del(); } template<typename T> pm_copyP<T>::del() { --(*count_ref); if(*count_ref==0) { delete myp; delete count_ref; } } template<typename T> T* pm_copyP<T>::getP() { return myp; } template<typename T> class pm_forbidP{ public: pm_forbidP(T* _p); ~pm_forbidP(); T* getP(); private: T* myp; pm_forbidP(); pm_forbidP(const pm_forbidP&); pm_forbidP& operator=(const pm_forbidP&); }; template<typename T> pm_forbidP<T>::pm_forbidP(T* _p):myp(_p){} template<typename T> T* pm_forbidP<T>::getP() { return myp; } template<typename T> pm_forbidP<T>::~pm_forbidP() { delete myp; } template<typename T> class pm_copyValue{ public: pm_copyValue(T* _p); pm_copyValue(const pm_copyValue&); pm_copyValue& operator=(const pm_copyValue&); ~pm_copyValue(); T* getP(); private: T* myp; void del(); pm_copyValue(); }; template<typename T> pm_copyValue<T>::pm_copyValue(T* _p):myp(_p){} template<typename T> pm_copyValue<T>::pm_copyValue(const pm_copyValue& _pm):myp(new T(*_pm.myp)){} template<typename T> pm_copyValue<T>& pm_copyValue<T>::operator=(const pm_copyValue& _pm) { if(&_pm!=this) { del(); myp=new T(*_pm.myp); } return *this; } template<typename T> pm_copyValue<T>::~pm_copyValue() { del(); } template<typename T> void pm_copyValue<T>::del() { delete myp; } template<typename T> T* pm_copyValue<T>::getP() { return myp; } template<typename T> class pm_transforP{ public: pm_transforP(T* _p); pm_transforP(pm_transforP&); pm_transforP& operator=(pm_transforP&); ~pm_transforP(); T* getP(); private: T* myp; void del(); pm_transforP(); }; template<typename T> pm_transforP<T>::pm_transforP(T* _p):myp(_p){} template<typename T> pm_transforP<T>::pm_transforP(pm_transforP& _pm):myp(_pm.myp) { _pm.myp=0;//const 怎么可以修改. } template<typename T> pm_transforP<T>& pm_transforP<T>::operator=(pm_transforP& _pm) { if(this!=&_pm) { del(); myp=_pm.myp; _pm.myp=0;//const 怎么可以修改. } return *this; } template<typename T> pm_transforP<T>::~pm_transforP() { del(); } template<typename T> void pm_transforP<T>::del() { if(myp!=0) { delete myp; } } template<typename T> T* pm_transforP<T>::getP() { return myp; } #endif // LS_UTINITY_H_INCLUDED
关于异常:
#include <iostream> #include <stdexcept> using namespace std; //c++,实在经验不足.感觉只能是,使用某些函数,又不想每次都检测是否返回正确.那么抛出错误.程序结束. //感觉还不如返回错误代码呢. int dev(int a,int b); int main() { int result=0; try { result=dev(3,1); } catch(exception &e) { //提示错误,保存关键数据,程序退出 cout<<e.what()<<endl; return -1; } cout<<result<<endl; return 0; } int dev(int a,int b) { if(b==0) { throw runtime_error("b is zero"); } else if(b==1) { throw logic_error("b can not be 1"); } else { return a/b; } return 0; }
关于类的数据成员和参数问题。以及const。
1)类的data member.
如果是内置类型或类的值类型,语义就是局部数据,const语义就是,在类内,一个局部常量.
如果是内置类型或类的指针或引用类型,语义就是局部的指针,指向外部数据,const语义就是,在类内,不可通过此指针修改外部数据.
如果是内置类型或类的智能指针类型.语义就是局部数据,但里面有指针指向外部数据.const语义就是,在类内,不可通过此局部数据中的指针修改外部数据.
(可以完全代替第二种,只是size为8,而第2中size是4(32system)).
如果是内置类型或类的智能指针的指针或引用类型.语义就是很大概率是你想的的太复杂了.请退化为第3种.智能指针就是为了自动释放内存.
再保存它的指针,又把问题解决方案变成了问题本身.餐巾纸的作用就是为了吃饭时,让衣服更干净.为了方便拿东西.又套一个外套,还不如拿掉餐巾纸.
但是构造函数的参数应该使用 智能指针的reference,这个时候智能指针当成一般类处理.智能指针本质就是一个类了.
总结:
值还是智能指针(指针),还是引用.
从数据库讲,
一个字段不是另一个表的key。那么就是值。否则就是引用。如果表不存在这个字读。那么就是用方法返回数据(查询其他表)
const还是非const?
可修改用非const.否则用const.
对于智能指针,指针不可修改用 const shared_ptr<T>,指针所指的数据不可修改用shared_ptr<const T>.
从数据库讲。如果一个字段设置了触发器,字段是只读了。那么类中。一定要是const。
2)类的constructor的参数.
如果参数是内置类型或类的值类型,语义就是会创建一个原数据的副本,压入函数体.const语义就是,此参数的数据不可修改.但可以赋值给const或非const.
如果参数是内置类型或类的指针或引用类型,语义就是引用原数据,压入原数据的指针到函数体.const语义就是此地址的指向不可修改.
如果参数是内置类型或类的智能指针类型.语义就是会创建一个原数据(包含一个指针)的副本,压入函数体.const语义就是,此参数的数据不可修改.也就是里面的地址的指向不可修改.
时钟周期
时钟周期也称为振荡周期,定义为时钟脉冲的倒数(时钟周期就是单片机外接晶振的倒数,例如12M的晶振,它的时钟周期就是1/12us),是计算机中的最基本的、最小的时间单位。
在一个时钟周期内,CPU仅完成一个最基本的动作。时钟脉冲是计算机的基本工作脉冲,控制着计算机的工作节奏。时钟频率越高,工作速度就越快。
8051单片机把一个时钟周期定义为一个节拍(用P表示),二个节拍定义为一个状态周期(用S表示)。
机器周期
计算机中,常把一条指令的执行过程划分为若干个阶段,每一个阶段完成一项工作。每一项工作称为一个基本操作,完成一个基本操作所需要的时间称为机器周期。8051系列单片机的一个机器周期由6个S周期(状态周期)组成。 一个S周期=2个节拍(P),所以8051单片机的一个机器周期=6个状态周期=12个时钟周期。
例如外接24M晶振的单片机,他的一个机器周期=12/24M 秒;
指令周期
执行一条指令所需要的时间,一般由若干个机器周期组成。指令不同,所需的机器周期也不同。
int main(void)
{
char buf[10];
int n = read(STDIN_FILENO, buf, 10);
write(STDOUT_FILENO, buf, n);
return 0;
}
输入字符,回车后。。。。。
少于等于10个ok。大于10个。后续的字符,和回车键都还在标准输出中,会认为用户敲入了命令。
关于开发整体流程。
//对于开发的流程,个人倾向,先建模,后建表.再实际建立class.
//因为先建立表,可以更快理清类之前细节.因为建类的时候需要考虑实际数据的存放问题.
//建立类的时候,发现问题.也可以修改表.
//而建立好类,不满足表,改类就麻烦.
//再次.表的话更直观,可以先不考虑细节.从整体掌握模型的数据流是否正确.
//甚至,类中犯的错误的设计,在表中就不太会出现.如员工,和职务.表明显会有好几个.一个员工表,几个不同职务表.
//而类,可能会设计为一个类.建模错误,会导致表设计不符合表设计范式.
//但是设计表的时候也可以考虑一下类.是否需要多一个表,来表现包含关系.或继承关系.
再一次卡在设计流程上了。
继续卡在无数据库设计上。
有数据库设计,数据存放问题不用考虑。而无数据库,放在那里,用 vector 对象还是指针,总是感觉设计不好。用vector或智能指针。
应该还是基于分析后。关系型数据设计开路(好理解,也很熟悉),数据存放问题的话。去掉表的外键,放入外键所在的表。用vector直接存放对象。,vector自己离开作用域会自动析构。析构会调用成员的析构函数并释放堆空间。完美啊。
可以先省去内部中其他类的集合。从上往下设计下来就好,下级设计好了。再返回上级,使用下级的初始化函数,来修改上级的初始化函数或其它初始化的地方。
这样设计了数据的流向后,再从面向对象的思维,设计行为。来给数据流向取个名字。
对象间的数据存放问题。
1)如果原本数据成员都不多。那么偏向一方(其中有确定数据属于的那方)。
2)用map存储数据。类方法提供对map的真删改,查, 类本身或管理类提供逻辑,调用增删改,特别注意逻辑中含删除的操作。
单个数据直接放栈,如果太大用智能指针。如果是不确定的多个数据或者多个大数据。用vector就好了。甚至单个大数据也可以用vector,vector自己离开作用域会自动析构。析构会调用成员的析构函数并释放堆空间。完美啊。
定义参数值用全局const。但如果是状态返回值或者作为参数可以用enum.这样就可以限定返回的数据范围。但是枚举不能设定数据类型。比如int_8,所以在网络编程需要固定长度的时候又很尴尬。
模型设计的一点想法,
看了下网狐。有个设计,类之间的包含关系 ,不放指针,或智能指针。
直接放一个key.
所以设计的时候,
1.可以先设计一个对象,包含属性和方法。
2.再设计一个管理类,包含一个当前key 的最大小(根据情况,是先进先出,还是先进后出)值。 用int 记录。
一般可以用int ,取int最大值为默认值,表示下次插入的key。插入的时候用这个做key.并·--, 删除的时候,看看要删除的是不是等于 key-1.如果是,++。 所以用map的key,来当前数据库的外键。
好处是避免了指针的坏处。指针可能有移动操作,也比较危险。而用 key,自然的多。终于解决了这个疑问。
封装的一个含义就是类的某个或几个数据是状态数据。他的改变只由行为(方法)来改变。并提供只读的查看。
服务端和客户端同步开发。
客户端的初始化行为放入main中(之后可以由网络模块发送消息,获得消息,并回调这些方法)。
客户端的动作逻辑封装成方法(之后由网络模块发送消息,获得消息,并回调这些方法)
服务端是一个完备的系统,应该是一个可以自检,自运行的系统。客户端只是通过发送消息,改变服务端的自运行的过程中的状态值。
c#
RoomInfo selectroom = rooms.Where(s => s.room_id == (SByte)this.comboBox1.SelectedValue).Single();
where 相当于里面一个bool函数。where里面已经回调了()里面的函数。并根据bool值来决定是否加入结果集合。
c++ get .set 生成器。
List<string> inputcode = new List<string>(); List<string> outputcode = new List<string>(); string className = this.textBox3.Text.Trim(); inputcode = this.textBox1.Text.Split(new string[] {" "}, StringSplitOptions.RemoveEmptyEntries).ToList(); for(int i=0;i<inputcode.Count;++i) { string[] eachline=inputcode[i].Split(new string[] {" ",";"}, StringSplitOptions.RemoveEmptyEntries); if(eachline.Count()==2) { string type=eachline[0]; string name=eachline[1]; this.textBox2.Text+=type+" "+className+"::Get"+name+"()"+System.Environment.NewLine; this.textBox2.Text+="{"+System.Environment.NewLine; this.textBox2.Text += " " + "return " + name + ";" +System.Environment.NewLine; this.textBox2.Text+="}"+System.Environment.NewLine; this.textBox2.Text+="void "+className+"::Set"+name+"("+type+" _"+name+")"+System.Environment.NewLine; this.textBox2.Text+="{"+System.Environment.NewLine; this.textBox2.Text += " " + name + "=_" + name + ";" + System.Environment.NewLine; this.textBox2.Text+="}"+System.Environment.NewLine; this.textBox2.Text=this.textBox2.Text.Replace("std::",""); } }
目的:有时候有些情况比较复杂,写完了代码。也没法确定是否完全正确。画图感觉比较复杂,只能靠测试。这个时候使用状态机分析法。就能比较好。
步骤:先写出初始行为,和输入行为,以及输入行为对应的猜想的动作,通过猜想的动作,对状态的更改,判断状态是否合理,来验证行为是否正确。
每次集合中所有状态和行为一一匹配。有新状态。就保存。
之后每次用新状态和所有行为一一匹配。直到没有新状态为止。
初始状态: r_ok,s_ok,e_in;
输入行为和对应猜想动作()
1)recv_again. r_ok
2)recv_close. r_close,cancel event
3)recv_error. del
4)send_ok. s_ok ,1)close:yes,block:yes=>s_ok 2)close:yes,block:no => s_ok 3) colse:no,block:yes=>s_ok. e_in. 4)close:no,block:no=>s_ok
5)send_block. s_block,mod e_out
6)send_err. del
初始状态: 下和所有输入行为产生的新状态
1:r_ok,s_ok,e_in;
1-1)=>
1-2)=>r_close,s_ok
1-3)=>del
1-4)=>r_ok,s_ok,e_in
1-5)=>r_ok,s_block,e_out
1-6)=>del
状态应该正确。所以猜想行为暂时正确。
在用得到的新状态,和所有行为一一匹配
1:r_close,s_ok
2:r_ok,s_block,e_out
1-1)=>不可能会存在的行为
1-2)=>不可能会存在的行为
1-3)=>不可能会存在的行为
1-4)=>
1-5)=>r_close,s_block, e_out
1-6)=>del
2-1)=>不可能会存在的行为
2-2)=>不可能会存在的行为
2-3)=>不可能会存在的行为
2-4)=>
2-5)=>
2-6)=>del
又得到1种新状态。所有状态是2×2×2.现在只有4种。
在用得到的新状态,和所有行为一一匹配
1:r_close,s_block, e_out
1-1)=>不可能会存在的行为
1-2)=>不可能会存在的行为
1-3)=>不可能会存在的行为
1-4)=>
1-5)=>
1-6)=>del
无任何新状态。估算下是否正确
估算下,还有剩下4种是什么情况。
1:r_ok,s_ok,e_in;
2:r_ok,s_block,e_out
3:r_close,s_ok
4:r_close,s_block, e_out
哦。因为s_ 和e_只能组合成2种。
所以就是4种。
所以我们得到了全部状态。再验证一下猜想行为就好了。
虽然很烦琐,但是可以验证遗漏的情况。
测试epoll的时候,客户端可以线程10个内。但是开多点socket ,100左右。这样简陋的环境。也可以测试高流量,模拟高并发。注意看服务的发送和接受是否相同大小,如果是echo测试。
还要看客户端的接受。是否有重传现象。如果客户端接收的明显比服务端发送的多。
如何测试epoll的代码效率。
可以简单点。客户端开1000个socket.200毫毛休息一次。说明1秒有5000条信息处理。每条信息64B。发送速度就是300/kB.
服务端,每条信息的处理休息1毫秒。说明1秒处理1000条。但是测试还是不准。所以可以调整下。用netstat 命令查看。使得接受数据越来越多为好。说明程序处理慢。
这样就可以开始优化了。单线程可以优化批量发送,批量处理。
多线程就可以开始队列,新线程处理。多线程的一般特征是网路是没有问题的。接受快,发送快。因为单独线程再处理io。但是如果程序差,那么内存会原来越小。因为网络的数据全部拉到内存中去了。但是又处理不过来。