这几天刚学期android,目前项目要求的客户端是android平台,所以要开始啃了....
服务器与客户端的通信准备使用现有的开发框架,找了几个----mina,google 的 protobuf,smack,androidpn,Netty...
这些框架都不错,不过最终选择的是apache的mina框架,主要是mina在网上的资料比较全,用的也比较广泛,再就是也适合我项目以后的扩展加入SPRING\CXF\RESTFUL WEBSERVICE等
不废话了,开始把目前学习的进度开始进行整理,方便自己以后进行查阅,也给其他入门的兄弟们 参考参考。
当然,最重要的是希望大家能够提出并给与宝贵的经验。
服务端代码:
package org.demo; import java.net.InetSocketAddress; import java.nio.charset.Charset; import org.apache.mina.common.IdleStatus; import org.apache.mina.common.IoAcceptor; import org.apache.mina.filter.codec.ProtocolCodecFilter; import org.apache.mina.filter.codec.textline.LineDelimiter; import org.apache.mina.filter.codec.textline.TextLineCodecFactory; import org.apache.mina.transport.socket.nio.NioSocketAcceptor; import org.slf4j.Logger; import org.slf4j.LoggerFactory; public class Demo1Server { private static Logger logger = LoggerFactory.getLogger(Demo1Server.class); private static int PORT = 8989; public static void main(String[] args) { IoAcceptor acceptor = null; try { // 创建一个非阻塞的server端的Socket acceptor = new NioSocketAcceptor(); // 设置过滤器(使用Mina提供的文本换行符编解码器) acceptor.getFilterChain().addLast( "codec", new ProtocolCodecFilter(new TextLineCodecFactory(Charset .forName("UTF-8"), LineDelimiter.WINDOWS.getValue(), LineDelimiter.WINDOWS.getValue()))); // 设置读取数据的缓冲区大小 acceptor.getSessionConfig().setReadBufferSize(2048); // 读写通道10秒内无操作进入空闲状态 acceptor.getSessionConfig().setIdleTime(IdleStatus.BOTH_IDLE, 10); // 绑定逻辑处理器 acceptor.setHandler(new Demo1ServerHandler()); // 绑定端口 acceptor.bind(new InetSocketAddress(PORT)); logger.info("服务端启动成功... 端口号为:" + PORT); } catch (Exception e) { logger.error("服务端启动异常....", e); e.printStackTrace(); } } }
逻辑处理:
package org.demo; import java.util.Date; import net.sf.json.JSONObject; import org.apache.mina.common.IdleStatus; import org.apache.mina.common.IoHandlerAdapter; import org.apache.mina.common.IoProcessor; import org.apache.mina.common.IoSession; import org.apache.mina.transport.socket.nio.NioProcessor; import org.slf4j.Logger; import org.slf4j.LoggerFactory; public class Demo1ServerHandler extends IoHandlerAdapter{ public static Logger logger = LoggerFactory.getLogger(Demo1ServerHandler.class); /** * 这个方法当一个Session 对象被创建的时候被调用。对于TCP 连接来说,连接被接受的时候 * 调用,但要注意此时TCP 连接并未建立,此方法仅代表字面含义,也就是连接的对象 * IoSession 被创建完毕的时候,回调这个方法。 * 对于UDP 来说,当有数据包收到的时候回调这个方法,因为UDP 是无连接的。 */ @Override public void sessionCreated(IoSession session) throws Exception { logger.info("服务端与客户端创建连接..."); } /** * 这个方法在连接被打开时调用,它总是在sessionCreated()方法之后被调用。对于TCP 来 * 说,它是在连接被建立之后调用,你可以在这里执行一些认证操作、发送数据等。 */ @Override public void sessionOpened(IoSession session) throws Exception { logger.info("服务端与客户端连接打开..."); } /** * 接收到消息时调用的方法,也就是用于接收消息的方法,一般情况下,message 是一个 * IoBuffer 类,如果你使用了协议编解码器,那么可以强制转换为你需要的类型。 */ @Override public void messageReceived(IoSession session, Object message) throws Exception { /* String msg = message.toString(); //读取数据 logger.info("服务端接收到的数据为:" + msg+"客户端ip:"+session.getLocalAddress()); if ("bye".equals(msg)) { // 服务端断开连接的条件 session.close(); } Date date = new Date(); session.write(date);*/ JSONObject jsonObject = JSONObject.fromObject(message.toString()); String username; String sex; String qq; String score; String nickname; username = jsonObject.getString("username"); sex = jsonObject.getString("sex"); qq = jsonObject.getString("QQ"); score = jsonObject.getString("Min.score"); nickname = jsonObject.getString("nickname"); int state = login(username); String msg = "登录成功!"; if(state == 0){ msg = "登录失败!"; } logger.info("用户:" + username + msg); //模拟登陆 if ("bye".equals(nickname)) { // 服务端断开连接的条件 session.close(); } //Date date = new Date(); session.write(state); } //验证用户名 与 密码 public int login(String message){ if("sysadmin".equals(message)){ return 1; } return 0; } /** * 当发送消息成功时调用这个方法,注意这里的措辞,发送成功之后, * 也就是说发送消息是不能用这个方法的。 */ @Override public void messageSent(IoSession session, Object message) throws Exception { logger.info("服务端发送信息成功..."); } /** * 对于TCP 来说,连接被关闭时,调用这个方法。 * 对于UDP 来说,IoSession 的close()方法被调用时才会毁掉这个方法。 */ @Override public void sessionClosed(IoSession session) throws Exception { logger.info("服务端连接已经失效"); } /** * 这个方法在IoSession 的通道进入空闲状态时调用,对于UDP 协议来说,这个方法始终不会 * 被调用。 */ @Override public void sessionIdle(IoSession session, IdleStatus status) throws Exception { logger.info("服务端进入空闲状态..."); } /** * 这个方法在你的程序、Mina 自身出现异常时回调,一般这里是关闭IoSession。 */ @Override public void exceptionCaught(IoSession session, Throwable cause) throws Exception { logger.error("服务端发送异常...", cause); } }
客户端代码:
package org.demo; import java.net.InetSocketAddress; import java.nio.charset.Charset; import java.util.Timer; import java.util.TimerTask; import org.apache.mina.common.ConnectFuture; import org.apache.mina.common.IoConnector; import org.apache.mina.common.IoSession; import org.apache.mina.filter.codec.ProtocolCodecFilter; import org.apache.mina.filter.codec.textline.LineDelimiter; import org.apache.mina.filter.codec.textline.TextLineCodecFactory; import org.apache.mina.transport.socket.nio.NioSocketConnector; import org.json.JSONException; import org.json.JSONObject; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import android.app.Activity; import android.content.Context; import android.os.Bundle; import android.os.Handler; import android.os.HandlerThread; import android.os.Message; import android.view.View; import android.view.View.OnClickListener; import android.widget.Button; import android.widget.EditText; import android.widget.Toast; /** * @author wangmiao * @version 创建时间:2012-4-24 下午10:57:53 简单说明 */ public class HelloWorld2 extends Activity { private static Logger logger = LoggerFactory.getLogger(HelloWorld2.class); private static String HOST = "192.168.1.100"; private static int PORT = 8989; private static String LOGIN_NAME = ""; public HelloWorld2() { } Handler handler = new Handler(); @Override protected void onCreate(Bundle savedInstanceState) { // TODO Auto-generated method stub super.onCreate(savedInstanceState); setContentView(R.layout.main); System.out.println(1); /* * new Thread() { public void run() { socketServer(); } }.start(); */ Button btn = (Button) findViewById(R.id.button1); btn.setOnClickListener(new OnClickListener() { EditText name = (EditText) findViewById(R.id.username); @Override public void onClick(View v) { // TODO Auto-generated method stub //name.setText("sysadmin"); 设置初始值 final Handler myHandler = new Handler(){ int i = 0; @Override public void handleMessage(Message msg) { //该线程位于主线程 // TODO Auto-generated method stub //如果该消息是本程序所发送的 if(msg.what == 0x1233){ //主线程里面 显示操作 i++; showToast("第"+i+"次连接开始...."); } } }; //定义一个计时器,让该计时器周期性的执行指定任务 TimerTask对象的本质就是启动一条新线程 new Timer().schedule(new TimerTask() { @Override public void run() { //新启动的线程无法访问该Activity里的组件 //所以需要通过Handler发送消息 // TODO Auto-generated method stub Message msg = new Message(); msg.what = 0x1233; //发送消息 myHandler.sendMessage(msg); LOGIN_NAME = name.getText().toString(); //在子线程里面发送请求 socketServer(); } },0,10000); // /*// 压力测试 10s秒钟 执行一次 while(true){ new Thread(){ public void run(){ socketServer(); } }.start(); try { Thread.sleep(10000); } catch (InterruptedException e) { // TODO Auto-generated catch block e.printStackTrace(); } }*/ } }); System.out.println(1000); } public void showToast(final String text) { handler.post(new Runnable() { @Override public void run() { Toast.makeText(getApplicationContext(), text, Toast.LENGTH_SHORT).show(); } }); } public void socketServer() { // 创建一个非阻塞的客户端程序 System.out.println(2); IoConnector connector = new NioSocketConnector(); // 设置链接超时时间 System.out.println(3); connector.setConnectTimeout(5); System.out.println(4); // 添加过滤器 connector.getFilterChain().addLast( "codec", new ProtocolCodecFilter(new TextLineCodecFactory(Charset .forName("UTF-8"), LineDelimiter.WINDOWS.getValue(), LineDelimiter.WINDOWS.getValue()))); // 添加业务逻辑处理器类 connector.setHandler(new Demo1ClientHandler()); IoSession session = null; try { System.out.println(5); System.out.println(HOST + "|" + PORT); // 这里是异步操作 连接后立即返回 ConnectFuture future = connector.connect(new InetSocketAddress( HOST, PORT));// 创建连接 System.out.println(6); future.awaitUninterruptibly();// 等待连接创建完成 System.out.println(7); session = future.getSession();// 获得session // session.setAttribute(arg0, arg1) String jsonStr = "{\"people\":[" + "{ \"firstName\": \"问你t\", \"lastName\":\"McLaughlin\",\"email\": \"aaaa\" } ," + "{ \"firstName\": \"Brett\", \"lastName\":\"McLaughlin\",\"email\": \"aaaa\" } ,] } "; JSONObject json = createJSONObject(); // 根据key返回一个字符串 // //String username = json.getString("username"); // System.out.println("username==>"+username); System.out.println(8); session.write(json);// 发送消息 System.out.println(9); session.getCloseFuture().awaitUninterruptibly();// 等待连接断开 connector.dispose(); System.out.println(Demo1ClientHandler.ini); showToast(Demo1ClientHandler.ini); } catch (Exception e) { showToast("客户端链接异常,请检查网络"); logger.error("客户端链接异常...", e); } } public static JSONObject createJSONObject() { JSONObject jsonObject = new JSONObject(); try { jsonObject.put("username", LOGIN_NAME); jsonObject.put("sex", "男"); jsonObject.put("QQ", "413425430"); jsonObject.put("Min.score", new Integer(99)); jsonObject.put("nickname", "梦中心境"); } catch (JSONException e) { // TODO Auto-generated catch block e.printStackTrace(); } return jsonObject; } }
逻辑处理:
package org.demo; import org.apache.mina.common.IdleStatus; import org.apache.mina.common.IoHandlerAdapter; import org.apache.mina.common.IoSession; import org.slf4j.Logger; import org.slf4j.LoggerFactory; public class Demo1ClientHandler extends IoHandlerAdapter { private static Logger logger = LoggerFactory .getLogger(Demo1ClientHandler.class); static String ini = ""; @Override public void messageReceived(IoSession session, Object message) throws Exception { System.out.println(message); System.out.println(11); String msg = message.toString(); String info = ""; if ("1".equals(msg)) { // session.close(); //用户登录成功 关闭连接 info = "登录成功"; } else { info = "登录失败"; } ini = info; session.setAttribute("state", info); session.close(); System.out.println(12); // final HelloWorld h = new HelloWorld(); // h.DisplayToast(info); logger.info("客户端接收到的信息为:" + msg); } @Override public void exceptionCaught(IoSession session, Throwable cause) throws Exception { logger.error("客户端发生异常...", cause); } @Override public void sessionCreated(IoSession arg0) throws Exception { // TODO Auto-generated method stub } @Override public void sessionIdle(IoSession arg0, IdleStatus arg1) throws Exception { // TODO Auto-generated method stub } /** * 这个方法在连接被打开时调用,它总是在sessionCreated()方法之后被调用。对于TCP 来 * 说,它是在连接被建立之后调用,你可以在这里执行一些认证操作、发送数据等。 */ @Override public void sessionOpened(IoSession arg0) throws Exception { logger.info("ok", "i am ready!"); System.out.println(6); } }