2011-05-31

普物測驗軟體 原始碼–5 伺服器端接收

這部分不是客戶端使用的,而是我的電腦接受客戶端檔案部分。這最重要的觀念(客戶端上傳部分也是)在於如何建立檔案的讀取、寫入部分。個人認為尚有部分的缺陷,例如
我是將客戶端資料一次完整接收後(並回傳訊息),再一次將寫入的資料讀出再重新編排,這必造成資料讀、寫上的時間浪費。最好方式應直接讀取記憶體中的資料排列寫入檔案,避免二次寫入,多加一次讀取的時間消耗。
另外伺服器端如何與客戶端有更直接的訊息傳送,尚有待更多的功能學習。
import java.io.*;
import java.net.InetAddress;
import java.net.ServerSocket;
import java.net.Socket;
public class ServerCenter extends java.lang.Thread{
   
    private boolean OutServer = false;
    private ServerSocket server;    // 建立伺服器變數
    private final int ServerPort = 2525;    //伺服器 IP
    static int peo;
   
    public ServerCenter(){    // initial serversetting
       
       
        try{
            server = new ServerSocket(ServerPort); //建立伺服器物件
        }
        catch(java.io.IOException e){
            System.out.println("伺服器啟動失敗");
        }
    }
   
    public void run(){    //建立執行緒
        Socket skt;    // 建立伺服器動作變數
        InputStream ins;    //建立取得網路資料之變數
       
        System.out.println("伺服器初始化完成");
       
        while(!OutServer){    //當伺服器啟動時
            skt = null;    //伺服器動作變數清空
            String ip1 = null;
           
            for(int i=1;i<200;i++){
                try{
                    synchronized(server){        //同步化伺服器物件
                       
                        System.out.println(" 等待新客戶端呼叫 . .. ...");
                        skt = server.accept();}    //啟動伺服器接收功能
                        byte buff[]=new byte[102400];    //建立接收的暫存資料空間(每次以多大的空間接受一個封包)
                        System.out.println("接受第 "+i+" 個連線,來自 IP = "+skt.getInetAddress());    //顯示對方 IP
                        if(skt.getInetAddress().toString().equals(ip1)){
                            i=i-1;
                            System.out.println("已重複連線,中斷");
                            skt.close();
                        }
                        ip1=skt.getInetAddress().toString();
                       
                        ins = skt.getInputStream();//建立取得網路資料之物件
                        int n=ins.read(buff);    //利用取得網資之物件來讀取記憶體暫存資料
//                        System.out.println(" 客戶端資料已存入記憶體 ");
                       
                        OutputStream out=skt.getOutputStream();    //建立回應物件
                        String str="上傳成功!!請記得,你是第 "+i+" 位交卷!";
                        out.write(str.getBytes());    //回應消息
                        out.close();    //關閉回應
                       
                       
                        File fw= new File("C:\\PhylabTemp.txt");   
                        BufferedWriter bfw=new BufferedWriter(new OutputStreamWriter(new FileOutputStream(fw.toString(), true),"big5"));
                        bfw.write(new String(buff,0,n));    // 將網路暫存寫入檔案                       
                       
                        bfw.close();    //關閉客戶端記憶體暫存資料,等一下再打開搜尋關鍵字串
                        ins.close();    //關閉本次接受
//                        System.out.println("客戶端連線結束");
                       
                       
                        FileInputStream fi = new FileInputStream("C:\\PhylabTemp.txt");
                        byte ba[]=new byte[fi.available()];
                        fi.read(ba);
                        int N01= new String(ba).lastIndexOf("Name:");
                        int N02= new String(ba).lastIndexOf(", Number:");
                        int N03= new String(ba).lastIndexOf(",  Score:");
                        int N04= new String(ba).lastIndexOf("end");
//                        String Ns01=new Character((char)(new String(ba).charAt(N01+5))).toString();
                        String name = new String(ba).substring(N01+5, N02);
                        String number = new String(ba).substring(N02+9, N03);
                        String score = new String(ba).substring(N03+9, N04-1);
                       
                        fi.close(); // 客戶端暫存於記憶體的資料可刪除了,因為已存到變數中
                       
//                        System.out.println(" 檔案取值 成功");

                       
                        FileInputStream fit=new FileInputStream("C:\\PhylabTemp.txt");    // 開新記憶體暫存檔,準備將資料寫入檔案中
                       
                       
                        FileOutputStream fot=new FileOutputStream("C:\\通訊\\"+number+"_"+name+"_"+score+".txt");    //以學號排序
                        FileOutputStream fot2 = null;    //建立另外以上傳順序排序
                        if(i<10){    //為了建立 01. 02. 03...10. 11. .. 排序而定
                            fot2 = new FileOutputStream("C:\\通訊\\00"+i+"_"+number+"_"+name+"_"+score+".txt");
                        }
                        if(i>=10&&i<100){
                            fot2=new FileOutputStream("C:\\通訊\\0"+i+"_"+number+"_"+name+"_"+score+".txt");
                        }
                        if(i>=100){
                            fot2=new FileOutputStream("C:\\通訊\\"+i+"_"+number+"_"+name+"_"+score+".txt");
                        }
                       
                        byte data[]=new byte[fit.available()];
                        fit.read(data);
                        fot.write(data);
                        fot2.write(data);
                        fit.close();
                        fot.close();
                        fot2.close();
                       
//                        System.out.println("檔案重建成功");
                       
                        skt.close();    //關閉接收功能
                       
                        File df = new File("C:\\PhylabTemp.txt");
                        df.delete();
                       
                        System.out.println("第 "+i+" 個   「"+name+"」   接收完成");
                       
                        if(name.equals("close")){
                            System.exit(0);
                        }
//                        if(i==peoss){
//                            break;
//                        }   
                }
                catch(java.io.IOException e){
                    System.out.println("連線失敗");
                }
            }
            break;
        }
    }
}

4 則留言:

雜言雜語 提到...

以上刪除部分,修改為

String instemp=new String(buff,0,n);
int N01= new String(instemp).lastIndexOf("Name:");
int N02= new String(instemp).lastIndexOf(", Number:");
int N03= new String(instemp).lastIndexOf(", Score:");
int N04= new String(instemp).lastIndexOf("end");
String name = new String(instemp).substring(N01+5, N02);
String number = new String(instemp).substring(N02+9, N03);
String score = new String(instemp).substring(N03+9, N04-1);


OutputStream out=skt.getOutputStream(); //建立回應物件
String str=name+ " 上傳成功! 你是第 "+i+" 位交卷!";
out.write(str.getBytes()); //回應消息
out.close(); //關閉回應


File fw= new File("C:\\PhylabTemp.txt");
BufferedWriter bfw=new BufferedWriter(new OutputStreamWriter(new FileOutputStream(fw.toString(), true),"big5"));
bfw.write(new String(buff,0,n)); // 將網路暫存寫入檔案

bfw.close();//關閉客戶端記憶體暫存資料,等一下再打開搜尋關鍵字串
ins.close(); //關閉本次接受

雜言雜語 提到...

利用下載到的資料,直接取得所需的變數,而不需要重新開啟檔案。可加入檔案的寫入速度並由此取值回傳給客戶端!

仕君 提到...

所以,你這是不是每加入一筆資料就會做一次排列?!

那為什麼不等所有資料都上傳完了之後再一次做排列呢?!
或是在每天的某個時段固定去跑個批次,
讓需要做排列的檔案在那個時間點一次做排列,
(例如晚上12:00server下上一次,在這同時做個批次...)
(類似銀行在某個時段會統整當天資料的概念...)
避免在server運作的同時,還要浪費資源在做檔案I/O上及排序...

雜言雜語 提到...

事實上伺服器只要持續開著,第一個連線進來的,會給序號 1,然後 2、、、,然後利用這序號直接加在接收到的資料上。

因此,這「交卷序號」很簡單,不需等將進來的資料全下載後再排序。

另外這有個取「學號」變數(number),是另外將它資料中的學號取出來,再以此學號命名,重覆建立一個檔案。

可能我這資料還算少,所以資料一上傳,建立得很快。

你那也是個好方法,但是我就要寫另一個程式去通通重新整理一次!

收到檔案後,結果就像
http://140.121.179.194/java_01.png
上半部是用「交卷順序」建立的。
下半部是用「擷取學號」建立的。