Android教程網
  1. 首頁
  2. Android 技術
  3. Android 手機
  4. Android 系統教程
  5. Android 游戲
 Android教程網 >> Android技術 >> 關於Android編程 >> Android搭建WEB Server—boa(二)

Android搭建WEB Server—boa(二)

編輯:關於Android編程

Android搭建WEB Server—boa(二)

上一篇只是對於移植boa的基本講解,在移植過程中,會出現很多問題。上文已經說明了如何去修改源碼和boa.conf文件,而使我們通過編譯。目前,我們要做的事情是:執行CGI程序。這個CGI程序有點特殊,它要調用system()函數,來運行一個腳本文件。這就要求它所需要的執行權限必須為root,因為如果不是root用戶,調用system()執行腳本是不通過的。即使這個腳本文件的權限為777,仍舊會提示Permission denied。

1 CGI程序


CGI(Common Gateway Interface)公共網關接口。這裡不詳細介紹CGI,有興趣的可以搜索一下CGI和fastCGI,資料很多,不怕找不到。推薦一個CGI的資料,很詳細,寫的很好。http://www.jdon.com/idea/cgi.html
簡單說下我對CGI的理解:CGI不能算一段程序,在B/S架構中,它運行在Server端,接收來自WEB服務器的數據,將處理結果返還給WEB服務器。它可以使用任何一種語言開發,在嵌入式領域,C/C++無疑是最快的、最合適的。下面是我的CGI程序。

#include "stdio.h"
#include "stdlib.h"
#include "string.h"
int main()
{
    char msg[100];
    memset(msg,0,100);
    fgets(msg,sizeof(msg),stdin);
    system("sh ./test.sh"); //test.sh僅僅是用來傳建test.txt文件的腳本。

    puts("\n");
    puts("");
    puts("");
    puts("");
    puts("");

    puts("");
    printf("%s\n",msg);
    puts("");

    puts("");
return 0;
}

2 HTML主頁


上文中需要一個index.html文件,充當主頁。本文要比之前高深一點,但實際上,稍微懂點html知識,就能寫一個簡單的交互頁面。主要是需要與CGI程序進行數據的交接。下面是我的index.html。

Login


目的IP 目的端口 攝像機IP  

3 調試


問題1 不能執行shell腳本

首先,進入Android系統shell。切換以root用戶登錄shell。在shell中啟動boa服務進程。用浏覽器訪問時,可以顯示主頁index.html,但是cgi程序並不能順利執行下去。上述中cgi程序調用了system()去執行test.sh腳本,創建test.txt文件。查看etc/boa/cgi-bin/目錄可知,並沒有生成test.txt。
搜索了網上的一些文章,大多與我的情況相悖。我在boa.conf中配置的是沒有問題的,可以查看一下我上篇文章,這裡就不加贅述了。最後才明白,出現這樣的錯誤是因為Permission denied。Android系統中,我在shell裡切換了root身份登錄啟動的boa,其實並沒有真的以root身份去運行boa這個進程。導致了我不能在cgi程序中執行腳本。請教了前輩,才發現這個問題的症結所在。慚愧……
解決的方法:在init.rc中以root身份啟動boa。

問題2 boa開機不能啟動

首先來說說init.rc。init.rc是管理Android系統開啟啟動項的文件,init.rc是必須要在源碼中更改的,它被做成ramdisk.img的一部分。更改init.rc源碼,要重新用 mmm 命令編譯,並重新刷ramdisk.img。詳細的介紹請自行百度,不做贅述。我在init.rc文件追加(記住別tm寫在第一行,不靠譜!!!)了boa的啟動代碼。

......
/* 開機啟動boa */
service boa /system/bin/boa
    class main
    user root
......

編譯後,刷入ramdisk.img,修改權限等等。根據前輩建議,把etc/boa更換了路徑,改成/data/boa。相應的boa.conf文件中也更改一下配置路徑。弄好之後,本以為萬事大吉,搞定收工。可惜,bug總是不想我按時吃飯哪。
ps看了一下進程,發現boa壓根就沒啟動。想著是啟動出錯了,於是更改了一下init.rc,調試調試。

......
service boa /system/bin/logwrapper /system/bin/boa
    class mian
    user root
......

這條代碼是為了調試boa,他會將在啟動過程中出現的log輸出到logcat.log當中。
再次重啟後,導出logcat.log,發現boa報錯。

boa : Could not chdir to “etc/boa”:aborting
boa : boa terminated by exit(1)

原因很簡單,上面我將boa的目錄轉到了data下,特別是boa.conf文件不在etc/boa/下,而是在data/boa/下。這就得改boa源碼了。在boa/src/下,修改defines.h。

......
29 #ifndef SERVER_ROOT
30 #define SERVER_ROOT "/etc/boa" —> "/data/boa"
31 #endif
......

交叉編譯後,再次運行。嗯,至少不報前面的錯誤了。

問題3 boa啟動異常

之前解決了boa不能啟動,沒想到boa啟動異常了。具體的表現呢,就是logcat.log中沒有boa的錯誤輸出,但是boa的error_log中每隔五秒會寫入一次啟動的信息,包括進程號,端口等。進程號一直增大,端口號一直不變。ps查看時,卻找不到boa的進程。初步判斷是boa在init過程中出現了錯誤。boa處於啟動過程,但可能系統認為boa已經退出了,所以又重新啟動了boa,所以導致反復重啟,卻看不到進程。
這時,adb shell後,手動啟動boa,ps看啟動成功了,但是,error_log中有爆出了新錯誤。

boa : boa.c:194 - unable to bind: Address already in use
boa : boa.c:194 - unable to bind: Address already in use
boa : boa.c:194 - unable to bind: Address already in use

這玩意每隔5s出來一次,沒什麼特殊含義,就是端口復用了。可就是這端口復用,困擾了我兩天。按照網上的說法,Android卻是存在這種機制,端口可能要等待一段時間才能重新bind。使用setsockpot()函數可以實現端口的復用。聽起來很簡單哈,可惜,查看代碼中卻是已經使用了這個函數,仍然出現這個報錯。
然後,更改了init.rc的內容如下:

......
service boa /system/bin/boa
    class main
    user root
    oneshot  //表明此進程僅僅啟動一次,即使失敗也不會重啟
......

萬萬沒想到,這樣一來竟然絲毫沒出現問題。boa開機正常啟動,cgi程序正常運行,error_log也沒有再報錯。看到這裡,估計有些人已經明白boa錯誤的原因了。原因就是,boa在init過程中確實啟動了,但是出於某種原因,一號進程認為這個boa已經退出了,我要重新啟動它,所以造成了不斷地重啟。這時adb shell來啟動boa,就相當於有兩個進程都是boa,都在bind同一個端口,造成了端口被占用的報錯。
清楚了原因後,只能去查看源碼了。在源碼中有這麼一段:

......
    /* background ourself */
if (do_fork) {
        switch(fork()) {
        case -1:
            /* error */
            perror("fork");
            exit(1);
            break;
        case 0:
            /* child, success */
            break;
        default:
           /* parent, success */
            exit(0);
            break;
        }
    }
......

這段代碼的意思呢就是fork()了一個子線程去執行下面的,而父線程直接退出了。雖然我也不知道為什麼作者會加入這麼一段代碼,(時間問題,不深究,以後再說)但我想,這就是造成上面報錯的根本原因。在boa的init過程中,boa父線程退出時給一號進程發送了一個信號,它退出的信號。於是一號進程認為boa退出了,所以重新又起了一次boa,如此周而復始。分析之後,將這段代碼注釋掉即可。同時將oneshot去掉。我可以直接用父進程完成接下來的任務,而不需要fork()子線程。
至此,圓滿結束。

  1. 上一頁:
  2. 下一頁:
熱門文章
閱讀排行版
Copyright © Android教程網 All Rights Reserved