zoukankan      html  css  js  c++  java
  • Android版Web服务器实现(二)使用服务来监听HTTP请求

    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请求

    源码下载

  • 相关阅读:
    20165314《网络对抗技术》week1 Exp0 Kali安装
    20165301 20165304 20165314《信息安全系统设计基础》实验五通讯协议设计
    2018-2019-1 20165314《信息安全系统设计基础》第九周学习总结
    2018-2019-1 20165301 20165304 20165314 实验四 外设驱动程序设计
    2018-2019-1 20165314《信息安全系统设计基础》第八周学习总结
    2018-2019-1 20165301 20165304 20165314 实验三 实时系统
    2018-2019-1 20165314 《信息安全系统设计基础》第七周学习总结
    2018-2019-1 20165301 20165304 20165314 实验二 固件程序设计
    2018-2019-1 20165314 《信息安全系统设计基础》第六周学习总结
    2018-2019-1 20165314《信息安全系统设计基础》第五周学习总结
  • 原文地址:https://www.cnblogs.com/sparkleDai/p/7605026.html
Copyright © 2011-2022 走看看