2012年12月12日 星期三

Ubuntu - 操作Tomcat

在Ubuntu安裝好Tomcat後,可以利用終端機輸入指令,啟動或關閉Tomcat,例如:
  啟動: /etc/init.d/tomcat7 start
  停止: /etc/init.d/tomcat7 stop
重新啟動: /etc/init.d/tomcat7 restart
要能做到這些動作,必須要先寫shell script。Tomcat安裝好後會有已寫好的startup.sh和shutdown.sh,再來是要在/etc/init.d/新增一個tomcat7的檔案,檔案內容為:
#這裡是使用j2ee的java library,請依據個人安裝版本和路徑做更動
export JAVA_HOME=/home/minimum/glassfish3/jdk7
case $1 in
start)
  #請依據個人安裝路徑做更動
  sh /usr/share/tomcat7/bin/startup.sh
  ;;
stop)
  #請依據個人安裝路徑做更動
  sh /usr/share/tomcat7/bin/shutdown.sh
   ;;
restart)
  #請依據個人安裝路徑做更動
  sh /usr/share/tomcat7/bin/shutdown.sh
  sh /usr/share/tomcat7/bin/startup.sh
  ;;
esac
exit 0
 存檔後,就能利用上述指令啟動或關閉Tomcat。

2012年11月1日 星期四

C++ - 建立process執行外部程式

目的:建立一個process,並執行外部程式。
要求:視窗隱藏,輸出重新導向到指定的檔案。
// Setting security for output handle (necessary)
SECURITY_ATTRIBUTES sa;
memset(&sa, 0, sizeof(SECURITY_ATTRIBUTES));
sa.nLength = sizeof(sa);
sa.lpSecurityDescriptor = NULL;
sa.bInheritHandle = TRUE;

// Setting output handle
HANDLE hConsoleRedirect = CreateFile((L"out.txt").c_str(), GENERIC_WRITE|GENERIC_READ, FILE_SHARE_WRITE|FILE_SHARE_READ|FILE_SHARE_DELETE, &sa, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL);
if(hConsoleRedirect == INVALID_HANDLE_VALUE) return;

// Setting console standup info
STARTUPINFO si;
memset(&si, 0, sizeof(STARTUPINFO));
si.cb = sizeof(si);
si.dwFlags = STARTF_USESTDHANDLES | STARTF_USESHOWWINDOW;
si.wShowWindow = SW_HIDE;
si.hStdOutput = hConsoleRedirect;
si.hStdError = hConsoleRedirect;

// Setting process info
PROCESS_INFORMATION pi;
memset(&pi, 0, sizeof(PROCESS_INFORMATION));       

// Excute command
wstring cmd = L"program.exe -argument";
bool bResult = CreateProcess(NULL, (LPWSTR) cmd.c_str(), NULL, NULL, TRUE, CREATE_NEW_CONSOLE|CREATE_UNICODE_ENVIRONMENT, NULL, NULL, &si, &pi);
DWORD ret = WaitForSingleObjectEx(pi.hProcess, INFINITE, FALSE);

// Close handles
CloseHandle(hConsoleRedirect);
CloseHandle(pi.hProcess);
CloseHandle(pi.hThread);

2012年9月25日 星期二

移除目錄(包含目錄下所有檔案和資料夾)

各家程式語言都有自己的function可以移除目錄或檔案,像boost C++有remove()和remove_all()可以使用。雖然呼叫function很方便,但若遇到要移除的目錄結構非常龐大時,很有可能會把heap塞爆。在這邊提供一個不一樣的解決方法:「呼叫系統指令 。 」

Windows系統有個指令叫做rmdir,Linux系統則是rm,這兩個指令加上參數就可以做到移除目錄以及目錄下所有檔案和資料夾的功能。

呼叫系統指令的好處是可以忽略例外發生,也不會佔用到程式的heap,簡單的說就是避免程式當掉。不要認為用系統指令的程式水準低,「能簡單解決問題的方法就是好方法!」

C++ - 字串大小寫轉換

字串大小寫轉換是在讀取檔案或使用者輸入文字時,常需要做的處理,沒想到我竟然會在別人的程式碼裡看到一種無言的寫法:
if ( !strcmp(p, ".pdf") || !strcmp(p, ".PDF") )
{
        ...
}
這段程式碼是判斷檔案是否為PDF,p是存放檔案名稱的字元陣列。這種判斷方法是一種很笨的寫法。

C++有strlwr(char * _str)函式可將字元陣列中的英文字母轉成小寫,而strupr(char * _str)函式則是轉成大寫,函式庫是string.h。C語言也有tolower(int c)和toupper(int c)可以使用,不過一次只能轉一個字元,要配合迴圈才能轉換字元陣列。

字串比對時,如果要忽略大小寫,C++有strcmpi(const char * _str1, const char * _str2)函式可以用。

2012年9月10日 星期一

C++ - 存取Windows機碼

作業系統:Windows 7
開發工具:Visual Studio 2010
程式語言:C/C++
程式功能:讀取與修改Windows機碼,範例是關閉Windows 7錯誤回報的顯示。
//HKEY_CURRENT_USER\Software\Microsoft\Windows\Windows Error Reporting
//"DontShowUI"=dword:00000001

#include <stdlib.h>
#include <Windows.h>
#include <atlconv.h>

long reg()
{
    HKEY hKey;
    long errorlevel = 0L;
    char* reg_video_path = "Software\\Microsoft\\Windows\\Windows Error Reporting"; // Registry path
    char* value_name = "DontShowUI"; // The key
    DWORD dwType = 0x00000000, dwSize = 0x00000000;
    DWORD data = 0x00000000;

    USES_CONVERSION;

    // Step 1: open key.
    errorlevel = RegOpenKeyExW(HKEY_CURRENT_USER, A2W(reg_video_path), 0, KEY_ALL_ACCESS, &hKey);
    if(errorlevel != ERROR_SUCCESS) return errorlevel;

    // Step 2: read size. (necessary)
    errorlevel = RegQueryValueEx(hKey, A2W(value_name), NULL, &dwType, NULL, &dwSize);
    if(errorlevel != ERROR_SUCCESS) return errorlevel;

    // Step 3: read value.
    errorlevel = RegQueryValueExW(hKey, A2W(value_name), NULL, &dwType, (LPBYTE)&data, &dwSize);
    if(errorlevel != ERROR_SUCCESS) return errorlevel;

    // TODO: set new data.

    // Step 4: set value.
    errorlevel = RegSetValueExW(hKey, A2W(value_name), 0, REG_DWORD, (const BYTE*)&data, sizeof(DWORD));
    if(errorlevel != ERROR_SUCCESS) return errorlevel;

    // step 5: close key.
    errorlevel = RegCloseKey(hKey);
    if(errorlevel != ERROR_SUCCESS) return errorlevel;

    return 0L;
}

Windows的版本不同,機碼名稱和值也可能不同,所以要針對作業系統的版本去寫。

2012年9月5日 星期三

Python - XML-RPC簡易實作

Python版本:3.2

最近在用XML-RPC實現server與client之間的互動,底下是簡單的訊息互傳範例:

Server端

#Python 2
#import SimpleXMLRPCServer
#Python 3
import xmlrpc.server

host = "127.0.0.1"
port = 1234

def handle(msg):
    #Python 2
    #print "Handle message: " + msg
    #Python 3
    print("Handle message: " + msg)

    ret = "Hello! I have received your message."
    return ret

def main():
    #Python 2
    #server = SimpleXMLRPCServer.SimpleXMLRPCServer((host, port))
    #Python 3
    server = xmlrpc.server.SimpleXMLRPCServer((host, port))

    server.register_function(handle)
    server.serve_forever()

if __name__ == "__main__":
    main()

Client端

#Python 2
#import xmlrpclib
#Python 3
import xmlrpc.client

host = "http://127.0.0.1:1234"

def main():
    #Python 2
    #server = xmlrpclib.ServerProxy(hots)
    #Python 3
    server = xmlrpc.client.ServerProxy(host)

    result = server.handle("Welcome.")

    #Python 2
    #print result
    #Python 3
    print(result)

if __name__ == "__main__":
    main()

有一些地方要注意:
  1. Python 2和Python 3的xmlrpc library不同,範例裡有用註解表示Python 2的寫法。
  2. Python 2和Python 3的print也不同。
  3. SimpleXMLRPCServer()的參數是tuple型態,host要給字串,port要給整數。
  4. server的host設定為127.0.0.1,client就只能連線到127.0.0.1;換句話說,server的host若設定成192.168.1.1,client即使在本機,也不能透過127.0.0.1連線,只能連線到192.168.1.1。
  5. client端呼叫一次server端的handle(),socket連線即結束;要再次呼叫的話,要再執行一次ServerProxy()。
  6. server端可以一次註冊多個function。
  7. serve_forever()要放在最後面呼叫,因為呼叫完即進入server的main routine。

Windows - 工作排程

作業系統:Windows 7

桌面環境下,要設定工作排程可以從「開始」→「附屬應用程式」→「系統工具」→「工作排程器」,也可以從「控制台」→「系統管理工具」→「工作排程器」。

如果想從命令提示字元視窗設定工作排程,命令格式為:
增加:SCHTASKS /Create [參數]
刪除:SCHTASKS /Delete [參數]
 舉例來說,設定每天中午12點自動執行記事本:
SCHTASKS /Create /SC DAILY /TN NewTaskName /TR "%windir%\system32\notepad.exe" /ST 12:00
 刪除工作則是:
SCHTASKS /Delete /TN NewTaskName /F
 要查詢其他參數設定請參考:Windows - Schtasks.exe

2012年8月27日 星期一

Ubuntu - 環境變數

編輯系統變數:
$sudo vi /etc/environment

編輯使用者變數:
$sudo vi /etc/profile

重新載入環境變數:
source /etc/profile
source /etc/environment

2012年8月15日 星期三

Ubuntu - 強制關閉無回應程式

作業系統:Ubuntu 12.04

查詢系統正在運作的程式:
$ps aux
搜尋要找的程式:(例如notepad)
$ps aux|grep notepad
強制關閉程式:(例如notepad++)
$killall notepad++

Ubuntu - 安裝Java

作業系統:Ubuntu Server 12.04
應用程式:Oracle Java JDK 1.7.0

  1. 先到Java SE Downloads下載最新版的JDK,選擇tar.gz的版本。 (範例:jdk-7u6-linux-i586.tar.gz)
  2. 解壓縮到jdk1.7.0_06:
    tar -xvf ~/Downloads/jdk-7u6-linux-i586.tar.gz
  3. 建立JDK的新資料夾jdk1.7.0:
    sudo mkdir -p /usr/lib/jvm/jdk1.7.0
  4. 將解完壓縮的檔案移到新資料夾jdk1.7.0:
    sudo mv jdk1.7.0_06/* /usr/lib/jvm/jdk1.7.0/
  5. 安裝執行命令:
    sudo update-alternatives --install "/usr/bin/java" "java" "/usr/lib/jvm/jdk1.7.0/bin/java" 1 
    sudo update-alternatives --install "/usr/bin/javac" "javac" "/usr/lib/jvm/jdk1.7.0/bin/javac" 1  
    sudo update-alternatives --install "/usr/bin/javaws" "javaws" "/usr/lib/jvm/jdk1.7.0/bin/javaws" 1
  6. 完成!

Joomla - 在Ubuntu系統的操作問題

作業系統:Ubuntu Server 12.04
應用程式:Joomla 2.5.4

事件狀況:
安裝module、plug-in或更新版本發生失敗。

解決方法:
網站的存取路徑是放在root下的/var/www,存取權限需要root帳號。平常登入系統的帳號雖然是管理員,但並不是root帳號,需要使用sudo才能擁有root的帳號權限。Joomla透過網頁進行內容管理時,會更動路徑下的檔案,為了能夠讓安裝和更新等動作成功進行,需要先將檔案的操作權限進行變更:
$sudo chmod -R a+w /var/www/