《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; } @Override public 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 block e.printStackTrace(); } attempts--; } _myLog.l(Log.DEBUG, "Creating server thread"); _serverThread = new Thread(this); _serverThread.start(); return super.onStartCommand(intent, flags, startId); } @Override public 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 block e.printStackTrace(); } UiUpdater.updateClients(); _myLog.d("WebService.onDestroy() finished"); } @Override public IBinder onBind(Intent intent) { return null; } @Override public 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); } }
监听到了HTTP的请求后,需要对其进行处理以作出响应,具体请看下一篇。
转载请注明出处:Android版Web服务器实现(二)使用服务来监听HTTP请求
源码下载