Android版Web服务器实现(二)使用服务来监听HTTP请求

来源:互联网 发布:阿里云邮箱故障 编辑:程序博客网 时间:2024/06/05 02:20

Android版Web服务器实现(一)HTTP协议请求头解析》一文中说到了HTTP协议请求头的解析,那么我们要如何得到这个HTTP请求头呢?我们需要监听端口。监听是一直要运行着的,在Android中比较好的方式就是使用服务。下面是实现的代码。

WebServer.java

package com.sparkle.webservice;import java.io.IOException;import java.net.InetAddress;import java.net.InetSocketAddress;import java.net.ServerSocket;import android.app.Service;import android.content.Context;import android.content.Intent;import android.net.wifi.WifiManager;import android.os.IBinder;import android.util.Log;import com.sparkle.kits.IP;public class WebServer extends Service implements Runnable {private static boolean _isRunning = false;private static Thread _serverThread = null;private ServerSocket _listenSocket = null;private MyLog _myLog = new MyLog(getClass().getName());private static int _port = Defaults.getPort();private TcpListener _tcpListener = null;private static final int WAKE_INTERVAL_MS = 1000;public WebServer() {try {Init();} catch (IOException e) {e.printStackTrace();}}private void Init() throws IOException {_listenSocket = new ServerSocket();_listenSocket.setReuseAddress(true);_listenSocket.bind(new InetSocketAddress(_port));}public static void Start(Context context) {if (!_isRunning) {_isRunning = true;Intent intent = new Intent(context, WebServer.class);context.startService(intent);}}public static void Stop(Context context) {if (_isRunning) {_isRunning = false;Intent intent = new Intent(context, WebServer.class);context.stopService(intent);}}public static boolean isRunning() {return _isRunning;}@Overridepublic int onStartCommand(Intent intent, int flags, int startId) {int attempts = 10;// The previous server thread may still be cleaning up,// wait for it to finish.while (_serverThread != null) {_myLog.l(Log.WARN, "Won't start, server thread exists");if (attempts <= 0) {_myLog.l(Log.ERROR, "Server thread already exists");return super.onStartCommand(intent, flags, startId);}try {Thread.sleep(1000);} catch (InterruptedException e) {// TODO Auto-generated catch blocke.printStackTrace();}attempts--;}_myLog.l(Log.DEBUG, "Creating server thread");_serverThread = new Thread(this);_serverThread.start();return super.onStartCommand(intent, flags, startId);}@Overridepublic void onDestroy() {if (_tcpListener != null) {_tcpListener.quit();}_myLog.l(Log.INFO, "onDestroy() Stopping server");if (_serverThread == null) {_myLog.l(Log.WARN, "Stopping with null serverThread");return;}_serverThread.interrupt();try {_serverThread.join(10000); // wait 10 second for server thread to// finish} catch (InterruptedException e) {}if (_serverThread.isAlive()) {_myLog.l(Log.WARN, "Server thread failed to exit");} else {_myLog.d("serverThread joined ok");_serverThread = null;}try {if (_listenSocket != null) {_listenSocket.close();}} catch (IOException e) {// TODO Auto-generated catch blocke.printStackTrace();}UiUpdater.updateClients();_myLog.d("WebService.onDestroy() finished");}@Overridepublic IBinder onBind(Intent intent) {return null;}@Overridepublic void run() {// Server thread run.while (_isRunning) {UiUpdater.updateClients();if (_tcpListener == null) {_tcpListener = new TcpListener(_listenSocket, this);_tcpListener.start();}try {Thread.sleep(WAKE_INTERVAL_MS);} catch (InterruptedException e) {_myLog.l(Log.DEBUG, "Thread interrupted");}}}public static InetAddress getWifiIp(Context context) {if (context == null) {throw new NullPointerException("Global context is null");}WifiManager wifiManager = (WifiManager) context.getSystemService(Context.WIFI_SERVICE);if (!wifiManager.isWifiEnabled()) {return null;}int ipAsInt = wifiManager.getConnectionInfo().getIpAddress();if (ipAsInt == 0) {return null;} else {return IP.intToInet(ipAsInt);}}public static int getPort() {return _port;}}
注:

1、WebServer继承自Service,内部套了一个服务的线程,所以又实现了Runnable接口。

2、重载onStartCommand方法,在该方法中启动服务线程_serverThread。在启动时,进行探测,以确保前一次启动的_serverThread已经关闭。

3、重载onDestroy方法,在该方法中关闭服务线程。

4、在run方法中,启用监听_tcpListener。TcpListener是一个封装的类,具体参看后面的代码。

5、附上getWifiIp和getPort方法,以方便调用。

6、UiUpdater是一个界面更新器,具体的请参看后文的代码。

7、服务需要在AndroidManifest.xml中注册,注册部分代码如下。

AndroidManifest.xml部分代码

   <application        android:allowBackup="true"        android:icon="@drawable/ic_launcher"        android:label="@string/app_name"        android:theme="@style/AppTheme" >        <activity            android:name="com.sparkle.webservice.MainActivity"            android:label="@string/app_name" >            <intent-filter>                <action android:name="android.intent.action.MAIN" />                <category android:name="android.intent.category.LAUNCHER" />            </intent-filter>        </activity>        <service android:name="com.sparkle.webservice.WebServer" />    </application>



TcpListener.java

package com.sparkle.webservice;import java.net.ServerSocket;import java.net.Socket;import android.util.Log;public class TcpListener extends Thread {private ServerSocket _listenSocket = null;private MyLog _myLog = new MyLog(getClass().getName());public TcpListener(ServerSocket listenSocket, WebServer webServer) {this._listenSocket = listenSocket;}public void quit() {try {_listenSocket.close(); // if the TcpListener thread is blocked on// accept,// closing the socket will raise an// exception} catch (Exception e) {_myLog.l(Log.DEBUG, "Exception closing TcpListener listenSocket");}}public void run() {try {while (true) {Socket clientSocket = _listenSocket.accept();_myLog.l(Log.INFO, "New connection, spawned thread");SessionThread newSession = new SessionThread(clientSocket);newSession.start();}} catch (Exception e) {_myLog.l(Log.DEBUG, "Exception in TcpListener");}}}
注:

1、在run中使用accept的阻塞方法来监听。

2、在收到请求后,放到SessionThread中去处理,该部分代码请参看后文。

3、MyLog是自定义的一个日志类。

MyLog.java

package com.sparkle.webservice;import android.util.Log;public class MyLog {protected String tag;public MyLog(String tag) {this.tag = tag;}public void l(int level, String str, boolean sysOnly) {synchronized (MyLog.class) {str = str.trim();Log.println(level, tag, str);}}public void l(int level, String str) {l(level, str, false);}public void e(String s) {l(Log.ERROR, s, false);}public void w(String s) {l(Log.WARN, s, false);}public void i(String s) {l(Log.INFO, s, false);}public void d(String s) {l(Log.DEBUG, s, false);}}

注:日志输出时使用synchronized来确保日志的输出。

监听到了HTTP的请求后,需要对其进行处理以作出响应,具体请看下一篇。

转载请注明出处:Android版Web服务器实现(二)使用服务来监听HTTP请求

源码下载

0 0
原创粉丝点击