java实现自己的通信协议,使用状态模式设计在Java中实现通信协议

Apologies if this is answered elsewhere; couldn't find enough information to convince myself of the best way to do this. I also realize this is a lengthy explanation with no code, but let me know if I should whip up some sample code to help demonstrate what I'm doing.

Basically:

implementing a communication protocol in Java using System.in/out

current approach is implementing a state pattern where a Scanner is instantiated on System.in in the context class

concrete states invoke a context method to read from the Scanner, and subsequently perform actions/transition states appropriately based on the value returned by the Scanner

My original intent for using a state pattern was to simplify the code when parsing sequences like this from System.in (don't ask about the syntax, it's something I have to work with):

COMMAND NAME=X

HEADER

line of header information

CONTENTS

lines of command contents

ENDCONTENTS

ENDCOMMAND

I generally define a concrete state for each type of command I expect to receive. Using the above sequence as an example, I would have a state set that looked something like {WAITING_FOR_COMMAND, COMMAND_RECEIVED, PARSING_HEADER, PARSING_CONTENTS, PARSING_DONE, COMMAND_PROCESSED}. I'd initially be in WAITING_FOR_COMMAND, then when "COMMAND NAME=X" is received I'd transition to COMMAND_RECEIVED, then when "HEADER" came in I'd transition to PARSING_HEADER, etc. This design makes traversing all the edge cases in the protocol easier, and also makes the code easy to update/maintain for when the protocol gets tweaked. Obviously much better than massive switch statements and repetitive boundary checks.

The problem I'm having is that I find myself declaring more and more state variables in the context class as I flesh out my concrete state behaviors, and know this is probably bad since I'm creating very exposed interfaces and very high linkages between the context and concrete state classes. The command sequences in this protocol can be arbitrarily long, and I need to save information imparted by each item in the command sequence until the command sequence is complete.

Using the above command sequence as an example, after "COMMAND ID=X", I want to save the value X for future use after I receive "ENDCOMMAND" and fully process the command. After "HEADER", I want to save the header information for future use after I receive "ENDCOMMAND" for when I actually process the command. So on and so forth. Simply adding commandId and header state variables to the context class works for now, but doesn't seem clean or well encapsulated to me at all.

Does anyone have any high level suggestions on how they'd approach this problem? Is there a better use of a state design pattern for this?

Just to note some ideas I've been playing with:

defining state contexts for each type of command sequence, and invoking the appropriate context upon receiving the relevant command from System.in; this seems almost as messy as having giant switch blocks, and seems to overly convolute the design

designing a full-blown FSM architecture that supports composite FSMs, where each command sequence occupies its own FSM within an overarching FSM; this seems like overkill to me

creating a ProtocolCommand object with various subclasses for each command sequence type; I could pass these into each state when transitioning, and gradually build them up as I go...but this clutters the state interface and forces all states to ingest a parameter that they won't necessarily use

Thanks so much! Sorry this was so verbose, let me know if I can clarify anything.

解决方案

I have used an enum for this style of parsing with one enum for each state. An example is here

http://vanillajava.blogspot.co.uk/2011/06/java-secret-using-enum-as-state-machine.html

interface Context {

ByteBuffer buffer();

State state();

void state(State state);

}

interface State {

/**

* @return true to keep processing, false to read more data.

*/

boolean process(Context context);

}

enum States implements State {

XML {

public boolean process(Context context) {

if (context.buffer().remaining() < 16) return false;

// read header

if(headerComplete)

context.state(States.ROOT);

return true;

}

}, ROOT {

public boolean process(Context context) {

if (context.buffer().remaining() < 8) return false;

// read root tag

if(rootComplete)

context.state(States.IN_ROOT);

return true;

}

}

}

public void process(Context context) {

socket.read(context.buffer());

while(context.state().process(context));

}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值