[Netty] Fossil - Generate a request in Client

Netty server接收一个request到执行sql,最后返回给client结果。

那么,client如何生成这个request?

 

第一步:开场启动:

initSystemParameter();  // --> 传输协议设置(a)
mHandler = new Handler( );
mHandler.postDelayed( mRunable, SPLASH_DISPLAY_LENGHT );

        // 进入登陆界面
        public void run( ) {
            ActivityRouter.goToSignIn( SplashActivity.this );
        }

(a) 支持多种传输协议:

    public static ProtocolHandler getProtocolHandler( Context context ) {
ProtocolHandler handler
= null; switch ( mHandlerType ) { case HANDLER_XML: handler = new XMLProtocolHandler( ); break; case HANDLER_PROTOBUF: // if netty is already init, here is just a NULL check NettyHandler.initNetty( context );  // --> (b) handler = new NettyHandler( ); break; default: break; }

(b) netty初始化:initNetty

java.lang.System.setProperty( "java.net.preferIPv4Stack",     "true"  );
java.lang.System.setProperty( "java.net.preferIPv6Addresses", "false" );

mBootstrap = new ClientBootstrap( new NioClientSocketChannelFactory(
  // only need 1 boss thread
  Executors.newFixedThreadPool( mBossThreadNum ), 
  // only permit 5 consist request
  Executors.newFixedThreadPool( mWorkerThreadNum ) ) ); 

  // Configure the event pipeline factory.
  mBootstrap.setPipelineFactory( new ManGaGaTestClientPipelineFactory( context ) );  // --> (c)
  mConnectFuture = mBootstrap.connect( new InetSocketAddress( AccountInfo.mNettyServerIP, AccountInfo.mNettyServerPort ) );
            
  // Wait until the connection is made successfully.
  mConnectFuture.awaitUninterruptibly( );

(c) ChannelPipeline

配置完全类似服务器端,这里的自定义服务可以定义为例如“消息推送”。

p.addLast("handler", new ManGaGaTestClientHandler( mContext )); //upstream handler

// ManGaGaTestClientHandler定义内容
mNotificationManager = ( NotificationManager ) mContext.getSystemService( Context.NOTIFICATION_SERVICE );

如此,我们有了处理request的netty版本的handler。

 

第二步:关于ActivityRouter设计的必要性,便于统一管理activity之间的关系。

public class ActivityRouter {public static void goToSignIn( Context currentContext ) {
        Intent intent = new Intent( currentContext, SignInActivity.class );
        intent.setFlags( Intent.FLAG_ACTIVITY_CLEAR_TOP );
        currentContext.startActivity( intent );
    }
  ...

点击按钮后,进入AccountEngine,这里体现了MVC的思想:Model View Controller,用一种业务逻辑、数据、界面显示分离的方法组织代码。

myButton.setOnClickListener( new OnClickListener( ) {
  @Override
  public void onClick( View arg0 ) {
    if ( checkUserInput( ) ) {
      mAccountEngine.signIn( mETUsername.getText( ).toString( ), mETPassword.getText( ).toString( ) );
    }
   }

之后,进入业务逻辑部分。

 

第三步:构建request,AccountEngine。

mAccountEngine.signIn( mETUsername.getText( ).toString( ), mETPassword.getText( ).toString( ) );

在使用signIn方法前,先构建这个engine类,这里出现了一个TGApplication类,它的作用是什么?

ISharedModuleStorage ss = ( TGApplication ) getApplication( );
mAccountEngine = new AccountEngine( ss, getApplicationContext( ) );
1.
public AccountEngine( ISharedModuleStorage aSharedModuleStorage, Context context ){...}

getApplication()是用来获取Application实例的,但是该方法只在Activity和Service中才能调用;

在一些其他的地方,比如说当我们在BroadcastReceiver中也想获取Application实例,这时就需要使用getApplicationContext()方法

From:http://blog.csdn.net/ly502541243/article/details/52105466

既然Application是在应用一创建就初始化了,而且是在应用运行时一直存在的,那我们可以把它当做是一个全局变量来使用,可以保存一些共享的数据,或者说做一些工具类的初始化工作。

2.
// call back for account operations to XMPP utility
mXmppAccountOpCbk
= new CMGGXmppAccountOperationCallback( ); mHttpAccountOpCbk = new CMGGHttpAccountOperationCallback( ); mObserverList = new ArrayList<IStateObserver>( ); mState = new AccountEngineState( ); // 先获取共享空间的句柄:aSharedModuleStorage// Get instance of Xmpp Account Manager:HashMap<String, Object>( ); // obj = aSharedModuleStorage.getSharedObject( XMPPUtility.class.getName( ) ); mXmppManager = new XMPPUtility( ); // 这是一个需放在共享空间的utility aSharedModuleStorage.putLongSharedObject( XMPPUtility.class.getName( ), mXmppManager ); // 其实就是netty mProtocolHandler = ProtocolHandlerFactory.getProtocolHandler( context );

 

第四步:发送request,执行signIn。

public final boolean signIn( String aUserName, String aPassword ) {

// 既是聊天的登陆; if ( mXmppManager != null ) { mXmppManager.signIn( aUserName, aPassword, mXmppAccountOpCbk );  // --> }
// 也是主服务的登陆;
Map<String, Object> data = new HashMap<String, Object>( ); data.put( ProtocolRequestTag.USER_NAME, aUserName ); data.put( ProtocolRequestTag.USER_PASSWORD, aPassword ); data.put( ProtocolRequestTag.CALL_BACK, mHttpAccountOpCbk ); mProtocolHandler.sendRequest( new Request( ProtocolFunctionName.SIGNIN, data ) );   // --> return true; }

 

第五步:回调函数处理服务器的回应。

(1) xmpp的回调

    public final boolean signIn( String aUserName, String aPassword, IMGGAccountOperationCallback aCallback ) {
        new Thread( new SignInFunc( aUserName, aPassword, aCallback ) ).start( );
        return true;
    }

可见,开启一线程异步处理接收事件。

    private class SignInFunc implements Runnable {

        private String mUserName = null;
        private String mPassword = null;
        private IMHAccountOperationCallback mCallback = null;

        public SignInFunc( String aUserName, String aPassword, IMHAccountOperationCallback aCallback ) {
            this.mUserName = aUserName;
            this.mPassword = aPassword;
            this.mCallback = aCallback;
        }

        @Override
        public void run( ) {
            XMPPConnectionManager connectionManager = XMPPConnectionManager.getInstance( );
            // 尝试连接
            if ( !connectionManager.isConnected( ) ) {
                connectionManager.connect( HOST_NAME );
            }
            // 还没连接上就报错
            if ( !connectionManager.isConnected( ) ) {
                mCallback.operationFailed( new TErrorAccount( TMHAccountErrorMessage.EFailedToConnect ) );
                return;
            }
            // 连接上就开始login流程
            connectionManager.getConnection( ).login( mUserName, mPassword ); // XMPPConnection内部方法
            AccountInfo.setUserName( mUserName );
            AccountInfo.setPassword( mPassword );
            mCallback.signInFinished( );
        }
    }

 

(2) netty的回调

Make a new connection.

@Override
public void sendRequest( Request request ) {
// Get the handler instance to start request
        ManGaGaTestClientHandler handler = mConnectFuture.getChannel( ).getPipeline( ).get( ManGaGaTestClientHandler.class );
boolean ret = handler.handleRequest( request );     ... ... }

(1) 先找到大handler,也就是public class ManGaGaTestClientHandler extends SimpleChannelUpstreamHandler类中:

    public boolean handleRequest( Request request ) {
        String fun = request.getRequestName( );
        FunctionHandlerBase handler = FunctionHandlerFactory.getHandler( fun );  // <----
        // Jeff:找对应的handler
mHandler
= handler; mggRequest req = mHandler.encodeRequest( request ); return true; }

    @Override
    public void messageReceived( ChannelHandlerContext ctx, final MessageEvent e ) {
... <可用于消息推送> ...
}

(2) 再找到小handler,根据fun = ProtocolFunctionName.SIGNIN,工厂方法生成对应的handler这个干实事的家伙。

public class HandlerSignIn extends FunctionHandlerBase {
... ... @Override
public MhRequest encodeRequest( Request request ) {
//parse request data into protocolbuf format Map<String, Object> data = request.getData( ); mUsername = data.get( ProtocolRequestTag.USER_NAME ).toString(); mPassword = data.get( ProtocolRequestTag.USER_PASSWORD ).toString(); mCallback = ( IMGGAccountOperationCallback )data.get( ProtocolRequestTag.CALL_BACK ); mggRequestProtocolProperty.Builder ppBuild = mggRequestProtocolProperty.newBuilder(); ppBuild.setApiId (ProtocolRequestTag.API_ID). setApiVer (ProtocolRequestTag.API_VERSION). setClientId(ProtocolRequestTag.CLIENT_ID). setSecurity(false); mggRequestDataSignIn.Builder dBuild = mggRequestDataSignIn.newBuilder(); dBuild.setUsername(mUsername).
setPassword(mPassword); mggRequest.Builder build
= mggRequest.newBuilder(); build.setFunction (mggFunctions.FUN_SIGNIN_VALUE). setProperty (ppBuild.build()). setRequestDataSignin(dBuild); return build.build(); }
  ... ...
}

如此,这个request就发了出去。

 

 

最后的问题:

  • protobuff中对signIn的规定的类HandlerSignIn的实例化在哪里?
public class FunctionHandlerFactory {

    public static FunctionHandlerBase getHandler( String function ) {
        FunctionHandlerBase handler = null;
        if ( function.equals( ProtocolFunctionName.SIGNUP ) ) {
            handler = new HandlerSignUp( );
        } else if ( function.equals( ProtocolFunctionName.SIGNIN ) ) {
            handler = new HandlerSignIn( );
... ...

 

  • 服务器端如何接收的?接收到包,解析,生成对应的service来处理。
<Server>

@Override
public void messageReceived( ChannelHandlerContext ctx, MessageEvent e ) {    System.out.println( "ManGagaServerHandler: Message received" );    // 获取这个请求包    mggRequest request = ( mggRequest ) e.getMessage( );    mggServiceBase service = null;    mggResponse response = null;    // 查看服务器端是否有对应客户端的function的请求    if ( request.hasFunction( ) ) {// get service handler to handle this request       service = mggServiceFactory.getServcie( request.getFunction( ) );      response = service.handleRequest( request );    } else { // unknwon request      response = createUnknownResponse( );    }    // 回应客户端    e.getChannel( ).write( response ); }

 

  • 客户端的回调函数mHttpAccountOpCbk与服务器推送的实现区别?
请求结果回调

public
class HandlerSignIn extends FunctionHandlerBase {   ... ... @Override public MhRequest encodeRequest( Request request ) { ... } @Override public boolean CheckResponse(mggResponse response) { int inv_result = mggResults.RES_FAILED_VALUE; int func_result = mggResults.RES_FAILED_VALUE; //first check if this request success inv_result = response.getProperty().getResult();if( inv_result == mggResults.RES_SUCCESS_VALUE ){ //invoke success, here we check function call result if( response.hasFunction() ){if( response.getFunction() == mggFunctions.FUN_SIGNIN_VALUE ){ func_result = response.getResponseDataSignin().getResult(); } } } int err = 0; if( func_result == MhResults.RES_FAILED_VALUE ){ err = response.getResponseDataSignin().getError(); } //if signin success or already signed, go ahead success process //next,业务逻辑 } }

再回到大handler中,主自定义服务中实现消息推送的接收,毕竟,接什么消息是未知的。

推送消息接收

public
class ManGaGaTestClientHandler extends SimpleChannelUpstreamHandler {public boolean handleRequest( Request request ) {
... ...
}
@Override public void messageReceived( ChannelHandlerContext ctx, final MessageEvent e ) { // transform message to protobuf binary mggResponse resp = ( mggResponse ) e.getMessage( ); // test push if ( mggFunctions.FUN_MULTICAST_USER_LOCATION_VALUE == resp.getFunction( ) ) { mggUser user = resp.getResponseDataMulticastUserLocation( ).getUser( ); long userId = user.getUserId( ); String username = user.getUsername( ); String nickName = user.getNickname( ); ... ...
return; } } }

 

posted @ 2018-02-02 06:34  郝壹贰叁  阅读(265)  评论(0)    收藏  举报