您的位置:首页 > 编程语言 > C语言/C++

states模式在C语言中的实践

2007-11-20 15:58 176 查看
最近开发一个项目的状态机,由于状态比较多,外部事件也比较复杂,用传统的方法状态机相当臃肿,可读性和调试起来比较困难,看过设计模式那本书中有提及states模式,一直没有实践过,这次就在这个项目中试了试,效果那是相当好啊,看来把面向对象坚持到底好处多多啊。
先来说说C中的面向对象,其实和C++类似,主要表现在设计思想上,对业务进行功能划分,分析得到各个独立对象,给各个对象建立行为,封装接口,尽量减少对象间的耦合性。在具体的代码阶段,用函数指针实现继承关系。这次用socket主动连接的状态机来举例说明.
一个简单的主动式socket在运行态划分为三个状态,IDLE状态表示没有进行连接空闲,CONNECTING状态表示正在连接状态,READY状态表示已经建立连接可以通讯。在整个socket通讯期间可能发生的外部事件有CONNCNF连接确认,DISCIND连接断开,DATAIND数据到达,SEND发送数据,CONNREQ连接请求等。下表分别列出在三种状态下各个事件可能的处理行为。

[align=left] [/align]
[align=left]IDLE[/align]
[align=left]CONNECTING[/align]
[align=left]READY[/align]
[align=left]CONNREQ[/align]
[align=left]Do connect request,[/align]
[align=left]states change to CONNECTING[/align]
[align=left]Nothing[/align]
[align=left]Nothing[/align]
[align=left]CONNCNF[/align]
[align=left]Nothing[/align]
[align=left]Socket ready, states change to READY[/align]
[align=left]Nothing[/align]
[align=left]DISCIND[/align]
[align=left]Nothing[/align]
[align=left]Connect failed, states change to IDLE[/align]
[align=left]Connection lost, states change to IDLE[/align]
[align=left]DATAIND[/align]
[align=left]Nothing[/align]
[align=left]Nothing[/align]
[align=left]Data coming[/align]
[align=left]SEND[/align]
[align=left]Nothing[/align]
[align=left]Nothing[/align]
[align=left]Send data[/align]
States模式主要的特点是将socket各个状态升级为一个对象,它不仅仅是一个状态,它还封装了在该状态下,socket可能的行为。
首先定义一个states基类,其包含所有状态下socket可能的行为:

struct SockStates {
void *implementer; // 用来指向states实例的实现者
s32 (*connReq)(SockStates* _me, void* dstAddr, int addrLen);
s32 (*connCnf)(SockStates* _me);
s32 (*discInd)(SockStates* _me, int cause);
s32 (*dataInd)(SockStates* _me, void* data, int dataLen);
s32 (*writeAble)(SockStates* _me);
s32 (*send)(SockStates* _me, void* data, int dataLen);
void (*destroy)(SockStates* _me);
} ;

在Socket对象中使用SockStates对象来表示特定的状态

struct Socket ...{
SockStates* states;
// …………………
}

当socket发生外部事件的时候,直接调用states中的行为完成处理,socket对象实际上不关心到底是在什么状态下怎么处理这些事件,而都交给states的子类来实现。socket本身只需要一个提供一个改变自身状态的接口。

void Socket_changeStates(Socket * me, SockStates * states)
{
// 删除原来的状态对象
if(me->states)
me->states->destroy(me->states);
// 改变为新的状态对象
me->states = states;
}
// 外部事件发生时调用的接口
void Socket_connReq(Socket* me, void* dstAddr, int addrLen)
{
// 如果当前状态下有对connReq的处理则调用,没有则什么对不做,或者报错
If (me->states && me-> me->states->connReq)
me->states->connReq(me->states, dstAddr, addrLen);
}

其它操作(connCnf, discInd, dataInd, writeable, send)与connReq同样形式封装。

然后分别实现具体的状态对象:

// IDLE状态对象
typedef struct SocketIdleStates ...{
SockStates states;
Socket* sock;
// …………………………
} SocketIdleStates;

// Idle 状态下connReq的处理
void SocketIdleStates_connReq(SockStates * _me, void* dstAddr, int addrLen)
{
SocketIdleStates* me = (SocketIdleStates*)_me->implementer;

// 调用接口完成连接请求

// 切换socket状态到CONNECTING
Socket_changeStates(me->sock, SocketConnectingStates_create(me->sock));
}

void SocketIdleStates_destroy(SockStates* _me)
{
SocketIdleStates * me = (SocketIdleStates*)_me->implementer;
free (me);
}

SockStates * SocketIdleStates_create(Socket * usr)
{
SocketIdleStates * me;

me = (SocketIdleStates*)malloc(sizeof(SocketIdleStates));
assert(me);
me->states.implementer = me;
me->states.destroy = SocketIdleStates_destroy;
me->states.connReq = SocketIdleStates_connReq;
me->sock = usr;

return &me->states;
}

// CONNECTING状态对象
typedef struct SocketConnectingStates ...{
SockStates states;
Socket* sock;
// …………………………
} SocketIdleStates;

// Connecting 状态下connCnf的处理
void SocketConnectingStates_connCnf(SockStates * _me)
{
SocketConnectingStates* me = (SocketConnectingStates*)_me->implementer;

// 调用接口完成连接确认

// 切换socket状态到READY
Socket_changeStates(me->sock, SocketReadyStates_create(me->sock));
}

// Connecting 状态下discInd的处理
void SocketConnectingStates_discInd(SockStates * _me, int cause)
{
SocketConnectingStates* me = (SocketConnectingStates*)_me->implementer;

// 调用接口完成断开连接操作

// 切换socket状态到IDLE
Socket_changeStates(me->sock, SocketIdleStates_create(me->sock));
}

void SocketConnectingStates_destroy(SockStates* _me)
{
SocketConnectingStates * me = (SocketConnectingStates *)_me->implementer;
free (me);
}

SockStates * SocketConnectingStates_create(Socket * usr)
{
SocketConnectingStates * me;

me = (SocketConnectingStates *)malloc(sizeof(SocketConnectingStates));
assert(me);
me->states.implementer = me;
me->states.destroy = SocketConnectingStates_destroy;
me->states.connCnf = SocketConnectingStates_connCnf;
me->states.discInd = SocketConnectingStates_discInd;
me->sock = usr;

return &me->states;
}

// READY状态对象
typedef struct SocketReadyStates ...{
SockStates states;
Socket* sock;
// …………………………
} SocketReadyStates;

// ready状态下send的处理
void SocketReadyStates_send(SockStates * _me, void* data, int dataLen)
{
SocketReadyStates * me = (SocketReadyStates *)_me->implementer;

// 调用接口发送数据
}

// ready状态下dataInd的处理
void SocketReadyStates_dataInd(SockStates * _me, void* data, int dataLen)
{
SocketReadyStates * me = (SocketReadyStates *)_me->implementer;

// 调用接口处理收到的数据
}

// ready状态下discInd的处理
void SocketReadyStates_discInd(SockStates * _me, int cause)
{
SocketReadyStates * me = (SocketReadyStates *)_me->implementer;

// 调用接口完成断开连接操作

// 切换socket状态到IDLE
Socket_changeStates(me->sock, SocketIdleStates_create(me->sock));
}

void SocketReadyStates_destroy(SockStates* _me)
{
SocketReadyStates * me = (SocketReadyStates *)_me->implementer;
free (me);
}

SockStates * SocketReadyStates_create(Socket * usr)
{
SocketReadyStates * me;

me = (SocketReadyStates *)malloc(sizeof(SocketReadyStates));
assert(me);
me->states.implementer = me;
me->states.destroy = SocketReadyStates_destroy;
me->states.send = SocketReadyStates_send;
me->states.dataInd = SocketReadyStates_dataInd;
me->states.discInd = SocketReadyStates_discInd;
me->sock = usr;

return &me->states;
}

这样整个socket的行为被各个状态子类瓜分了,切换和操作都在各个子类去完成,socket只负责向外部提供接口,虽然看起来比较复杂,但当状态很多,外部事件很多的时候,逻辑相当清楚,扩展起来需要添加减少状态也相当的方便,不会影响其他状态下的行为。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: