Posts match “ java ” tag:

Socket是??

  • Socket最早緣起於Unix,而在Unix的檔案可以用開啟open -> 讀寫write/read -> 關閉close的模式來操作,所以Socket在Unix當中也遵循這樣的操作模式,算是一種文件,Socket所提供的API就是可以進行的操作(開啟/關閉、讀寫)。
  • 使用TCP/IP協定的程式都是採用Socket來進行連接傳輸的介面,最常見的例子就是網頁瀏覽器,底層都是用Socket去做連接通信的介面。
  • Socket架構圖解


Java Socket API

簡單了解Socket為何後,接著就要來看在Java當中程式怎麼寫了。Socket Programming採用Server/Client(以下簡稱S/C架構)的架構來實作,所以下面列出幾個簡單觀念先了解後會更快上手:

  • S/C架構下的程式進行通訊,Server端需要提供一個固定位置(一個IP:Port或Domain Name),Client要連接就要先知道這位置。
  • 在Java當中S/C架構就是對應到ServerSocketSocket兩個物件,Server端用ServerSocket.listen()來監聽Client端,Client端用Socket和Server端做連接,Server端用ServerSocket.accept()來取得和Client端連線的Socket物件。
  • 當Server和Client連接後,就可以用socket.getInputStream()socket.getOutputStream()來做資料的讀寫傳輸。
  • 最後資料傳遞完後,記得要呼叫socket.close()來關閉所有使用到的Sockets。

程式碼

Server端

public class Server
{
    public static final int LISTEN_PORT = 5987;
    
    public void listenRequest()
    {
        ServerSocket serverSocket = null;
        ExecutorService threadExecutor = Executors.newCachedThreadPool();
        try
        {
            serverSocket = new ServerSocket( LISTEN_PORT );
            System.out.println("Server listening requests...");
            while ( true )
            {
                Socket socket = serverSocket.accept();
                threadExecutor.execute( new RequestThread( socket ) );
            }
        }
        catch ( IOException e )
        {
            e.printStackTrace();
        }
        finally
        {
            if ( threadExecutor != null )
                threadExecutor.shutdown();
            if ( serverSocket != null )
                try
                {
                    serverSocket.close();
                }
                catch ( IOException e )
                {
                    e.printStackTrace();
                }
        }
    }
    
    /**
     * @param args
     */
    public static void main( String[] args )
    {
        Server server = new Server();
        server.listenRequest();
    }
    
    /**
     * 處理Client端的Request執行續。
     *
     * @version
     */
    class RequestThread implements Runnable
    {
        private Socket clientSocket;
        
        public RequestThread( Socket clientSocket )
        {
            this.clientSocket = clientSocket;
        }
        
        /* (non-Javadoc)
         * @see java.lang.Runnable#run()
         */
        @Override
        public void run()
        {
            System.out.printf("有%s連線進來!\n", clientSocket.getRemoteSocketAddress() );
            DataInputStream input = null;
            DataOutputStream output = null;
            
            try
            {
                input = new DataInputStream( this.clientSocket.getInputStream() );
                output = new DataOutputStream( this.clientSocket.getOutputStream() );
                while ( true )
                {
                    output.writeUTF( String.format("Hi, %s!\n", clientSocket.getRemoteSocketAddress() ) );
                    output.flush();
                    // TODO 處理IO,這邊定義protocol協定!!

                    break;
                }
            }
            catch ( IOException e )
            {
                e.printStackTrace();
            }
            finally 
            {
                try
                {
                    if ( input != null )
                        input.close();
                    if ( output != null )
                        output.close();
                    if ( this.clientSocket != null && !this.clientSocket.isClosed() )
                        this.clientSocket.close();
                }
                catch ( IOException e )
                {
                    e.printStackTrace();
                }
            }
        }
    }
}

Client端

public class Client
{
    public static void main( String[] args ) throws IOException
    {
        String host = "";
        int port = 5987;
        Socket socket = null;
        Scanner consoleInput = new Scanner( System.in );
        System.out.println("請輸入Server端位址");
        host = consoleInput.nextLine();
        try
        {
            socket = new Socket( host, port );
            DataInputStream input = null;
            DataOutputStream output = null;
            
            try
            {
                input = new DataInputStream( socket.getInputStream() );
                output = new DataOutputStream( socket.getOutputStream() );
                while ( true )
                {
                    System.out.println( input.readUTF() );
                    break;
                }
            }
            catch ( IOException e )
            {
            }
            finally 
            {
                if ( input != null )
                    input.close();
                if ( output != null )
                    output.close();
            }
        }
        catch ( IOException e )
        {
            e.printStackTrace();
        }
        finally
        {
            if ( socket != null )
                socket.close();
            if ( consoleInput != null )
                consoleInput.close();
        }
    }
}

程式解說

  • ServerSocket serverSocket = new ServerSocket( port )當中的port使用上必須是唯一的,因為port是用來辨識電腦上每個獨立的服務,每個不同的服務所使用的port就會不同,可用的port範圍從0~65536,前1024個port是TCP/IP欲留著給一些特定協定使用(例如:HTTP=80, FTP=21),所以程式的port只能使用大於1024之後的整數。
  • Server端採用允許多個Client端連接的簡單多執行緒連線架構,其思路為每一個Client連線就用一個執行緒來處理,在ServerSocket.accept()呼叫後會回傳一個和目前Client連線的Socket,我們將此Socket傳遞給執行緒做後續的處理,而ServerSocket可以繼續listen()來達到多個Client連接的架構。
  • 程式當中是使用DataInput/OutputStream來處理IO資料傳遞,當然你可以照你的需求來使用不同的IO Stream。
  • 取得IO Stream後就可以依照你所定義的protocol來做資料的傳遞,程式當中是Server端回傳一個訊息給Client端,然後Client端取得後印出。

學生時期的一些程式作品集,整理一下拿出來獻醜 >///<(以下圖多!!)。
主要是用Java寫的,當然還有含Android和Python,而應用主要有資料庫、網路爬蟲、Socket Programming、機器學習應用、演算法設計...等等項目。

以下是簡單列表(照完成時間排序):

  • Gmail Man - Gmail客戶端,可以跟本機端資料庫做同步更新。
  • 餐飲熱量計算程式 - 學校專題(補)飲食熱量資料庫應用。
  • 股市交易資料爬蟲 - 網路爬蟲可以抓每日股市的交易資料。
  • 圖片下載程式 - 輸入關鍵字,可以自動下載搜尋到的所有圖片。
  • 樂透網路下注程式 -- 幫學弟寫的一個網路程式設計作業,半個小時內寫完。
  • 地址顯示服務 - 輸入一個網址,提取一個網頁正文並分析出地址,然後把所有地址顯示在網頁上。
  • 在地遊App - 一支可以查詢地點資訊、顯示照片和地圖的App。
  • 地點關鍵字提取引擎 - 利用文字分析技術自動提取出一個地點的關鍵字列表。
  • 地點自動分類器 - 實作一個分類演算法來將地點自動分類為景點、餐飲和住宿。

Gmail Man

這是校內「雲端程式設計課程」的作業之一,題目是用抽的,我抽中用Gmail Contact API去寫一個應用程式,我就簡單做一個Gmail的客戶端。

功能

Gmail的客戶端,可以直接編輯通訊錄的資料,並且可以跟本機端的資料庫做同步備份。

所用技術


餐飲熱量計算程式

這程式是我的學校畢業專題,因為我大四休學,所以原本一年的專題中斷(做臉部器官偵測,是影像處理的應用),後來復學後就做這個簡單的應用當作畢業專題。

功能

程式提供各種餐飲的熱量資訊,使用者可以點選三餐所吃的餐點即可立刻計算當天攝取的熱量總和;或者可以輸入熱量和一些限制(例如:低脂、素食...等),程式會找出符合的餐飲。。

  • 主畫面1:使用者可以點選他今天三餐吃的餐點,程式就會幫忙計算今天攝取的總熱量是多少。 輸入熱量值和選擇限制,程式會幫你挑出符合的餐飲讓使用者選。

  • 主畫面2:可以直接檢視每個餐飲在資料庫的資料,必要的時候可以在程式登入資料庫然後編輯資料。

  • 主畫面3:或者更直接可以執行SQL指令和設定過濾器來做查詢資料。

所用技術


股市交易資料爬蟲

功能

這是一隻網路爬蟲,用來從網頁上抓每天股票買賣超的交易資料,並且把當日的前十名買賣超的公司+張數做成圖表顯示出來。

所用技術


圖片下載程式

功能

輸入關鍵字(例如:正妹),程式會自動幫你下載所有符合的圖片(使用Google搜尋結果)。

所用技術


樂透網路下注程式

幫學弟寫的作業程式,30分鐘搞定。

這是一個Network Socket Program,Server端可以等待多個Client來連線下單,然後接著時間截止後,Server端會停止繼續下注,並且把中獎號碼送到Client端,如果Client端接受後有中獎,則會顯示。

所用技術


地址顯示服務

功能

此網頁服務允許使用者輸入一個網頁,後端會分析出網頁正文後並且使用文字分析提取出所有地址,接著把地址標註在地圖上。 此服務主要目的在於當我們瀏覽一個美食部落格時,該文章當中可能列舉一個區域的所有美食,我們就可以在地圖上一次瀏覽所有美食店家的位置。

所用技術


在地遊App

功能

此App可以用來查詢和編輯地點資料,顯示該地點的照片和拍新照片並上傳,顯示地圖位置。

所用技術


地點關鍵字提取引擎

功能

此文字探勘引擎使用字詞加權技術,以每個地點的部落格文章作為分析來源,找出屬於該地點的關鍵字並且計算出該字詞和該地點的相關程度。如下圖所示,使用了四種不同的字詞加權計算公式來計算,我們可以比較不同的公式所算出來的精準度並且衡量計算速度。

所用技術


地點自動分類器

功能

此程式使用KNN分類演算法來將地點以它所有的部落格作為分析來源來自動分類為景點、餐飲和住宿。

所用技術

  • KNN分類演算法
  • KNN分類演算法加速器

需求

  • 輸入日期字串(或java.util.Date),可以輸出對應是星期幾。
  • 輸出可以依照各程式的資料結構需求而改變,可以輸出字串、enum類別或其他自己定義的資料結構。
  • 例如:輸入「2014-03-17」,輸出將會是「星期一」或「1」。

思路

  • 善用java.text.DateFormatjava.util.Calendar兩個類別搭配服用即可達成。
  • 這邊因為輸出可以依照資料結構需求而變,所以使用最簡單的Integer來實作,資料結構轉換在client端實作。

程式碼

/**
 * 輸入日期,可以轉換成星期幾。
 * 
 * @param dateString日期字串
 * @return 星期幾
 * @throws ParseException 無法將字串轉換成java.util.Date類別
 */
public static String date2Day( String dateString ) throws ParseException
{
    SimpleDateFormat dateStringFormat = new SimpleDateFormat( "yyyy-MM-dd" );
    Date date = dateStringFormat.parse( dateString );

    SimpleDateFormat date2DayFormat = new SimpleDateFormat( "u" );
    return date2DayFormat.format( date );
}

實作說明

  • 第一個SimpleDateFormat是用來將字串轉換成java.util.Date物件,如果輸入是java.util.Date則可以不用做字串轉Date的轉換。
  • 第二個SimpleDateFormat就是用來將日期轉換成星期幾,在new SimpleDateFormat("u")u稱為日期時間的pattern,用來表示做日期格式化時分析時的樣式,而u pattern是用來表示一週的星期幾,並且以整數表示,1=星期一 ... 7=星期天。
  • 如果要直接轉換成「星期幾」而不是整數,則將pattern換成E即可。
  • 以上pattern的大小寫都要一樣!! 不一樣的大小寫在SimpleDateFormat會有不同的解讀,例如:大寫M表示月份,小寫m表示分鐘。

參閱更多

SimpleDateFormat