您的位置:首页 > 理论基础 > 计算机网络

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

2014-03-11 10:35 666 查看
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);
}
}


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

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

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

源码下载
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: