思路:使用Servlet3.0的AsyncContext将客户端请求响应保存起来,当服务端有数据变更时再响应,使用请求轮询的方式保持客户端和服务端的连接。
服务端tomcat7+ servlet3.0:
@WebServlet(urlPatterns = "/server",asyncSupported = true) public class MessageServer extends HttpServlet { // TODO 任务队列 ,还没实现 ConcurrentLinkedQueue<String> taskQueue = new ConcurrentLinkedQueue<String>(); //请求响应队列 ConcurrentLinkedQueue<AsyncContext> contextQueue = new ConcurrentLinkedQueue<AsyncContext>(); @Override protected void doGet(HttpServletRequest req, HttpServletResponse resp)throws ServletException, IOException { doPost(req, resp); } protected void doPost(final HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { request.setCharacterEncoding("UTF-8"); response.setCharacterEncoding("UTF-8"); String flag = request.getParameter("flag"); String task = StringUtil.Stream2String(request.getInputStream()); System.out.println(task); if(StringUtil.NotEmpty(flag)){ //客户端有数据发送过来 if("client".equals(flag)&&StringUtil.NotEmpty(task)){ // taskQueue.offer(task); push(task); }else if("receiver".equals(flag)){ //响应客户端 response.getWriter().flush(); final AsyncContext asyncContext = request.startAsync(); new Thread(){ public void run() { asyncContext.setTimeout(0); contextQueue.offer(asyncContext); System.out.println("现有接收方:"+contextQueue.size()); }; }.start(); } } } /** * 从响应请求队列取出响应对象,逐一响应 * @param task * @throws IOException */ private synchronized void push(String task) throws IOException { while(!contextQueue.isEmpty()){ AsyncContext asyncContext = contextQueue.poll(); HttpServletResponse response = (HttpServletResponse) asyncContext.getResponse(); response.getWriter().println(task); response.setStatus(HttpServletResponse.SC_OK); asyncContext.complete(); } } }
接收端(android客户端):
=========MasycTask.java 异步任务类===========
public class MasyncTask extends AsyncTask<URL,String, Void> { TextView info; boolean flag; HttpURLConnection conn; public MasyncTask(TextView info) { this.info = info; } protected Void doInBackground(URL... urls) { try { HttpURLConnection conn = (HttpURLConnection) urls[0].openConnection(); conn.setConnectTimeout(5000); this.conn = conn; if(conn.getResponseCode()==HttpURLConnection.HTTP_OK){ if(!flag){ publishProgress("成功连接服务器!"); flag = true; } //将服务端返回的信息发送到前台方法 String string = StringUtil.Stream2String(conn.getInputStream()); if(StringUtil.NotEmpty(string)){ publishProgress(string); } doInBackground(urls); } } catch (IOException e) { publishProgress("网络连接异常!"+e.getMessage()); } return null; } protected void onProgressUpdate(String... values) { info.append(values[0]+"\n"); } public void mCancel(){ conn.disconnect(); conn = null; } }
===========MainActivity.java================
public class MainActivity extends Activity { TextView info; MasyncTask asyncTask; public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); info = (TextView) findViewById(R.id.info); try { asyncTask = new MasyncTask(info); asyncTask.execute(new URL("http://192.168.1.100:8080/MessageServer/server?flag=receiver")); } catch (MalformedURLException e) { info.append("URL解析异常!\n"); } } @Override protected void onDestroy() { //中断连接 asyncTask.mCancel(); super.onDestroy(); } }
发送端( android客户端):
==========MTask.java========
public class Mtask extends AsyncTask<String, Void,String> { EditText msg; Context context; public Mtask(EditText msg,Context context) { this.msg = msg; this.context = context; } protected String doInBackground(String... strUrl) { String result=null; try { String string = msg.getText().toString(); if(StringUtil.NotEmpty(string)){ HttpPost method = new HttpPost(strUrl[0]); HttpConnectionParams.setConnectionTimeout(method.getParams(),5000); HttpEntity entity = new StringEntity(string,"UTF-8"); method.setEntity(entity); //执行请求,如果中途想终止请求可以使用abort() HttpResponse response = new DefaultHttpClient().execute(method); if(response.getStatusLine().getStatusCode() == HttpStatus.SC_OK){ result = "发送成功!"; } } } catch (IOException e) { result = "网络连接异常!"+e.getMessage(); } return result; } protected void onPostExecute(String result) { Toast.makeText(context,result,Toast.LENGTH_SHORT).show(); } }
============MainActivity.java=============
public class MainActivity extends Activity { EditText msg; public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); msg = (EditText) findViewById(R.id.msg); } public void sendMsg(View v){ new Mtask(msg,this).execute("http://192.168.1.100:8080/MessageServer/server?flag=client"); } }