[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; } } }

浙公网安备 33010602011771号