深入理解Apache_Mina

深入理解Apache_Mina
深入理解Apache_Mina

Mina状态机介绍

(Introduction to mina-statemachine)

如果你使用Mina开发一个复杂的网络应用时,你可能在某些地方会遇到那个古老而又好用的状态模式,来使用这个模式解决你的复杂应用。然而,在你做这个决定之前,你或许想检出Mina的状态机的代码,它会根据当前对象的状态来返回对接收到的简短的数据的处理信息。

注意:现在正式发布Mina的状态机。因此你要自己在Mina的SVN服务器上检出该代码,并自己编译,请参考开发指南,来获取更多的关于检出和编译Mina源码的信息。Mina的状态机可以和所有已经发布的版本Mina配合使用(1.0.x,1.1.x和当前发布的版本)。

一个简单的例子

让我们使用一个简单的例子来展示一下Mina的状态机是如何工作的。下面的图片展示了一个录音机的状态机。其中的椭圆是状态,箭头表示事务。每个事务都有一个事件的名字来标记该事务。

初始化时,录音机的状态是空的。当磁带放如录音机的时候,加载的事件被触发,录音机进入到加载状态。在加载的状态下,退出的事件会使录音机进入到空的状态,播放的事件会使加载的状态进入到播放状态。等等......我想你可以推断后后面的结果:)

现在让我们写一些代码。外部(录音机中使用该代码的地方)只能看到录音机的接口:

----------------------START----------------------

public interface TapeDeck{

void load(String nameOfTape);

void eject();

void start();

void pause();

void stop();

}

-----------------------END------------------------

下面我们开始编写真正执行的代码,这些代码在一个事务被触发时,会在状态机中执行。首先我们定义一个状态。这些状态都使用字符串常量来定义,并且使用@state标记来声明。

----------------------START----------------------

public class TapeDeckHandl e r{

@State public static final String EMPTY="Empty";

@State public static final String LOADED="Loaded";

@State public static final String PLAYING="Playing";

@State public static final String PAUSED="Paused";

}

-----------------------END------------------------

现在我们已经定义了录音机中的所有状态,我们可以根据每个事务来创建相应的代码。每个事务都和一个TapeDeckHandl e r的方法对应。每个事务的方法都使用@Transtrati o n标签来声明,这个标签定义了事件的ID,该ID会触发事务的执行。事务开始时的状态使用start,事务结束使用next,事务正在运行使用on。

----------------------START----------------------

public class TapeDeckHandl e r{

@State public static final String EMPTY="Empty";

@State public static final String LOADED="Loaded";

@State public static final String PLAYING="Playing";

@State public static final String PAUSED="Paused";

@Transition(on="load",in=EMPTY,next=LOADED)

public void loadTape(String nameOfTape){

System.out.print ln("Tape'"+nameOfTape+"'loaded");

}

@Transitions({

@Transition(on="play",in=LOADED,next=PLAYING),

@Transition(on="play",in=PAUSED,next=PLAYING)

})

public void playTape(){

System.out.print ln("Playing tape");

}

@Transition(on="pause",in=PLAYING,next=PAUSED)

public void pauseTape(){

System.out.print ln("Tape paused");

}

@Transition(on="stop",in=PLAYING,next=LOADED)

public void stopTape(){

System.out.print ln("Tape stopped");

}

@Transition(on="eject",in=LOADED,next=EMPTY)

public void ejectTape(){

System.out.print ln("Tape ejected");

}

}

-----------------------END------------------------

请注意,TapeDeckHandler类没有实现TapeDeck,呵呵,这是故意的。

现在让我们亲密接触一下这个代码。在loadTape方法上的@Transition标签:

----------------------START----------------------

@Transition(on="load",in=EMPTY,next=LOADED)

public void loadTape(String nameOfTape){}

-----------------------END-----------------------

指定了这个状态后,当录音机处于空状态时,磁带装载事件启动后会触发loadTape方法,并且录音机状态将会变换到Loaded状态。@Transition标签中关于pauseTape,stopTape,ejectTape的方法就不需要在多介绍了。关于playTape的标签和其他的标签看起来不太一样。从上面的图中我们可以知道,当录音机的状态在Loaded或者Paused 时,play事件都会播放磁带。当多个事务同时条用同一个方法时,@Transition标签需要按下面的方法使用:

----------------------START----------------------

@Transitions({

@Transition(on="play",in=LOADED,next=PLAYING),

@Transition(on="play",in=PAUSED,next=PLAYING)

})

public void playTape(){}

-----------------------END-----------------------

@Transition标签清晰的列出了声明的方法被多个事务调用的情况。

######################################################要点:更多关于@Transition标签的参数

(1)如果你省略了on参数,系统会将该值默认为“*”,这样任何事件都可以触发该方法。

(2)如果你省略了next参数,系统会将默认值改为“_self_”,这个是和当前的状态相关的,

如果你要实现一个循环的事务,你所需要做的就是省略状态机中的next参数。

(3)weight参数用于定义事务的查询顺序,一般的状态的事务是根据weight的值

按升序排列的,weight默认的是0.

######################################################现在最后一步就是使用声明类创建一个状态机的对象,并且使用这个状态机的实例创建一个代理对象,该代理对象实现了TapeDeck接口:

----------------------START----------------------

public static void main(String[]args){

//创建录音机事件的句柄

TapeDeckHandler handler=new TapeDeckHandler();

//创建录音机的状态机

StateMachine sm= StateMachineFactory.getInstance(Transition.class).create(TapeDeckHandler.EMPTY, handler);

//使用上面的状态机,通过一个代理创建一个TapeDeck的实例

TapeDeck deck=new StateMachineProxyBuilder().create(TapeDeck.class,sm);

//加载磁带

deck.load("The Knife-Silent Shout");

//播放

deck.pl a y();

//暂停

deck.pause();

//播放

deck.pl a y();

//停止

deck.stop();

//退出

deck.eject();

}

-----------------------END-----------------------

这一行

----------------------START----------------------

TapeDeckHandler handler=new TapeDeckHandler();

StateMachine sm= StateMachineFactory.getInstance(Transition.class).create(TapeDeckHandler.EMPTY, handler);

-----------------------END-----------------------

使用TapeDeckHandl e r创建一个状态机的实例。StateMachineFactory.getInstance(...)调用的方法中使用的Transition.class是通知工厂我们使用@Transition标签创建一个状态机。我们指定了状态机开始时状态是空的。一个状态机是一个基本的指示图。状态对象和图中的节点对应,事务对象和箭头指向的方向对应。我们在TapeDeckHandl e r中使用的每一个@Transition标签都和一个事务的实例对应。

######################################################要点:那么,@Transition和Transition有什么不同吗?

@Transition是你用来标记当事务在状态之间变化时应该使用那个方法。在后台处理中,

Mina的状态机会为MethodTransition中每一个事务标签创建一个事务的实例。MethodTransition

实现了Transition接口。作为一个Mina状态机的使用者,你不用直接使用Transition或者

MethodTransition类型的对象。

######################################################录音机TapeDeck的实例是通过调用StateMachineProxyBuilder来创建的:

----------------------START----------------------

TapeDeck deck=new StateMachineProxyBuilder().create(TapeDeck.class,sm);

-----------------------END-----------------------

StateMachineProxyBuilder.create()使用的接口需要由代理的对象来实现,状态机的实例将接收由代理产生的事件所触发的方法。

当代码执行时,输出的结果如下:

----------------------START----------------------

Tape'The Knife-Silent Shout'loaded

Playing tape

Tape paused

Playing tape

Tape stopped

Tape ejected

-----------------------END-----------------------

#####################################################要点:这和Mina有什么关系?

或许你已经注意到,在这个例子中没有对Mina进行任何配置。但是不要着急。

稍后我们将会看到如何为Mina的IoHandler接口创建一个状态机。

######################################################

它是怎样工作的?

让我们走马观花的看看当代理调用一个方法的时候发生了什么。

查看一个StateContext(状态的上下文)对象

状态上下文之所以重要是因为它保存了当前的状态。代理调用一个方法时,状态上下文

会通知StateContextLookup实例去方法的参数中获取一个状态的上下文。一般情况下,StateContextLookup的实现将会循环方法中的参数,并查找一个指定类型的对象,并且

使用这个对象反转出一个上下文对象。如果没有声明一个状态上下文,StateContextLookup 将会创一个,并将其存放到对象中。

当代理Mina的IoHandler接口时,我们将使用IoSessoinStateContextLookup实例,该实例用来查询一个IoSession中的方法参数。它将会使用IoSession的属性值为每一个Mina 的session来存放一个独立的状态上下文的实例。这中方式下,同样的状态机可以让所有的Mina的会话使用,而不会使每个会话彼此产生影响。

######################################################要点:在上面的例子中,当我们使用StateMachineProxyBuilder创建一个代理时,我们

一直没有我们一直没有配置StateContex tLookup使用哪种实现。如果没有配置,系统会

使用SingletonStateContextLookup。SingletonStateContextLookup总是不理会方法中

传递给它的参数,它一直返回一个相同的状态上下文。很明显,这中方式在多个客户端

并发的情况下使用同一个同一个状态机是没有意义的。这种情况下的配置会在后面的关于

IoHandler的代理配置时进行说明。

######################################################将方法请求反转成一个事件对象所有在代理对象上的方法请求都会有代理对象转换成事件对象。一个事件有一个ID或者0个或多个参数。事件的ID和方法的名字相当,事件的参数和方法的参数相当。调用方法deck.load("The Knife-Silent Shout")相当于事件{id= "load",arguments=["The Knife-Silent Shout"]}.事件对象中包含一个状态上下文的引用,该状态上下文是当前查找到的。

触发状态机

一旦事件对象被创建,代理会调用StateMachine.handle(Event).方法。StateMachine.handle(Event)遍历事务对象中当前的状态,来查找能够接收当前事件的事务的实例。这个过程会在事务的实例找到后停止。这个查询的顺序是由事务的重量值来决定的

(重量值一般在@Transition 标签中指定)。

执行事务

最后一部就是在Transition 中调用匹配事件对象的Transition.execute(Event)方法。当事件已经执行,这个状态机将更新当前的状态,更新后的值是你在事务中定义的后面的状态。######################################################要点:事务是一个接口。每次你使用@Transition 标签时,MethodTransition 对象将会被创建。

######################################################

MethodTransition(MethodTransition(方法事务方法事务方法事务)

)MethodTransition 非常重要,它还需要一些补充说明。如果事件ID 和@Transition 标签中的on 参数匹配,事件的参数和@Transition 中的参数匹配,那么MethodTransition 和这个事件匹配。

所以如果事件看起来像{id ="foo",arguments =[a,b,c]},那么下面的方法:

----------------------START----------------------

@Transition(on ="foo")

public void someMethod(One one,Two two,Three three){...}

-----------------------END-----------------------

只和这个事件匹配((a instanceof One &&b instanceof Two &&c instanceof Three)==true).。当匹配时,这个方法将会被与其匹配的事件使用绑定的参数调用。

######################################################要点:Integer,Double,Float,等也和他们的基本类型int,double,float,等匹配。

######################################################因此,上面的状态是一个子集,需要和下面的方法匹配:

----------------------START----------------------

@Transition(on ="foo")

public void someMethod(Two two){...}

-----------------------END-----------------------

上面的方法和((a instanceof Two ||b instanceof Two ||c instanceof Two)==true)是等价的。在这种情况下,第一个被匹配的事件的参数将会和该方法绑定,在它被调用的时候。一个方法如果没有参数,在其事件的ID 匹配时,仍然会被调用:

----------------------START----------------------

@Transition(on ="foo")

public void someMethod(){...}

-----------------------END-----------------------

这样做让事件的处理变得有点复杂,开始的两个方法的参数和事件的类及状态的上下文接口相匹配。这意味着:

----------------------START----------------------

@Transition(on ="foo")

public void someMethod(Event event,StateContext context,One one,Two two,Three three){...}

@Transition(on="foo")

public void someMethod(Event event,One one,Two two,Three three){...}

@Transition(on="foo")

public void someMethod(StateContext context,One one,Two two,Three three){...}

-----------------------END-----------------------

上面的方法和事件{id="foo",arguments=[a,b,c]}if((a instanceof One&&b instanceof Two&&c instanceof Three)==true)是匹配的。当前的事件对象和事件的方法绑定,当前的状态上下文和该方法被调用时的上下文绑定。

在此之前一个事件的参数的集合将会被使用。当然,一个指定的状态上下文的实现将会被指定,以用来替代通用的上下文接口。

----------------------START----------------------

@Transition(on="foo")

public void someMethod(MyStateContext context,Two two){...}

-----------------------END-----------------------

######################################################要点:方法中参数的顺序很重要。若方法需要访问当前的事件,它必须被配置为第一个

方法参数。当事件为第一个参数的时候,状态上下问不能配置为第二个参数,它也不能

配置为第一个方法的参数。事件的参数也要按正确的顺序进行匹配。方法的事务不会在

查找匹配事件方法的时候重新排序。

######################################################到现在如果你已经掌握了上面的内容,恭喜你!我知道上面的内容会有点难以消化。希望下面的例子能让你对上面的内容有更清晰的了解。注意这个事件Event{id= "messageReceived",arguments=[ArrayList a=[...],Integer b=1024]}。下面的方法将和这个事件是等价的:

----------------------START----------------------

//All method arguments matches all event arguments directly

@Transition(on="messageReceived")

public void messageRecei v ed(ArrayList l,Integer i){...}

//Matches since((a instanceof Li s t&&b instanceof Number)==true)

@Transition(on="messageReceived")

public void messageRecei v ed(Li s t l,Number n){...}

//Matches since((b instanceof Number)==true)

@Transition(on="messageReceived")

public void messageRecei v ed(Number n){...}

//Methods with no arguments always matches

@Transition(on="messageReceived")

public void messageRecei v ed(){...}

//Methods only interested in the current Event or StateContext always matches

@Transition(on="messageReceived")

public void messageRecei v ed(StateContext context){...}

//Matches since((a instanceof Collect ion)==true)

@Transition(on="messageReceived")

public void messageRecei v ed(Event event,Collect ion c){...}

-----------------------END-----------------------

但是下面的方法不会和这个事件相匹配:

----------------------START----------------------

//Incorrect ordering

@Transition(on="messageReceived")

public void messageRecei v ed(Integer i,Li s t l){...}

//((a instanceof LinkedList)==false)

@Transition(on="messageReceived")

public void messageRecei v ed(LinkedList l,Number n){...}

//Event must be first argument

@Transition(on="messageReceived")

public void messageRecei v ed(ArrayList l,Event event){...}

//StateContext must be second argument if Event is used

@Transition(on="messageReceived")

public void messageRecei v ed(Event event,ArrayList l,StateContext context){...}

//Event must come before StateContext

@Transition(on="messageReceived")

public void messageRecei v ed(StateContext context,Event event){...}

-----------------------END-----------------------

状态继承

状态的实例将会有一个父类的状态。如果StateMachine.handle(Event)的方法不能找到一个事务和当前的事件在当前的状态中匹配,它将会寻找父类中的装。如果仍然没有找到,那么事务将会自动寻找父类的父类,知道找到为止。

这个特性很有用,当你想为所有的状态添加一些通用的代码时,不需要为每一个状态的方法来声明事务。这里你可以创建一个类的继承体系,使用下面的方法即可:

----------------------START----------------------

@State public static final String A="A";

@State(A)public static final String B="A->B";

@State(A)public static final String C="A->C";

@State(B)public static final String D="A->B->D";

@State(C)public static final String E="A->C->E";

-----------------------END-----------------------

使用状态继承来处理错误信息

让我们回到录音机的例子。如果录音机里没有磁带,当你调用deck.pl a y()方法时将会怎样?让我们试试:

示例代码:

----------------------START----------------------

public static void main(String[]args){

...

deck.load("The Knife-Silent Shout");

deck.pl a y();

deck.pause();

deck.pl a y();

deck.stop();

deck.eject();

deck.pl a y();

}

-----------------------END-----------------------

运行结果:

----------------------START----------------------

...

Tape stopped

Tape ejected

Exception in thread"main"o.a.m.sm.event.UnhandledEventException:

Unhandled event:org.apache.mina.statemachine.event.Event@15eb0a9[id=play,...] at org.apache.mi n a.statemachine.StateMachine.handl e(StateMachine.java:285)

at

org.apache.mina.statemachine.StateMachine.processEvents(StateMachine.java:142) ...

-----------------------END-----------------------

哦,我们得到了一个无法处理的异常UnhandledEvent Exception,这是因为在录音机的空状态时,没有事务来处理播放的状态。我们将添加一个指定的事务来处理所有不能匹配的事件。----------------------START----------------------

@Transitions({

@Transition(on="*",in=EMPTY,weight=100),

@Transition(on="*",in=LOADED,weight=100),

@Transition(on="*",in=PLAYING,weight=100),

@Transition(on="*",in=PAUSED,weight=100)

})

public void error(Event event){

System.out.print ln("Cannot'"+event.getId()+"'at this time");

}

-----------------------END-----------------------

现在当你运行上面的main()方法时,你将不会再得到一个异常,输出如下:

----------------------START----------------------

...

Tape stopped

Tape ejected

Cannot'play'at this time.

-----------------------END-----------------------

现在这些看起来运行的都很好,是吗?但是如果们有30个状态而不是4个,那该怎么办?那么我们需要在上面的错误方法处理中配置30个事务的声明。这样不好。让我们用状态继承来解决:

----------------------START----------------------

public static class TapeDeckHandl e r{

@State public static final String ROOT="Root";

@State(ROOT)public static final String EMPTY="Empty";

@State(ROOT)public static final String LOADED="Loaded";

@State(ROOT)public static final String PLAYING="Playing";

@State(ROOT)public static final String PAUSED="Paused";

...

@Transition(on="*",in=ROOT)

public void error(Event event){

System.out.print ln("Cannot'"+event.getId()+"'at this time");

}

}

-----------------------END-----------------------

这个运行的结果和上面的是一样的,但是它比要每个方法都配置声明要简单的多。

IoHandler配合使用

的状态机和IoHandler

Mina的状态机和

现在我们将上面的录音机程序改造成一个TCP服务器,并扩展一些方法。服务器将接收一些命令类似于:load,play,stop等等。服务器响应的信息将会是+或者是-。协议是基于Mina自身提供的一个文本协议,所有的命令和响应编码都是基于UTF-8。这里有一个简单的会话示例:

----------------------START----------------------

telnet localhost12345

S:+Greetings from your tape deck!

C:list

S:+(1:"The Knife-Silent Shout",2:"Kings of conveni e nce-Riot on an empty street") C:load1

S:+"The Knife-Silent Shout"loaded

C:play

S:+Playing"The Knife-Silent Shout"

C:pause

S:+"The Knife-Silent Shout"paused

C:play

S:+Playing"The Knife-Silent Shout"

C:info

S:+Tape deck is playing.Current tape:"The Knife-Silent Shout"

C:eject

S:-Cannot eject while playing

C:stop

S:+"The Knife-Silent Shout"stopped

C:eject

S:+"The Knife-Silent Shout"ejected

C:qui t

S:+Bye!Please come back!

-----------------------END-----------------------

该程序完整的代码在org.apache.mina.exampl e.tapedeck包中,这个可以通过检出Mina 源码的SVN库中的mi n a-exampl e来得到。代码使用Mina的ProtocolCodecFilter来编解码传输的二进数据对象。这里只是为每个状态对服务器的请求实现了一个简单的编解码器。在此不在对Mina中编解码的实现做过多的讲解。

现在我们看一下这个服务器是如何工作的。这里面一个重要的类就是实现了录音机程序的TapeDeckServer类。这里我们要做的第一件事情就是去定义这些状态:

----------------------START----------------------

@State public static final String ROOT="Root";

@State(ROOT)public static final String EMPTY="Empty";

@State(ROOT)public static final String LOADED="Loaded";

@State(ROOT)public static final String PLAYING="Playing";

@State(ROOT)public static final String PAUSED="Paused";

-----------------------END-----------------------

在这里没有什么新增的内容。然而,但是处理这些事件的方法看起来将会不一样。让我们看看playTape的方法。

----------------------START----------------------

@IoHandl e rTransitions({

@IoHandl e rTransition(on=MESSAGE_RECEIVED,in=LOADED,next=PLAYING), @IoHandl e rTransition(on=MESSAGE_RECEIVED,in=PAUSED,next=PLAYING) })

public void playTape(TapeDeckContext context,IoSession session,PlayCommand cmd){ session.write("+Playing\""+context.tapeName+"\"");

}

-----------------------END-----------------------

这里没有使用通用的@Transition和@Transitions的事务声明,而是使用了Mina指定的@IoHandl e rTransition和@IoHandl e rTransitions声明。当为Mina的IoHandler创建一个状态机时,它会选择让你使用Java enum(枚举)类型来替代我们上面使用的字符串类型。这个在Mina的IoFilter中也是一样的。

我们现在使用MESSAGE_RECEIVED来替代"play"来作为事件的名字(on是@IoHandl e rTransition的一个属性)。这个

常量是在org.apache.mina.statemachine.event.IoHandl e rEvents中定义的,它的值是"messageReceived",这个和Mina的IoHandler中的messageRecei v ed()方法是一致的。谢谢Java5中的静态导入,我们在使用该变量的时候就不用再通过类的名字来调用该常量,

我们只需要按下面的方法导入该类:

----------------------START----------------------

import static org.apache.mina.statemachine.event.IoHandl e rEvents.*;

-----------------------END-----------------------

这样状态内容就被导入了。

另外一个要改变的内容是我们自定了一个StateContext状态上下文的实现--TapeDeckContext。这个类主要是用于返回当前录音机的状态的名字。

----------------------START----------------------

static class TapeDeckContext extends AbstractStateContext{

public String tapeName;

}

-----------------------END-----------------------

######################################################要点:为什么不把状态的名字保存到IoSession中?

我们可以将录音机状态的名字保存到IoSession中,但是使用一个自定义的StateContex t

来保存这个状态将会使这个类型更加安全。

######################################################最后需要注意的事情是playTape()方法使用了PlayCommand命令来作为它的最后的一个参数。最后一个参数和IoHandler's messageRecei v ed(IoSession session,Object message)方法匹配。这意味着只有在客户端发送的信息被编码成playCommand命令时,该方法才会被调用。

在录音机开始进行播放前,它要做的事情就是要装载磁带。当装载的命令从客户端发送过来时,服务器提供的磁带的数字代号将会从磁带列表中将可用的磁带的名字取出:

----------------------START----------------------

@IoHandl e rTransition(on=MESSAGE_RECEIVED,in=EMPTY,next=LOADED)

public void loadTape(TapeDeckContext context,IoSession session,LoadCommand cmd){ if(cmd.getTapeNumber()<1||cmd.getTapeNumber()>tapes.length){ session.write("-Unknown tape number:"+cmd.getTapeNumber());

StateControl.breakAndGotoNext(EMPTY);

}else{

context.tapeName=tapes[cmd.getTapeNumber()-1];

session.write("+\""+context.tapeName+"\"loaded");

}

}

-----------------------END-----------------------

这段代码使用了StateControl状态控制器来重写了下一个状态。如果用户指定了一个非法的数字,我们将不会将加载状态删除,而是使用一个空状态来代替。代码如下所示:

----------------------START----------------------

StateControl.breakAndGotoNext(EMPTY);

-----------------------END-----------------------

状态控制器将会在后面的章节中详细的讲述。

connect()方法将会在Mina开启一个会话并调用sessionOpened()方法时触发。

----------------------START----------------------

@IoHandl e rTransition(on=SESSION_OPENED,in=EMPTY)

public void connect(IoSession session){

session.write("+Greetings from your tape deck!");

}

-----------------------END-----------------------

它所做的工作就是向客户端发送欢迎的信息。状态机将会保持空的状态。

pauseTape(),stopTape()和ejectTape()方法和playTape()很相似。这里不再进行过多的讲述。listTapes(),info()和qui t()方法也很容易理,也不再进行过多的讲解。请注意后面的三个方法是在根状态下使用的。这意味着listTapes(),info()和qui t()可以在任何状态中使用。

现在让我们看一下错误处理。error()将会在客户端发送一个非法的操作时触发:

----------------------START----------------------

@IoHandl e rTransition(on=MESSAGE_RECEIVED,in=ROOT,weight=10)

public void error(Event event,StateContext context,IoSession session,Command cmd){ session.write("-Cannot"+cmd.getName()+"while"

+context.getCurrentState().getId().toLowerCase());

}

-----------------------END-----------------------

error()已经被指定了一个高于listTapes(),info()和qui t()的重量值来阻止客户端调用上面的方法。注意error()方法是怎样使用状态上下文来保存当前状态的ID的。字符串常量值由@State annotati o n(Empty,Loaded etc)声明。这个将会由Mina的状态机当成状态的ID 来使用。

commandSyntaxError()方法将会在ProtocolDecoder抛出CommandSyntaxException异常时被调用。它将会简单的输出

客户端发送的信息不能解码为一个状态命令。

exceptionCaught()方法将会在任何异常发生时调用,除了CommandSyntaxException异常(这个异常有一个较高的重量值)。

它将会立刻关闭会话。

最后一个@IoHandl e rTransition的方法是unhandl e dEvent(),它将会在@IoHandl e rTransition中的方法没有事件匹配时调用。

我们需要这个方法是因为我们没有@IoHandl e rTransition的方法来处理所有可能的事件(例如:我们没有处理messageSent(Event)

方法)。没有这个方法,Mina的状态机将会在执行一个事件的时候抛出一个异常。

最后一点我们要看的是那个类创建了IoHandler的代理,main()方法也在其中:

----------------------START----------------------

pri v ate static IoHandler createIoHandler(){

StateMachine sm= StateMachineFactory.getInstance(IoHandl e rTransiti o n.class).create(EMPTY,new

TapeDeckServer());

return new StateMachineProxyBui l der().setStateContextLookup(

new IoSessionStateContextLookup(new StateContextFactory(){

public StateContext create(){

return new TapeDeckContext();

}

})).create(IoHandler.class,sm);

}

//This code will work with MINA1.0/1.1:

public static void main(String[]args)throws Exception{

SocketAcceptor acceptor=new SocketAcceptor();

SocketAcceptorConfig confi g=new SocketAcceptorConfig();

confi g.setReuseAddress(true);

ProtocolCodecFilter pcf=new ProtocolCodecFilter(

new TextLineEncoder(),new CommandDecoder());

confi g.getFilterChain().addLast("codec",pcf);

acceptor.bind(new InetSocketAddress(12345),createIoHandler(),confi g);

}

//This code will work with MINA trunk:

public static void main(String[]args)throws Exception{

SocketAcceptor acceptor=new NioSocketAcceptor();

acceptor.setReuseAddress(true);

ProtocolCodecFilter pcf=new ProtocolCodecFilter(

new TextLineEncoder(),new CommandDecoder());

acceptor.getFilterChain().addLast("codec",pcf);

acceptor.setHandl e r(createIoHandler());

acceptor.setLocalAddress(new InetSocketAddress(PORT));

acceptor.bind();

}

-----------------------END-----------------------

createIoHandler()方法创建了一个状态机,这个和我们之前所做的相似除了我们指定一个IoHandlerTransition.clas类来代替Transition.class在StateMachineFactory.getInstance(...)方法中。这是我们在使用@IoHandl e rTransition声明的时候必须要做的。当然这时我们使用了一个IoSessionStateContextLookup和一个自定义的StateContextFactory类,这个在我们创建一个IoHandler代理时被使用到了。如果我们没有使用IoSessionStateContextLookup,那么所有的客户端将会使用同一个状态机,这是我们不希望看到的。

main()方法创建了SocketAcceptor实例,并且绑定了一个ProtocolCodecFilter,它用于编解码命令对象。最后它绑定了12345端口和IoHandler的实例。这个IoHandler实例是由createIoHandler()方法创建的。

深入理解Apache Mina----Mina的几个类

最近一直在看Mina的源码,用了Mina这么长时间,说实话,现在才开始对Mina有了一些深刻的理解,关于Mina的基本知识的介绍,这里就不多说了,网上已经有很多不错的文章都对Mina做了较深刻的剖析,现在就是想从Mina的最根本的地方来对Mina做一些深层次上的探讨。

还是先从Mina的入口程序来说,每当要启动一个Mina的程序(包括服务器和客户端)时候,这里只是对服务器重点做一些讲解,至于说Mina的客户端的应用,这里只是简单的涉及一点,不会对其做很深入的探讨。但是Mina的服务器和客户端在很大的程度上都是一样,所以这里就“挂一漏万”的简单讲解一下。

在此之前我一直想找一种“串糖葫芦”的方式来讲解一下Mina,可是一直没有时间来看Mina 的源码,真的是无从下手,虽然网上的很多关于Mina的一些文章,讲解的非常透彻了,但是可能对于初学者来说,显得有些深奥,在这里特别的提一下洞庭散人对Mina源码的透彻的分析,如果你对Mina已经有了一定的了解或者是正在学习Mina的源码,建议你去看看他的博客,里面有很多东西讲的是相当到位的。在这里就不在多举例子了。写这篇文档主要是想对刚接触Mina的人讲解一些Mina的基本知识,由浅入深,一步一步的学习Mina思想的精髓,我接触Mina的时间也比较长了,几乎天天在和它打交道,每当你发现一个新奇的用法的时候,你真的会被Mina所折服,我这里不是对Mina的吹捧,记得我曾经和同事开玩笑说,“等真正的懂得了Mina,你就知道什么叫Java了”,所以,我现在想急切的把现在所知道和了解的所有关于Mina的一些东西都想在这篇文章里面写出来,如果有写的不到位的地方还请各位同学多多指正,下面就开始对Mina做一个完整的介绍。

一、先说说Mina的几个类和接口

(1)IoService

(2)BaseIoService

(3)BaseIoAcceptor

(4)IoAcceptor

(5)IoConnector

这几个类和接口是整个服务器或客户端程序(IoConnector)的入口程序,其中就Mina的整体上来说,IoService是所有IO通信的入口程序,下面的几个接口和类都是继承或者实现了IoService接口。

下面先给出Mina(入口程序)的整体架构图:

Mina的整体架构图

在这里先提出几个个问题:

(1)为什么有了一个IoService还要再有一个BaseIoService?

(2)BaseIoService和IoAcceptor(IoConnector)有什么区别?

(3)BaseIoAcceptor(BaseIoConnector)为什么不去直接实现IoService,而是又添加了IoAcceptor(IoConnector)?

带着这几个问题我们来解读一下Mina的源码:

首先,解答第一个问题,为什么有了一个IoService还要再有一个BaseIoService?IoService 和BaseIoService最明显的区别就是IoService是一个接口,而BaseIoService是一个抽象类。BaseIoService实现了IoService中的部分方法。

这里先把IoService接口中要实现的方法和BaseIoService中实现的方法列举如下:

通过对IoService和BaseIoService的比较可以发现,除了getDefaultConfig()这个方法没有在BaseIoService中实现之外,其他的方法都已经在BaseIoService实现了。这里就有一个问题,为什么BaseIoService只是实现了IoService的部分方法,而没有全部实现IoService 的方法呢?通常都知道,接口中的方法是必须要由实现类来实现的,这点是毋庸置疑的。你可以写一个空方法,里面没有任何的逻辑处理,但是你的实现类中却不能没有该方法。但是在Mina中作为实现类的BaseIoService却没有IoService指定的方法getDefaultConfig(),难道Mina真的有独到之处?不是!仔细看看BaseIoService你就会知道,BaseIoService是一个抽象类,抽象类就是用来被继承的,它提供了一些其子类公用的一些方法,当抽象类实现一个接口时,抽象类可以有选择性的实现其所有子类都需要的实现的一些方法,对于接口中指定法方法,抽象类可以选择全部实现或者部分实现。在Mina中如果没有BaseIoService 这个抽象类,而是由BaseIoAcceptor和BaseIoConnector直接去实现BaseIoService接口,那么必然会导致这个两个实现类中都要重写相应的方法,这样就脱离了面向对象设计的本质,没有达到复用的目的。在BaseIoAcceptor/BaseIoConnector和BaseIoService之间添加一个BaseIoService就是为了达到代码复用的目的。在这个问题上主要是要记住两点:

1)抽象类在实现接口的时候可以部分或者全部实现接口中的方法。但是当抽象类只是实现了接口中的部分方法的时候,抽象类的子类必须要实现抽象类中未实现的接口的方

法。在此处,IoService的getDefaultConfig()方法在BaseIoService(BaseIoAcceptor

是BaseIoService的子类,但它也是一个抽象类,所以它也没有实现

getDefaultConfig()),getDefaultConfig()是由BaseIoAcceptor的子类们来实现的(如

SocketAcceptor,这是一个具体实现类)。所以接口的所有方法必须被具体的实现类实

现和抽象类在实现接口的时候可以部分或者全部实现接口中的方法是不矛盾的。

2)注意代码的重用。在面向对象的编程语言中都提供了抽象类和接口,抽象类和接口最大的区别就是抽象类提供了方法的具体实现,供其子类来调用;而接口只是提供了对

方法的声明,其方法的实现要由其具体实现类来做。在Java中一个子类只能有一个

父类,但是却能实现多个接口。个人认为接口和抽象类各有特色,接口的使用比较灵

活,不同的接口可以让其子类扮演不同的角色,侧重于类的复用,在很大程度上解决

了代码复用的问题;抽象类更侧重的是方法的复用,某种意义上讲,抽象类的使用对

于程序来说使用起来更加轻松,但是是使用抽象类还是接口要根据具体的情况而定。

对于接口和抽象类的具体的用法请参考闫宏的《Java与模式》中相关部分的讲解。

之所以在这里罗列这么些问题,目的不仅仅是为了讲解Mina的原理,而是想从一个高的角度来看待的这个经典的开源项目,通过对Mina的学习和理解,能够真正的懂得什么是一个项目,什么是面向对象编程,更本质的东西是怎么灵活运用Java来达到上面的两个目的。这个才是最重要的,哪怕是你在看完本文后对Mina的理解还是有点模糊,但是你至少要知道在编写一个程序的时候怎样从面向对象的角度上去思考一个问题,而不是在用着面向对象的语言写着结构化的程序。这些东西都是自己做开发这么长时间的一些心得,在这里总结出来,目的主要是用于交流和学习,不是在卖弄,只是想让更多的初学者少走一些弯路,懂得学习的方法。

还是回到对Mina的刚提出的那几个问题上来,现在,第一个问题已经解决了,为什么有了一个IoService还要再有一个BaseIoService?答案就是为了代码的复用。

其次,下面开始讨论第二个问题,BaseIoService和IoAcceptor(IoConnector)有什么区别?在讨论这个问题之前,还是先给出这两个类(接口)提供的方法,如下图:

在讨论第一个问题的时候我们已经看过了BaseIoService的方法了,但是没有对这些方法的功能做些梳理,现在就对这些方法做些简单的介绍:

getFilterChainBuilder()和setFilterChainBuilder():这两个方法主要是对一个服务的IoFilter的操作,关于IoFilter的详细介绍会在后面给出,现在你可以将其理解为是一个处理业务逻辑的模块,例如:黑名单的处理、数据的转换、日志信息的处理等等都可以在这个IoFilter中实现,它的工作原理和Servlet 中的过滤器很相似。

addListener()和removeListener():这两个方法通过名字看就可以理解了,就是给当前的服务添加和删除一个监听器,这个监听器主要是用于对当前连接到服务的IoSession进行管理,这个也会在后面做详细的讲解。

getManagerServiceAddress()和getManagerSessions():这两个方法的功能比较相似,一个是获取当前服务所管理的远程地址,一个是获取当前服务所管理的会话IoSession,IoSession对SocketAddress做了一个完整的封装,你也可以先将这两个方法的功能理解为是一回事,具体的区别会在后面给出。

isManaged():检测某个SocketAddress是否处于被管理的状态。

getListeners():获取当前服务的监听器。

看了上面对BaseIoService功能的介绍,现在我们可以理解BaseIoService提供的方法主要是用于对当前服务的管理。那么要管理一个服务,前提条件是这个服务必须存在,存在的前提是什么,就是要启动一个服务,或者是连接到一个远程主机上,这两个任务分别是IoAcceptor和IoConnector来完成的,此处要注意的是这两个对象都是接口,没有具体的实现,具体的实现会由下面介绍的它们相关的子类(SocketAcceptor等)来实现。这样IoAcceptor/IoConnector的功能我们就可以总结出来了,就是启动和停止一个服务。

对于一个完整的服务来说,既要有启动这样的前提条件,还要有对服务的管理和对服务响应

的逻辑处理,这两个缺一不可,回到第二个问题,BaseIoService和IoAcceptor(IoConnector)有什么区别?区别就在于它们实现的功能不一样,但都是为了一个完整的服务来打基础的,两者缺一都不能称为一个完整的服务。这三个都是IoService子类(子接口),IoService只是提供了一些服务应该具有多基本的方法,BaseIoService提供了IoService部分方法的具体实现,而IoAcceptor(IoConnector)是对特定服务要具备的操作的做了一些扩展,这样一个服务完整的模型正在逐渐向我们清晰的展现出来。

再次,讨论一下第三个问题。BaseIoAcceptor(BaseIoConnector)为什么不去直接实现IoService,而是又添加了IoAcceptor(IoConnector)?这个问题其实在上面已经有所涉及,

为了达到对象复用的目的,所以Mina的设计者给出了一个BaseIoService,

IoAcceptor(IoConnector)是实现一个特定服务必须要提供的一些方法。更具体一点,IoAcceptor(IoConnector)是为了一个特定的服务(服务器/客户端)而设计的,而IoService只是提供了一个服务应该具备的一些基本的方法。所以在Mina中给出了一个针对具体服务的一个接口IoAcceptor(IoConnector),这样BaseIoAcceptor(BaseIoConnector)就提供了一个服务所必备的一些条件。因为它即实现了IoAcceptor(IoConnector)接口又继承了抽象类BaseIoService,这样就实现了IoService中的所有方法,并且也添加了特定服务应该具有的方法(即IoAcceptor(IoConnector)中的方法)。以上就是第三个问题的答案。

二、Mina中提供的几个特定的服务

从上面的讨论中我们已经知道了Mina上层的类和接口的一些功能。即图中所示的已经在上面解释清楚了。

Mina的上层结构图(抽象层)

在此我们可以把Mina的上层结构简单的定义为Mina的“抽象层”,既然有了抽象层,肯定就会有其具体实现,抽象中最重要的两个类是BaseIoAcceptor和BaseIoConnector,它们分别是用于服务器和客户端的一个入口程序。

首先,说一下BaseIoAcceptor中的三个具体实现类:

(1)DatagramAcceptorDelegate:数据报UDP通信的服务器入口程序。该类使用UDP协

议进行通信,UDP协议主要是用在视频、远程服务的监听(如心跳程序)中等数据传输要求不是很高的地方。

(2)VmPipeAcceptor:虚拟通道(VM)通信的服务器入口程序。虚拟管道协议主要用于无线通

信方面。

坚定不移贯彻新发展理念

第十讲坚定不移贯彻新发展理念 党的十八大以来,习近平总书记顺应时代和实践发展的新要求,坚持以人民为中心的发展思想,鲜明提出要坚定不移贯彻创新、协调、绿色、开放、共享的新发展理念,引领我国发展全局发生历史性变革。新发展理念集中体现了我们党对新的发展阶段基本特征的深刻洞察和科学把握,标志着我们党对经济社会发展规律的认识达到了新的高度,是我国经济社会发展必须长期坚持的重要遵循。 一、引领我国发展全局深刻变革的科学指引 创新、协调、绿色、开放、共享的新发展理念不是凭空得来的,而是在深刻总结国内外发展经验教训、分析国内外发展大势的基础上形成的,也是针对我国发展中的突出矛盾和问题提出来的。新发展理念深刻揭示了实现更高质量、更有效率、更加公平、更可持续发展的必由之路,是引领我国发展全局深刻变革的科学指引,对于进一步转变发展方式、优化经济结构、转换增长动力,推动我国经济实现高质量发展具有重大指导意义。 新发展理念是针对我国经济发展进入新常态、世界经济复苏乏力形势提出的治本之策。党的十八大以来,面对极其错综复杂的国内外经济形势,以习近平同志为核心的党中央审时度势,从我国经济发展的阶段性特征出发,作出我国经济发展进入新常态的战略判断。世界经济在大调整大变革之中也出现了一些新的变化趋势,2008年国际金融危机深层次影响持续蔓延,西方国家结束黄金增长期,世界经济进入深度调整期,国际贸易低迷,金融市场跌宕起伏,保护主义明显抬头。面对这种新变化新情况,再沿袭粗放发展模式、简单地追求增长速度,显然行不通,必须确立新发展理念来引领和推动我国经济从高速增长阶段转向高质量发展阶段,不断开创经济发展新局面。 新发展理念是针对当前我国发展面临的突出问题和挑战提出的战略指引。我国物质基础雄厚、人力资本丰富、市场空间广阔、发展潜力巨大,经济发展方式加快转变,新的增长动力正在孕育形成,经济长期向好基本面没有改变。同时,发展不平衡不充分的一些突出问题尚未解决,发展质量和效益还不高,创新能力不够强,实体经济水平有待提高,生态环境保护任重道远;民生领域还有不少短板,脱贫攻坚任务艰巨,城乡区域发展和收入分配差距依然较大,群众在就业、教育、医疗、居住、养老等方面面临不少难题;等等。这些问题,必须着力加以解决。新发展理念就是针对这些问题提出的。创新发展注重解决发展动力问题,

远程访问OPC服务器设置

远程访问OPC服务器设置 OPC客户端一方面可以访问本机上的OPC服务器,另一方面,它还可以利用微软的DCOM机制,通过网络来访问其它计算机上的OPC服务器,从而达到远程数据连接的目的。访问本地服务器比较简单,只要检索本地的OPC服务器,并配置相应的组(Group)和数据项(Item)即可,通过网络访问时需要考虑较多的网络连接因素,大体上来说大概有如下的几个需要配置的方面(以WINXP Xp2为例): 一. 运行OPC客户端的计算机和运行OPC服务器的计算机需要彼此能互相访问。 1.1要保证其物理连接,也就是网线正确的连接着两台计算机。 1.2在这两台计算机上分别建立同一个账号及密码,比如用户名[opcuser],密码[123456](注 意:用户密码最好不要设置为空),在这两台计算上使用这个账户都可以登录系统。关于增加账号及密码请参考对应Windows操作系统的帮助文档。 1.3启用各自Windows操作系统的Guest权限。 完成上面几步后,应该达到的效果是:从任何一台计算机搜索另一台计算机,都可以搜索到,并且可以访问对方计算机的共享目录及共享打印机等资源。如下图: 即便用户没有共享任何东西,也会显示空的共享文件夹,而不会产生诸如”不能访问”

等信息。 如果不能访问对方的计算机,首先用ping命令来保证网络的连通,如果必要的情况下,可以关闭这两台计算机的防火墙(无论是winxp xp2自带的防火墙还是专用的防火墙)以及杀毒软件,以杜绝可能产生的问题。 如果访问另一台计算机产生”拒绝访问”的错误,可从网络查找相关资源进行解决。 二. 配置OPCServer所在的计算机 2.1 注册OPCEnum.exe。 opcenum.exe是运行在服务器端的用于枚举本机OPC服务器的服务程序,由OPC基金会提供。注册opcenum有如下几种方式:a)将opcenum.exe拷贝到系统目录下,然后用命令行运行opcenum /regserver 来注册它。b)安装一些OPC服务器程序时会自动安装并注册这个服务程序,比如iconics的模拟OPC服务器程序。c)运行OPC基金会的OPC Core Redistributable安装包,其中包含必要的模块程序。 考虑到远程访问OPC服务器应用较少,以及opcenum.exe对一般用户在系统安全方面带来的混淆,在HMIBuilder中的OPC服务器本身不带OPCEnum.exe,用户根据自己的需要自行注册。 2.2 配置本机的DCOM安全 2.2.1 在命令行运行dcomcnfg,如下图: 产生配置界面如下:

JAVA线程池原理333

在什么情况下使用线程池? 1.单个任务处理的时间比较短 2.将需处理的任务的数量大 使用线程池的好处: 1.减少在创建和销毁线程上所花的时间以及系统资源的开销 2.如不使用线程池,有可能造成系统创建大量线程而导致消耗完系统内存以及”过度切换”。 线程池工作原理:

线程池为线程生命周期开销问题和资源不足问题提供了解决方案。通过对多个任务重用线程,线程创建的开销被分摊到了多个任务上。其好处是,因为在请求到达时线程已经存在,所以无意中也消除了线程创建所带来的延迟。这样,就可以立即为请求服务,使应用程序响应更快。而且,通过适当地调整线程池中的线程数目,也就是当请求的数目超过某个阈值时,就强制其它任何新到的请求一直等待,直到获得一个线程来处理为止,从而可以防止资源不足。 线程池的替代方案 线程池远不是服务器应用程序内使用多线程的唯一方法。如同上面所提到的,有时,为每个新任务生成一个新线程是十分明智的。然而,如果任务创建过于频繁而任务的平均处理时间过短,那么为每个任务生成一个新线程将会导致性能问题。 另一个常见的线程模型是为某一类型的任务分配一个后台线程与任务队列。AWT 和 Swing 就使用这个模型,在这个模型中有一个 GUI 事件线程,导致用户界面发生变化的所有工作都必须在该线程中执行。然而,由于只有一个 AWT 线程,因此要在 AWT 线程中执行任务可能要花费相当长时间才能完成,这是不可取的。因此,Swing 应用程序经常需要额外的工作线程,用于运行时间很长的、同 UI 有关的任务。 每个任务对应一个线程方法和单个后台线程(single-background-thread)方法在某些情形下都工作得非常理想。每个任务一个线程方法在只有少量运行时间很长的任务时工作得十分好。而只要调度可预见性不是很重要,则单个后台线程方法就工作得十分好,如低优先级后台任务就是这种情况。然而,大多数服务器应用程序都是面向处理大量的短期任务或子任务,因此往往希望具有一种能够以低开销有效地处理这些任务的机制以及一些资源管理和定时可预见性的措施。线程池提供了这些优点。 工作队列 就线程池的实际实现方式而言,术语“线程池”有些使人误解,因为线程池“明显的”实现在大多数情形下并不一定产生我们希望的结果。术语“线程池”先于Java 平台出现,因此它可能是较少面向对象方法的产物。然而,该术语仍继续广泛应用着。 虽然我们可以轻易地实现一个线程池类,其中客户机类等待一个可用线程、将任务传递给该线程以便执行、然后在任务完成时将线程归还给池,但这种方法却存在几个潜在的负面影响。例如在池为空时,会发生什么呢?试图向池线程传递任务的调用者都会发现池为空,在调用者等待一个可用的池线程时,它的线程将阻塞。我们之所以要使用后台线程的原因之一常常是为了防止正在提交的线程被阻塞。完全堵住调用者,如在线程池的“明显的”实现的情况,可以杜绝我们试图解决的问题的发生。 我们通常想要的是同一组固定的工作线程相结合的工作队列,它使用 wait() 和

Java多线程技术及案例

Java多线程技术及案例 进程和线程: 进程:每个进程都有独立的代码和数据空间(进程上下文),进程间的切换会有较大的开销,一个进程包含1–n个线程。 线程:同一类线程共享代码和数据空间,每个线程有独立的运行栈和程序计数器(PC),线程切换开销小。 线程和进程一样分为五个阶段:创建、就绪、运行、阻塞、终止。 多进程是指操作系统能同时运行多个任务(程序)。 多线程是指在同一程序中有多个顺序流在执行。 Java中多线程的多种实现方式 Java中有多种多线程实现方法,主要是继承https://www.360docs.net/doc/0c7034509.html,ng.Thread类的方法和 https://www.360docs.net/doc/0c7034509.html,ng.Runnable接口的方法。 继承Thread类 Thread是https://www.360docs.net/doc/0c7034509.html,ng包中的一个类,从这个类中实例化的对象代表线程,启动一个新线程需要建立一个Thread实例。 使用Thread类启动新的线程的步骤如下: 1.实例化Thread对象 2.调用start()方法启动线程 构造方法:

public Thread(String threadName); public Thread(); 例程: publicclass Thread1extends Thread{//定义一个类继承Thread privateint count=1000; publicvoid run(){//重写run方法 while(true){ System.out.print(count+" "); if(--count==0){ return; } } } publicstaticvoid main(String[] args){ Thread1 th1=new Thread1();//实例化继承了Thread的类 Thread1 th2=new Thread1(); th1.start();//调用start()方法, th2.start(); for(int i=0;i<1000;i++){ System.out.print("A "); } }

远程访问服务器设置

远程访问服务器设置 1设置TCP/IP协议 如果安装了多种网络协议,可以通过限制远程用户使用的网络协议来控制远程客户访问的网络资源。TCP/IP是最流行的LAN协议。对于TCP/IP协议来说"还需给远程客户分配IP地址以及其他TCP/IP配置,如DNS服务器和WINS服务器、默认闷关等。打开[路由和远程访问服务]控制台,在目录树中选择相应的服务器,单击鼠标右键,从弹出的快捷菜单中选择[属性]打开属性设置对话框,切换到如图4.43所示的[IP]选项卡,设置IP选项。 1.允许远程客户使用TCP/IP协议

选中[允许基于IP的远程访问和请求拨号连接]复选框,将允许远程访问客户机使用IP协议来访问服务器。如果清除此项,使用IP协议的客户端将不能连接远程访问服务器。 2.限制远程客户访问的网络范围 如果希望基于即的远程访问客户机能够访问到远程访问服务器所连接的网络,应选中[启用IP路由]复选框,激活路由功能。如果清除该选项。使用IP协议的客户机将只能访问远程访问服务器本身的资源,而不能访问网络中的其他资源。 3.向远程客户机指派lP地址 每个通过PPP连接到Windows2000远程访问服务器的远程计算机,都会被自动提供一个IP地址。远程访问服务器获得分配给远程访问客户机的IP地址有两种方式。 通过DHCP服务器获得。 由管理员指派给远程访问服务器的静态IP地址范围。 远程访问服务器也会从获得的IP地址中留出一个自己使用。 在[IP]选项卡的[IP地址分配]区域中设置向远程客户机分配IP地址的方式和范围。 通过DHCP服务器分配IP地址 如果选择[动态主机配置协议]单选钮。将由DHCP服务器为远程客户指定IP地址。远程访问将从DHCP服务器上一次性获得10个IP 地址,如图4.44所示。远程访问服务器将从DHCP获得的第一个IP 地址留给自己使用,并且在与基于TCP/IP的远程访问客户机连接时,

全面从严治党是全面建成小康社会的根本保证

龙源期刊网 https://www.360docs.net/doc/0c7034509.html, 全面从严治党是全面建成小康社会的根本保证 作者:张明学 来源:《青年时代》2018年第02期 摘要:中国共产党“四个全面”战略布局之间是既相互贯通又紧密联系的统一体,即“全面建成小康社会”是处于统领地位的战略目标,而“全面深化改革”、“全面推进依法治国”、“全面从严治党”是实现这一目标的三大战略举措。本文试从全面从严治党和全面建成小康社会两个维度作为重点阐述二者之间的辩证关系,深刻理解全面从严治党是全面建成小康社会的根本保证这一原理。 关键词:四个全面;中国梦;党的建设 实现全面建成小康社会是一个需要打组合拳的新模式过程,我国是一个拥有13多亿人口的发展中大国,全面深化改革是实现全面建成小康社会的不竭动力,但是改革的过程是破旧立新,存在着“阵痛”,会“牵一发而动全身”,涉及的利益冲突和矛盾是方方面面的。常言说:“打铁还需自身硬”。要确保党始终成为推进各项事业改革的坚强领导核心,就必须全面从严治党,加强和改善党的领导。 一、全面深化改革必须不断加强和改善党的领导 首先,要牢牢把握全面深化改革的正确方向,必须在思想上从严治党,因为只有思想一致,才能步调一致。全面深化改革,就必须下狠心,开猛药,对一些已经固化的利益集团开炮,在整个过程中必须要认识到改革的艰难,如果不形成合力,就不可能获得真正的成功。要必须把广大党员干部的思想认识统一到中央的决策上来,把中央的各项部署分解和落实到广大干部群众实际工作中,确保全面深化改革能够沿着有利于党和人民事业发展的方向不断前进。一是要在思想上从严治党,就必须以思想理论建设为根本,重点抓好学习中央的各项决议决策和习近平总书记的系列讲话精神,引导和教育党员干部政治素养不断提高,促使大家矢志不渝为中国特色社会主义共同理想而奋斗;二是要以党性教育为抓手,以“三严三实”精神和“两学一做”活动为契机重点抓好党的优良传统和作风建设,教育引导党员干部特别是领导干部要牢固树立正确的世界观、权力观、事业观;三是要以道德建设为基础,重点抓好四德素养的提高,培育和践行各级干部对社会主义核心价值观的高度认同,教育引导党员干部做社会主义道德的示范者和维护者。 其次,全面深化改革过程中各项决策的形成和推进,必须加强和突显各级领导的责任意识。全面深化改革会牵涉到经济、政治、文化、社会、生态文明和党的建设等多个领域,会对一系列体制机制进行大刀阔斧的改革,是一项事关复杂利益进行不断调整的系统工程。因此,每一项改革措施的决策和推进,都需要站在全局的高度进行整体谋划、协调推进,在决策的过

如何远程连接服务器

如何远程连接服务器 大多数的公司、网站、论坛的服务器都是放在机房叫人托管,因此挑选托管机房是一件很重要也很头疼的事,虽然每个机房都说是24小时留人值守,但事实是服务器真宕机的时候,打电话叫人重启,对方总能找到理由拖上半天才给你重启,给公司和网站论坛带来麻烦甚至造成经济损失。为此,南宁网络人电脑有限公司推出了一套方便、简捷的远程控制解决方案:通过电话唤醒技术远程重启计算机,解决无人值守的问题,再配合免费的网络人(Netman)远程控制软件,实现远程控制电脑:远程运行软件程序、上传下载和修改文件、远程开启外接设备等! 详情咨询:https://www.360docs.net/doc/0c7034509.html,/hardware.asp 第一步:远程开机 将网络人开机卡插在计算机的PCI 插槽上,不需要其他软件配合,不需要在电脑上安装驱动,打个电话,就能远程开机。网络人开机卡,有固话和手机两个版本。固话版需要从电话机上分出一根电话线插到开机卡上;如果你的电脑旁没有座机,可以选择手机版,在控制上放置一张手机卡。开机卡安装好后,只要拨打该电话或手机号,即可实现远程开机,简单实用,快捷稳定。 简单人性化的开机方法:

拨打接在开机卡上的电话或手机,在过了30一50秒的等待时间,如无人接听,将进入启动平台,这时语音提示输入登陆密码进行验证,验证密码正确之后,便可以根据语音提示来对电脑进行开关机的操作了: 按1#键,相当于手工按了一下电脑面板上的开机按键,电脑启动。 按2#键,相当于手工按了一下电脑面板上的开机按键,电脑关闭。如果电脑已经处于关机状态下,就会提示指令无效。 按3#键,可以修改响铃时间。需要提醒大家的是,一般的电话响铃时间都不会超过50秒,如果超过就自动挂机了,因此提醒大家设置响铃时间时不要超过50秒。 按下4#键,可以修改登陆密码,默认的登陆密码是123456 ,大家在使用时最好更改为6位数的其他密码。 按下5#键,相当于手工持续按下电脑面板上的开机按键6秒钟。电脑在死机的情况下,就可以通过这一功能,强制关闭电脑。过几分钟后,再重新启动就可以了。 如果你忘记了登陆密码,可以按下电话插口旁的复位键,得设置恢复到出厂设置,密码将复原为123456。 第二步:远程控制、操作计算机 安装完成后,还可以通过网络人(Netman)配套的远控软件对电脑进行远程控制。 网络人(Netman)个人版是一款可以穿透内网、完全免费、超级安全的远程控制软件。支持远程隐性监控对方屏幕,遥控键盘、鼠标,远程上传、下载、修改、运行文件……就像操作自己电脑一样方便,大大提高远程办公效率。

【知识学习】对“全面从严治党”的理解与体会

对“全面从严治党”的理解与体会 常言道:基础不牢,地动山摇。基层党组织发挥着战斗堡垒作用,基层党组织战斗力的强弱直接关系着党的整体战斗力的强弱。推动全面从严治党向基层延伸,认真落实习总书记讲话精神,才能厚植党的执政根基。 全面从严治党,必须加强基层组织建设,夯实基层基础。党的工作最坚实的力量支撑在基层,最突出的矛盾问题也在基层,必须把抓基层、打基础作为长远之计和固本之策,扎实推进“双基”建设,推动基层组织全面进步、全面过硬。 全面从严治党,必须推动党纪党规教育向基层延伸,唤醒党员党纪意识。开展“两学一做”学习教育,推动教育覆盖每一个基层党组织和党员,唤醒党员意识,促使党员干部尊崇党章、坚定理想信念,树立看齐意识,自觉培养高尚道德情操,守住纪律底线。 全面从严治党,必须把惩治腐败向基层延伸,维护群众切身利益。要教育引导党员干部强化规则意识、规矩意识,培养法治思维、法治理念、法治精神,带头遵守国家法律,带头遵守党规党纪,加强对违反制度行为的监督和查处。 全面从严治党,必须将管党治党意识,管党治党责任深入基层。首先基层党组织要树立正确的政绩观,把抓好党建作为最大的政绩,强化党建意识,对全面从严治党主动担责,认真履责,扎实尽责。坚持党建工作和中心工作一起谋划、

一起部署、一起考核,把每条战线、每个领域、每个环节的党建工作抓具体、抓深入,坚决防止“一手硬、一手软”。其次基层党组织主要责任人对党建工作要亲自抓、负总责,班子其他成员要切实落实党建工作责任和工作部署,细化到人,量化到岗,以责任落实推动工作落实。最后对工作不力,党建工作落后的地方和单位负责人,要及时进行诫勉谈话,对管党治党不力造成不良影响和严重后果的要严格问责,严肃处理。

【工作经验】X市国税局牢牢把握三个着力点落实全面从严治党主体责任

X市国税局牢牢把握三个着力点落实全面从严治党主体责任 全面从严治党是“四个全面”治国理念的重要组成部分。习近平总书记在十八届中央纪委六次全会上指出“全面从严治党,核心是加强党的领导,基础在全面,关键在严,要害在治”,为各级党组织担负全面从严治党主体责任指明了方向。XX市局党组认真贯彻落实上级部署,牢牢把握党的领导、全面覆盖、从严善治三个着力点,推进全面从严治党主体责任落实到位。 一、守土有责,强化党的领导 牢固树立“落实主体责任是领导干部必须履行的重大政治责任和政治纪律,不抓就是失职,抓不好就是渎职”的理念,义不容辞地担当起这份责任,做到守土有责、守土尽责。市局党组以强化党建工作为抓手,切实强化党的领导。一是加强领导抓党建。成立党建工作领导小组,把党建工作纳入绩效管理,细化、量化、硬化考核指标,实施奖惩联动,严格责任追究,解决各级党建工作抓什么、谁来抓、怎么抓的问题。二是健全机制抓党建。推进工作调研常态化。作为党组书记,我到苏任职后,就和党组成员及相关业务处室一起,紧紧围绕深化税收管理改革、全面推进营改增、干部队伍建设、服务地方经济发展等工作重点,深入基层开展调查研究,听取基层意见,解决一线困难;推进党员经常性教育常态化。市局党组带头开展党组中心组理论学习,读原著、听讲座、谈体会,紧密结合税收工作实际,想办法、出实招,在“深学、实做”上下功夫;推行党的组织生活常态化。严格落实领导干部双重组织生活要求,党组成员参加所在支部组织生活,认真落实交心谈心、征集合理化建议等制度,让干部群众参与党建工作、评价党建成效。规范支部组织生活记录、党员信息、党员联系服

务群众、党费收缴等台账管理。三是深化创建抓党建。深入开展文明单位、文明示范窗口、青年文明号、巾帼文明岗、党员示范岗等创建活动,激发党员干部创先争优积极性,全市国税系统实现文明创建工作满堂红,连续七年被表彰为“XX市作风效能优胜单位”。四是创新载体抓党建。广泛开展“道德讲堂”、“亮牌示范”、“双结对”、“在职党员进社区、进企业”等系列活动,在内网开设“为身边人点赞”活动专栏,制作《点赞你我他》系列宣传册,凝聚精气神,传递正能量。 二、全面覆盖,拓展治党内涵 围绕全面从严治党要求,把建章立制和执行落实有机统一,实现内容、对象和过程的全面覆盖。一是内容全覆盖。拓展全面从严治党主体责任内涵和外延,落实到思想建党、制度治党、纪律立党、组织建党、人才兴党等各领域和全过程,坚决纠治组织软弱、队伍涣散、党风退化、纪律松弛等问题,为税收中心工作开展提供坚强保证。二是对象全覆盖。将全系统各级党组织与全体党员干部纳入全面从严治党范畴,形成以市局党组为龙头,市区基层党支部、系统内基层党组织联手共治的新机制。三是过程全覆盖。把全面从严治党与税收中心工作结合起来,特别在营改增攻坚阶段,各级党组织与广大党员干部充分发挥了战斗堡垒作用和先锋模范作用,100余名机关党员干部充实营改增一线,保障了营改增工作有序推进;把全面从严治党与税收管理改革创新机制有机统一,融会贯通、相辅相成,防止和纠正“两张皮”现象;把全面从严治党与优化服务有机统一,改进工作作风,提升工作质效,持续增进纳税人获得感;把全面从严治党与依法治税有机统一,坚持用法治思维、法治方式来带队治税,引导干部在法律框架内做好各项税收工作。 三、从严善治,夯实治税基石

Windows Server 2008远程桌面设置

Windows server 2008设置远程桌面 凭借无与伦比的安全优势,Windows Server 2008系统让不少朋友在不知不觉中加入了使用行列。不过,这并不意味着Windows Server 2008系统的安全性就能让人高枕无忧了;这不,当我们开启了该系统自带的远程桌面功能后,Windows Server 2008系统的安全问题随即就凸显出来了,如果我们不对远程桌面功能进行合适设置,那么Windows Server 2008服务器系统受到非法攻击的可能性就会加大。为了让Windows Server 2008系统更安全,本文特意总结几则远程桌面功能的安全设置技巧,希望大家能从中获得启发! 强迫执行网络级身份验证 尽管传统操作系统也具有远程桌面功能,不过Windows Server 2008系统对远程桌面功能的安全性能进行了强化,它允许网络管理员通过合适设置来强迫远程桌面连接用户执行网络级身份验证,以防止一些非法用户也趁机使用远程桌面功能来入侵Windows Server 2008服务器系统。要实现强迫远程桌面连接用户执行网络级身份验证操作时,我们必须按照如下步骤来设置Windows Server 2008系统的远程桌面连接参数:首先以超级用户的身份登录进入Windows Server 2008服务器系统,打开对应系统的“开始”菜单,从中依次选择“程序”、“管理工具”、“服务器管理器”选项,打开本地服务器系统的服务器管理器控制台窗口; 其次将鼠标定位于服务器管理器控制台窗口左侧显示区域中的“服务器管理”节点选项上,在对应“服务器管理”节点选项的右侧显示区域,单击“服务器摘要”设置区域中的“配置远程桌面”链接,打开服务器系统远程桌面功能的设置对话框; 在该设置对话框的“远程桌面”处,服务器系统共为我们提供了三个设置选项,如果我们想让局域网中的任何一台普通计算机都能顺利使用远程桌面连接来远程控制Windows Server 2008服务器系统时,那应该将“允许运行任意版本远程桌面的计算机连接”功能选项选中,当然这种功能选项容易对Windows Server 2008服务器系统的运行安全性带来麻烦。 为了让我们能够安全地使用远程桌面功能来远程控制服务器,Windows Server 2008系统推出了“只允许运行带网络级身份验证的远程桌面的计算机连接”这一控制选项(如图1所示),我们只要将该控制选项选中,再单击“确定”按钮保存好设置操作,日后Windows Server 2008系统就会自动强制对任何一位远程桌面连接用户执行网络级身份验证操作了,这样的话非法用户自然也就不能轻易通过远程桌面连接功能来非法攻击Windows Server 2008服务器系统了。

手把手教你做一个java线程池小例子

废话不多说开整 我用的是eclipse(这应该没多大影响) 建一个工程java工程和web工程都行然后建一个包建一个类带main方法 首先贴出来的是内部类 //继承了runnable接口 class MyTask implements Runnable { private int taskNum; public MyTask(int num) { this.taskNum = num; } @Override public void run() { System.out.println("正在执行task "+taskNum); try { //写业务 Thread.currentThread().sleep(2000); } catch (InterruptedException e) { e.printStackTrace(); } System.out.println("task "+taskNum+"执行完毕!"); } } 接下来就是这个类 public class testOne { public static void main(String[] args) { ThreadPoolExecutor executor = new ThreadPoolExecutor(5, 7, 10, https://www.360docs.net/doc/0c7034509.html,LISECONDS, new ArrayBlockingQueue(2),new ThreadPoolExecutor.DiscardOldestPolicy() );

for(int i=0;i<15;i++){ MyTask myTask = new MyTask(i); executor.execute(myTask); System.out.println("线程池中线程数目: "+executor.getPoolSize()+"队列等待执行的任务数目:"+ executor.getQueue().size()+"已经执行完别的任务数目: "+executor.getCompletedTaskCount()); } executor.shutdown(); } } 接下来在说明一下ThreadPoolExecutor的参数设置ThreadPoolExecutor(int corePoolSize,//线程池维护线程的最少数量 int maximumPoolSize,//线程池维护线程的最大数量 long keepAliveTime,//线程池维护线程所允许的空闲时间 TimeUnit unit, 线程池维护线程所允许的空闲时间单位 BlockingQueue workQueue,线程池所使用的缓存队列 RejectedExecutionHandler handler线程池对拒绝任务的处理策略 ) handler有四个选择: ThreadPoolExecutor.AbortPolicy() 抛出java.util.concurrent.RejectedExecutionException异常 ThreadPoolExecutor.CallerRunsPolicy() 重试添加当前的任务,他会自动重复调用execute()方法 ThreadPoolExecutor.DiscardOldestPolicy() 抛弃旧的任务 ThreadPoolExecutor.DiscardPolicy() 抛弃当前的任务 上面是一个例子接下来再来一个例子

深入理解新发展理念

深入理解新发展理念 创新、协调、绿色、开放、共享的发展理念,我在党的十八届五中全会和其他场合已经讲了不少,今天不从抓工作的角度全面讲了,而是结合历史和现实,结合一些重大问题,从理论上、宏观上讲讲。 第一,着力实施创新驱动发展战略。把创新摆在第一位,是因为创新是引领发展的第一动力。发展动力决定发展速度、效能、可持续性。对我国这么大体量的经济体来讲,如果动力问题解决不好,要实现经济持续健康发展和“两个翻番”是难以做到的。当然,协调发展、绿色发展、开放发展、共享发展都有利于增强发展动力,但核心在创新。抓住了创新,就抓住了牵动经济社会发展全局的“牛鼻子”。 坚持创新发展,是我们分析近代以来世界发展历程特别是总结我国改革开放成功实践得出的结论,是我们应对发展环境变化、增强发展动力、把握发展主动权,更好引领新常态的根本之策。 回顾近代以来世界发展历程,可以清楚看到,一个国家和民族的创新能力,从根本上影响甚至决定国家和民族前途命运。 16世纪以来,人类社会进入前所未有的创新活跃期,几百年里,人类在科学技术方面取得的创新成果超过过去几千年的总和。特别是18世纪以来,世界发生了几次重大科技革命,如近代物理学诞生、蒸汽机和机械、电力和运输、相对论和量子论、电子和信息技术发展等。在此带动下,世界经济发生多次产业革命,如机械化、电气化、自动化、信息化。每一

次科技和产业革命都深刻改变了世界发展面貌和格局。一些国家抓住了机遇,经济社会发展驶入快车道,经济实力、科技实力、军事实力迅速增强,甚至一跃成为世界强国。发端于英国的第一次产业革命,使英国走上了世界霸主地位;美国抓住了第二次产业革命机遇,赶超英国成为世界第一。从第二次产业革命以来,美国就占据世界第一的位置,这是因为美国在科技和产业革命中都是领航者和最大获利者。 中华民族是勇于创新、善于创新的民族。前面说到我国历史上的发展和辉煌,同当时我国科技发明和创新密切相关。我国古代在天文历法、数学、农学、医学、地理学等众多科技领域取得举世瞩目的成就。这些发明创造同生产紧密结合,为农业和手工业发展提供了有力支撑。英国哲学家培根这样讲到:印刷术、火药、指南针,这3种发明曾改变了整个世界事物的面貌和状态,以致没有一个帝国、教派和人物能比这3种发明在人类事业中产生更大的力量和影响。一些资料显示,16世纪以前世界上最重要的300项发明和发现中,我国占173项,远远超过同时代的欧洲。我国发展历史上长期处于世界领先地位,我国思想文化、社会制度、经济发展、科学技术以及其他许多方面对周边发挥了重要辐射和引领作用。近代以来,我国逐渐由领先变为落后,一个重要原因就是我们错失了多次科技和产业革命带来的巨大发展机遇。 当今世界,经济社会发展越来越依赖于理论、制度、科技、文化等领域的创新,国际竞争新优势也越来越体现在创新能力上。谁在创新上先行一步,谁就能拥有引领发展的主动权。当前,新一轮科技和产业革命蓄势

java深入理解线程池

深入研究线程池 一.什么是线程池? 线程池就是以一个或多个线程[循环执行]多个应用逻辑的线程集合. 注意这里用了线程集合的概念是我生造的,目的是为了区分执行一批应用逻辑的多个线程和 线程组的区别.关于线程组的概念请参阅基础部分. 一般而言,线程池有以下几个部分: 1.完成主要任务的一个或多个线程. 2.用于调度管理的管理线程. 3.要求执行的任务队列. 那么如果一个线程循环执行一段代码是否是线程池? 如果极端而言,应该算,但实际上循环代码应该算上一个逻辑单元.我们说最最弱化的线程池 应该是循环执行多个逻辑单元.也就是有一批要执行的任务,这些任务被独立为多个不同的执行单元.比如: int x = 0; while(true){ x ++; } 这就不能说循环中执行多个逻辑单元,因为它只是简单地对循环外部的初始变量执行++操作. 而如果已经有一个队列 ArrayList al = new ArrayList(); for(int i=0;i<10000;i++){ al.add(new AClass()); } 然后在一个线程中执行: while(al.size() != 0){ AClass a = (AClass)al.remove(0); a.businessMethod(); } 我们说这个线程就是循环执行多个逻辑单元.可以说这个线程是弱化的线程池.我们习惯上把这些相对独立的逻辑单元称为任务. 二.为什么要创建线程池? 线程池属于对象池.所有对象池都具有一个非常重要的共性,就是为了最大程度复用对象.那么 线程池的最重要的特征也就是最大程度利用线程. 从编程模型模型上说讲,在处理多任务时,每个任务一个线程是非常好的模型.如果确实可以这么做我们将可以使用编程模型更清楚,更优化.但是在实际应用中,每个任务一个线程会使用系统限入"过度切换"和"过度开销"的泥潭. 打个比方,如果可能,生活中每个人一辆房车,上面有休息,娱乐,餐饮等生活措施.而且道路交道永远不堵车,那是多么美好的梦中王国啊.可是残酷的现实告诉我们,那是不可能的.不仅每个人一辆车需要无数多的社会资源,而且地球上所能容纳的车辆总数是有限制的. 首先,创建线程本身需要额外(相对于执行任务而必须的资源)的开销.

PCS7远程访问OPC服务器设置

OPC服务器设置 OPC客户端一方面可以访问本机上的OPC服务器,另一方面,它还可以利用微软的DCOM机制,通过网络来访问其它计算机上的OPC服务器,从而达到远程数据连接的目的。访问本地服务器比较简单,只要检索本地的OPC服务器,并配置相应的组(Group)和数据项(Item)即可,通过网络访问时需要考虑较多的网络连接因素,大体上来说大概有如下的几个需要配置的方面(以WINXP Xp2为例): 一. 运行OPC客户端的计算机和运行OPC服务器的计算机需要彼此能互相访问。 1.1要保证其物理连接,也就是网线正确的连接着两台计算机。 1.2在这两台计算机上分别建立同一个账号及密码,比如用户名[opcuser],密码[123456](注 意:用户密码最好不要设置为空),在这两台计算上使用这个账户都可以登录系统。关于增加账号及密码请参考对应Windows操作系统的帮助文档。 1.3启用各自Windows操作系统的Guest权限。 完成上面几步后,应该达到的效果是:从任何一台计算机搜索另一台计算机,都可以搜索到,并且可以访问对方计算机的共享目录及共享打印机等资源。如下图: 即便用户没有共享任何东西,也会显示空的共享文件夹,而不会产生诸如”不能访问”

等信息。 如果不能访问对方的计算机,首先用ping命令来保证网络的连通,如果必要的情况下,可以关闭这两台计算机的防火墙(无论是winxp xp2自带的防火墙还是专用的防火墙)以及杀毒软件,以杜绝可能产生的问题。 如果访问另一台计算机产生”拒绝访问”的错误,可从网络查找相关资源进行解决。 二. 配置OPCServer所在的计算机 2.1 注册OPCEnum.exe。 opcenum.exe是运行在服务器端的用于枚举本机OPC服务器的服务程序,由OPC基金会提供。注册opcenum有如下几种方式:a)将opcenum.exe拷贝到系统目录下,然后用命令行运行opcenum /regserver 来注册它。b)安装一些OPC服务器程序时会自动安装并注册这个服务程序,比如iconics的模拟OPC服务器程序。c)运行OPC基金会的OPC Core Redistributable安装包,其中包含必要的模块程序。 考虑到远程访问OPC服务器应用较少,以及opcenum.exe对一般用户在系统安全方面带来的混淆,在HMIBuilder中的OPC服务器本身不带OPCEnum.exe,用户根据自己的需要自行注册。 2.2 配置本机的DCOM安全 2.2.1 在命令行运行dcomcnfg,如下图: 产生配置界面如下:

OPC DA远程连接设置

OPC DA远程连接设置 局域网内OPC DA客户端访问OPC DA服务器是基于DCOM组件的远程调用。新的OPC UA协议通过证书互换的方式可以更为简单的进行远程连接。如OPC服务器支持OPC UA建议使用OPC UA协议进行通讯,因实际工程的需要此次试验OPC DA的远程访问。 网上查阅的资料大部分通过大范围的开放DCOM调用权限来进行OPC DA通讯,通过测试和深入了解发现OPC访问的设置并不复杂,而且可以通过针对性的配置降低安全风险。 试验硬件: 局域网; 架设C(客户端)电脑和S(服务器)电脑; 保证两台PC相互ping通; 试验软件: KEPserverEX V6(OPC客户端)安装于客户端电脑; Applicom console(OPC服务器)安装于服务器电脑;(只支持OPC DA ) 关键设置: 1、用户配置(C和S都要配置) 2、防火墙配置(开启防火墙的PC需要配置) 3、本地电脑的DCOM配置(C和S均需要配置) 4、OPC服务器程序的DCOM配置(仅S需要配置) 一、创建用户账户 在C和S上分别创建一个拥有管理员权限的同名同密码账号,例如:PMI; 要进行OPC DA远程接,C必须使用该账户登录系统,通过配置S可以以该账户 登录系统。 二、配置防火墙 一般防火墙默认情况是开启的,如果C和S都不开防火墙,可以省略防火墙的配置,建议先关闭防火墙进行连接测试,测试连通后再开启防火墙进行配置。关于防火墙的配置在最后说明。

三、配置本地电脑的DCOM 运行comexp.msc -32进入32位DCOM组建服务界面,一般OPC软件位32位,如果软件为64位,运行comexp.msc进入64位DCOM组件服务界面进行配置。 1、客户端C和服务器S的DCOM配置 两台电脑均进入组件服务—我的电脑—属性 如下图进行设置:

windows设置只允许一个帐户远程访问服务器

Windows下设置只允许一个帐户远程桌面 访问服务器 很多服务器被黑客入侵,都是会通过各种漏洞新建一个用户帐户,然后想办法将之提权到administrators组里面,然后使用新建的帐户登陆到服务器上,然后再做进一步入侵,留下木马后门等。 针对这个情况,我们可以在组策略编辑器里面做一个小小的设置我们就可以让黑客新建的帐户无法登陆到我们的服务器了! 设置步骤如下: 1,使用gpedit.msc命令,打开组策略编辑器。然后依次展开计算机配置----windows设置----安全设置----本地策略----用户权限分配。到这里后,在右边的窗口中,找到通过终端服务允许登陆如下图所示: 2,设置属性,将原来的administrators组删除掉,然后添加上你的管理员帐户,可以是administrator或者是您自己新建的可以远程管理的用户(为方便演示我这里设置的administrator但是administrator本身就是不安全的),切记这里只保留一个用户就可以了。设置如下图所示:

3,到这里然后点击应用确定,然后设置就完成了。 4,下面来测试下一个效果,新建一个test帐户,密码随意,添加到administrators组内。

5,然后使用新建的帐户远程登陆,会发现提示你没有权限,而在没有做设置之前是可以登陆的! 小结: 由于现在越来越多的网络管理员的安全意识不够,照成大量的数据泄露以及服务器被抓成肉鸡或网站被挂马,等等现象不一而止,这篇文章只是我在一个客户被入侵后无法远程然后得到的一个想法。 关于这个权限的设置还有一个地方也是可以设置的,开打管理工具---终端服务配置--连接---RDP-Tcp属性--权限这里也是可以对用户的权限进行设置的。

运用JAVA的concurrent.ExecutorService线程池实现socket的TCP和UDP连接

运用JAVA的concurrent.ExecutorService线程池实现socket的TCP和UDP连接 最近在项目中可能要用到socket相关的东西来发送消息,所以初步研究了下socket 的TCP和UDP实现方式,并且结合java1.5的concurrent.ExecutorService类来实现多线程。 具体实现方式见代码: 一、TCP方式: 1、服务端实现方式: TCP的服务端实现方式主要用到ServerSocket类,接收等待客户端连接的方法是accept(); 代码如下:类SocketServerTCP 1private int port=8823; 2private ServerSocket serverSocket; 3private ExecutorService executorService;//线程池 4private final int POOL_SIZE=100;//单个CPU线程池大小 5 6public SocketServerTCP(){ 7try{ 8serverSocket=new ServerSocket(port); 9executorService= Executors.newFixedThreadPool(Runtime.getRuntime() 10.availableProcessors()*POOL_SIZE); https://www.360docs.net/doc/0c7034509.html,("端口号为"+port+"的服务器启动"); 12}catch(IOException e){ 13 e.printStackTrace(); 14} 15} 16 17public void service(){ 18System.out.println("socket初始化成功!"); https://www.360docs.net/doc/0c7034509.html,("socket服务端初始化成功!"); 20while(true){ 21Socket socket=null; 22try{ 23//接收客户连接,只要客户进行了连接,就会触发accept();从而建立连接

10.第十部分:在 Windows Server 2003 中使用 RRAS 来配置拨号远程访问服务器

配置拨号远程访问服务器的逐步式指南 本逐步式指南提供了配置路由和远程访问服务(RRAS) 结构以支持拨入远程访问连接的指导。 本页内容 简介 概述 配置拨号远程访问服务器 通过策略保护远程访问拨入 其他资源 简介 逐步式指南 Windows Server 2003 部署逐步式指南提供了很多常见操作系统配置的实际操作经验。本指南首先介绍通过以下过程来建立通用网络结构:安装Windows Server 2003;配置Active Directory?;安装Windows XP Professional 工作站并最后将此工作站添加到域中。后续逐步式指南假定您已建立了此通用网络结构。如果您不想遵循此通用网络结构,则需要在使用这些指南时进行适当的修改。 通用网络结构要求完成以下指南。 ?第一部分:将Windows Server 2003 安装为域控制器 ?第二部分:安装Windows XP Professional 工作站并将其连接到域上 在配置通用网络结构后,可以使用任何其他的逐步式指南。注意,某些逐步式指南除具备通用网络结构要求外,可能还需要满足额外的先决条件。任何额外的要求都将列在特定的逐步式指南中。 Microsoft Virtual PC 可以在物理实验室环境中或通过虚拟化技术(如Microsoft Virtual PC 2004 或Microsoft Virtual Server 2005)来实施Windows Server 2003 部署逐步式指南。借助于虚拟机技术,客户可以同时在一台物理服务器上运行多个操作系统。Virtual PC 2004 和Virtual Server 2005 就是为了在软件测试和开发、旧版应用程序迁移以及服务器整合方案中提高工作效率而设计的。 Windows Server 2003 部署逐步式指南假定所有配置都是在物理实验室环境中完成的,但大多数配置不经修改就可以应用于虚拟环境。 将这些逐步式指南中提供的概念应用于虚拟环境超出了本文的讨论范围。

相关文档
最新文档