以 Lazarus 實作收銀機前後台通訊程式 (使用 INDY 10) |
|
digitraveler
初階會員 發表:89 回覆:91 積分:46 註冊:2005-06-01 發送簡訊給我 |
看到標題, 或許有人會覺得奇怪, POS 跟後台 DB 通訊或要資料, 用資料庫聯結的方式或是 HTTP/XML 查詢不就得了 ?? 原因如下
1.這是有數百台 POS 規模的客戶, 不會讓你每台 POS 都灌個 ORACLE CLIENT 之類的東西直接去連資料庫 2.專櫃收銀員素質不一, 預防利用 POS 偷上網, 或是病毒感染癱瘓整個賣場網路, 幾乎所有通訊協定都鎖起來, 除了 POS 跟 POS SERVER 間自定的 Middle ware 的通訊協定 3.包含檔案傳輸, 都絕不透過網芳或是 FTP , 完全使用自訂通訊方式 , 本案例就是實做自訂的 POS 跟 POS SERVER 間的 Middle ware 通訊 我個人把收銀機前後台網路通訊歸類為四種主要命令, 建立好後這四種命令機制後, POS 前後台之間的通訊需求都可搞定, 其它業種之程式需求當然也可應用到 1.SEND_STR 命令 : POS 向主機發出 STRING 資料 例如 : POS 送出 "I AM ALIVE" 告知主機 POS 連線狀況 2.GET_STR 命令 : POS 向主機要求取回 STRING 資料 例如 : POS 向後台要回主機時間字串以便同步 POS 時間, 或是簡單查詢字串 (送出會員卡號, 從主機取回會員姓名等) 3.SEND_FILE 命令 : POS 向主機送出 FILE 例如 : POS 把交易資料檔送至主機 4.GET_FILE 命令 : POS 向主機要求取回 FILE (可能有多筆檔案) 例如 : POS 從主機取得 "程式更新", "主檔配信", 甚至較複雜的查詢(如退貨交易資料內容)都可透過 GET_FILE 命令機制 這些機制可以綁在 POS 程式中, 變成 POS 程式的一部份; 也可獨立出成一 Middleware 程式, 大檔案的分割傳送, Server 收到 Client 取檔指令後如何透過原連線回送檔案到 Client(不用再開一新連線), 分享給大家 [code delphi] CLIENT 端程式 //---------------------------------------------------------------------------- //函式使用例 : SND_STR('HELLO',0); //---------------------------------------------------------------------------- procedure TForm1.SND_STR(command_text: String ; command_tag:integer); begin if (connection_busy) then exit; connection_busy:=true; if (IdTCPClient1.Connected) then IdTCPClient1.Disconnect; IdTCPClient1.Host := Edit1.Text; IdTCPClient1.ReadTimeout:=1000; MemoLog('●SND_STR(' command_text ',' IntToStr(command_tag) ') 開始'); try IdTCPClient1.Connect; except MemoLog('連結失敗'); connection_busy:=false; MemoLog('○SND_STR() 結束'); exit; end; try IdTCPClient1.IOHandler.Write(LongInt(1),true); //Command_Id => 1:SND_STR 2:GET_STR 3:SND_FILE 4:GET_FILE IdTCPClient1.IOHandler.WriteLn(command_text); //Command_Text IdTCPClient1.IOHandler.Write(command_tag,true); //Command_Tag finally IdTCPClient1.Disconnect; connection_busy:=false; MemoLog('○SND_STR() 結束'); end; end; //---------------------------------------------------------------------------- //函式使用例 : ShowMessage(GET_STR('TIME',0)); //秀出主機時間字串 //---------------------------------------------------------------------------- function TForm1.GET_STR(command_text: String ; command_tag:integer): String; var r:String; begin if (connection_busy) then exit; connection_busy:=true; if (IdTCPClient1.Connected) then IdTCPClient1.Disconnect; IdTCPClient1.Host := Edit1.Text; IdTCPClient1.ReadTimeout:=1000; MemoLog('●GET_STR(' command_text ',' IntToStr(command_tag) ') 開始'); r:=''; try IdTCPClient1.Connect; except MemoLog('連結失敗'); connection_busy:=false; MemoLog('○GET_STR() 結束'); result:=r; exit; end; try IdTCPClient1.IOHandler.Write(LongInt(2),true); //Command_Id => 1:SND_STR 2:GET_STR 3:SND_FILE 4:GET_FILE IdTCPClient1.IOHandler.WriteLn(command_text); //Command_Text IdTCPClient1.IOHandler.Write(command_tag,true); //Command_Tag r:=IdTCPClient1.IOHandler.ReadLn; MemoLog('接收到回傳字串 : "' r '"'); finally IdTCPClient1.Disconnect; connection_busy:=false; MemoLog('○GET_STR() 結束'); end; result:=r; end; //---------------------------------------------------------------------------- //函式使用例 : if (OpenDialog1.Execute) then SND_FILE(OpenDialog1.FileName,0); //---------------------------------------------------------------------------- procedure TForm1.SND_FILE(command_text: String ; command_tag:integer); var buff:array[0..1024] of byte; buff2:array of Byte; //TBytes buff3:TIdBytes; //uses idGlobal fstream:TFileStream; filesize:integer; filename:String; readcount:integer; begin if (connection_busy) then exit; connection_busy:=true; if (IdTCPClient1.Connected) then IdTCPClient1.Disconnect; IdTCPClient1.Host := Edit1.Text; IdTCPClient1.ReadTimeout:=1000; MemoLog('●SND_FILE(' command_text ',' IntToStr(command_tag) ') 開始'); try IdTCPClient1.Connect; except MemoLog('連結失敗'); connection_busy:=false; MemoLog('○SND_FILE() 結束'); exit; end; try fstream:=TFileStream.Create(command_text, fmShareDenyWrite); //fmOpenRead(會獨佔), fmShareDenyWrite, fmShareDenyNone filename:=ExtractFileName(command_text); filesize:=fstream.Size; IdTCPClient1.IOHandler.Write(LongInt(3),true); //Command_Id => 1:SND_STR 2:GET_STR 3:SND_FILE 4:GET_FILE IdTCPClient1.IOHandler.WriteLn(filename); //Command_Text IdTCPClient1.IOHandler.Write(filesize,true); //Command_Tag MemoLog('發送檔案:' command_text); fstream.Position:=0; While (fstream.Position < filesize) do begin if ((filesize - fstream.Position) >= 1024) then //PASCAL 不能用 SIZEOF(buff) ?? readcount := 1024 else readcount := filesize - fstream.Position; fstream.ReadBuffer(buff, readcount); SetLength(buff3,readcount); Move(buff[0],buff3[0],readcount); IdTCPClient1.Socket.Write(buff3, readcount); end; MemoLog('發送檔案完成 (' IntToStr(filesize) ' bytes)'); finally fstream.Free; IdTCPClient1.Disconnect; connection_busy:=false; MemoLog('○SND_FILE() 結束'); end; end; //---------------------------------------------------------------------------- //函式使用例 : GET_FILE('PG_DOWNLOAD',0); //取得程式更新檔案 ('PG_DOWNLOAD'為自訂的程式更新識別字) //---------------------------------------------------------------------------- procedure TForm1.GET_FILE(command_text: String ; command_tag:integer); var buff:array[0..1024] of byte; buff3:TIdBytes; //uses idGlobal fstream:TFileStream; filesize:integer; filename:String; readcount:integer; get_file_path:String; TmpList: TStringList; TmpList2: TStringList; i: integer; begin if (connection_busy) then exit; connection_busy:=true; if (IdTCPClient1.Connected) then IdTCPClient1.Disconnect; IdTCPClient1.Host := Edit1.Text; IdTCPClient1.ReadTimeout:=5000; MemoLog('●GET_FILE(' command_text ',' IntToStr(command_tag) ') 開始'); try IdTCPClient1.Connect; except MemoLog('連結失敗'); connection_busy:=false; MemoLog('○GET_FILE 結束'); exit; end; try IdTCPClient1.IOHandler.Write(LongInt(4),true); //Command_Id => 1:SND_STR 2:GET_STR 3:SND_FILE 4:GET_FILE IdTCPClient1.IOHandler.WriteLn(command_text); //Command_Text IdTCPClient1.IOHandler.Write(command_tag,true); //Command_Tag get_file_path:=''; if (Trim(command_text)='PG_DOWNLOAD') then get_file_path:='C:\PG'; TmpList:=TStringList.Create; TmpList2:=TStringList.Create; //讀回檔案可能有多個 IdTCPClient1.Socket.ReadStrings(TmpList); //讀回檔名列 IdTCPClient1.Socket.ReadStrings(TmpList2); //讀回檔案 size 列 for i:=0 to TmpList.Count-1 do begin filename:=TmpList.Strings[i]; filesize:=StrToInt(TmpList2.Strings[i]); //假如 Client 端已存在該檔案要先刪除 filename:=get_file_path '\' filename; ForceDirectories(get_file_path); if (FileExists(filename)) then DeleteFile(filename); try fstream:=TFileStream.Create(filename, fmCreate); //接收端檔名路徑 MemoLog('接收檔案:' filename); while (filesize > fstream.Size) do begin if ((filesize - fstream.Size) > 1024) then readcount := 1024 else readcount := filesize - fstream.Size; //MemoLog("接收 bytes:" IntToStr(readcount)); IdTCPClient1.Socket.ReadBytes(buff3, readcount, false); Move(buff3[0],buff[0],readcount); fstream.WriteBuffer(buff, readcount); Application.ProcessMessages(); end; finally MemoLog('接收檔案完成 (' IntToStr(filesize) ' bytes)'); fstream.Free; end; end; finally TmpList.Free; TmpList2.Free; IdTCPClient1.Disconnect; connection_busy:=false; MemoLog('○GET_FILE 結束'); end; end; -------------------------------------------------------------------------------------------------------------------------------------- SERVER 端程式 只要放一個 IdTCPServer 控件, 在其 OnExecute() 事件中處理所有命令需求 procedure TForm1.IdTCPServer1Execute(AContext: TIdContext); var command_id:integer; command_text: String ; command_tag:integer; client_ip:String; buff:array[0..1023] of byte; buff2:array of Byte; buff3:TIdBytes; //uses idGlobal fstream:TFileStream; filesize:integer; filename:String; readcount:integer; i:integer; SID:Integer; TmpList:TStringList; TmpList2:TStringList; TmpList3:TStringList; MySync: TMySync; begin MySync:=TMySync.Create(); Randomize(); SID:=Random(100) Random(100); //INDY 10 沒有 THREAD ID, 需要的話可用這模擬 IncrConnectioncount; client_ip:=AContext.Connection.Socket.Binding.PeerIP; //同 AContext.Binding.PeerIP; try command_id:=AContext.Connection.IOHandler.ReadLongInt(true); //Command_Id => 1:SND_STR 2:GET_STR 3:SND_FILE 4:GET_FILE //MemoLog('command_id=' IntToStr(command_id)); case command_id of 1 : begin //收到 SND_STR 命令 //command_text:=AContext.Connection.IOHandler.ReadLn('\n',1000,-1); command_text:=AContext.Connection.IOHandler.ReadLn; command_tag :=AContext.Connection.IOHandler.ReadLongInt(true); if (command_text='POS_CONNECT') then begin log_text:=client_ip '/' {IntToStr(AContext.Data) }' (SND_STR): ' command_text '( POS_ID = ' IntToStr(command_tag) ')'; MySync.Synchronize; end else begin log_text:=client_ip '/' {IntToStr(AContext.Data) }' (SND_STR): ' command_text '(' IntToStr(command_tag) ')'; MySync.Synchronize; end; end; 2 : begin //收到 GET_STR 命令 //command_text:=AContext.Connection.IOHandler.ReadLn('\n',1000,-1); command_text:=AContext.Connection.IOHandler.ReadLn; command_tag :=AContext.Connection.IOHandler.ReadLongInt(true); log_text:=client_ip '/' {IntToStr(AContext.Data) }' (GET_STR): ' command_text '(' IntToStr(command_tag) ')'; MySync.Synchronize; if (command_text='TIME') then begin AContext.Connection.IOHandler.WriteLn('SERVER TIME IS ' FormatDateTime('hh:nn:ss', Now)); end end; 3 : begin //收到 SND_FILE 命令 command_text:=AContext.Connection.IOHandler.ReadLn; command_tag :=AContext.Connection.IOHandler.ReadLongInt(true); log_text:=client_ip '/' {IntToStr(AContext.Data) }' (SND_FILE): ' command_text '(' IntToStr(command_tag) ')'; MySync.Synchronize; filename:='C:\' command_text; filesize:=command_tag; if (FileExists(filename)) then DeleteFile(filename); log_text:=client_ip '/' {IntToStr(AContext.Data) }' (SND_FILE): SERVER 接收檔案 = ' filename; MySync.Synchronize; fstream:=TFileStream.Create(filename, fmCreate); while (filesize>fstream.Size) do begin if ((filesize-fstream.Size) >= 1024) then readcount := 1024 else readcount := filesize - fstream.Size; //log_text:=client_ip '/' {IntToStr(AContext.Data) }' (SND_FILE): read_bytes = ' IntToStr(readcount); //MySync.Synchronize; //SetLength(buff3,readcount); //這裡可以不用加 AContext.Connection.Socket.ReadBytes(buff3, readcount, false); Move(buff3[0],buff[0],readcount); fstream.WriteBuffer(buff, readcount); end; fstream.Free; log_text:=client_ip '/' {IntToStr(AContext.Data) }' (SND_FILE): SERVER 接收檔案完成 (' IntToStr(filesize) ' bytes)'; MySync.Synchronize; end; 4 : begin //收到 GET_FILE 命令 command_text:=AContext.Connection.IOHandler.ReadLn; command_tag :=AContext.Connection.IOHandler.ReadLongInt(true); log_text:=client_ip '/' {IntToStr(AContext.Data) }' (GET_FILE): ' command_text '(' IntToStr(command_tag) ')'; MySync.Synchronize; if (command_text='PG_DOWNLOAD') then begin TmpList:=TStringList.Create; TmpList2:=TStringList.Create; TmpList3:=TStringList.Create; _GetFileList(TmpList,'C:\windows\system32\*.*'); //檔名串列 TmpList2.Clear; for i:=0 to TmpList.Count-1 do begin TmpList2.Add(ExtractFileName(TmpList.Strings[i])); end; //檔案 Size 串列 TmpList3.Clear; for i:=0 to TmpList.Count-1 do begin TmpList3.Add(IntToStr(_FileSize(TmpList.Strings[i]))); end; AContext.Connection.IOHandler.Write(TmpList2, true); AContext.Connection.IOHandler.Write(TmpList3, true); //傳送檔案 for i:=0 to TmpList.Count-1 do begin filename:=TmpList.Strings[i]; fstream:=TFileStream.Create(filename, fmShareDenyWrite); //fmOpenRead(會獨佔), fmShareDenyWrite, fmShareDenyNone filesize:=fstream.Size; log_text:=client_ip '/' {IntToStr(AContext.Data) }' (GET_FILE): SERVER 回傳檔案 = ' filename; MySync.Synchronize; while (fstream.Position < filesize) do begin if ((filesize - fstream.Position) >= 1024) then readcount := 1024 else readcount := filesize - fstream.Position; //debug 用, 打開的話傳大檔會慢很多 //log_text:=client_ip '/' {IntToStr(AContext.Data) }' (GET_FILE): send_bytes = ' IntToStr(readcount); //MySync.Synchronize; fstream.ReadBuffer(buff, readcount); SetLength(buff3,readcount); Move(buff[0],buff3[0],readcount); AContext.Connection.IOHandler.Write(buff3, readcount); end; fstream.Free; log_text:=client_ip '/' {IntToStr(AContext.Data) }' (GET_FILE): SERVER 回傳檔案完成 (' IntToStr(filesize) ' bytes)'; MySync.Synchronize; end; TmpList.Free; TmpList2.Free; end; end; else //MemoLog(client_ip); end; finally AContext.Connection.Disconnect(); DecrConnectioncount; end; MySync.Free; end; [/code] ■ 相關參考及源碼下載 : http://tw.myblog.yahoo.com/bruce0829/article?mid=37 編輯記錄
digitraveler 重新編輯於 2010-05-26 17:13:21, 註解 無‧
digitraveler 重新編輯於 2010-05-26 17:14:24, 註解 無‧ digitraveler 重新編輯於 2010-05-26 17:18:26, 註解 無‧ digitraveler 重新編輯於 2010-05-31 20:30:54, 註解 無‧ digitraveler 重新編輯於 2010-06-12 11:28:26, 註解 無‧ digitraveler 重新編輯於 2010-06-12 11:29:03, 註解 無‧ digitraveler 重新編輯於 2010-06-12 11:30:21, 註解 無‧ digitraveler 重新編輯於 2010-06-12 11:39:07, 註解 無‧ |
digitraveler
初階會員 發表:89 回覆:91 積分:46 註冊:2005-06-01 發送簡訊給我 |
下雨天閒閒在家沒事幹, 休閒研究 ....
VS2003 C# INDY.NET 版 [code c#] 動態產生 TCPClient 控件 TCPClient IdTCPClient1 = new TCPClient(); //---------------------------------------------------------------------------- private void Form1_Load(object sender, System.EventArgs e) { Random randObj = new Random(); pos_id=randObj.Next(100,999); //取 100-999 隨機值 textBox1.Text=My.IntToStr(pos_id); //pos id IdTCPClient1.Port = 6501; Can_Connect(); } //---------------------------------------------------------------------------- //Example : SND_STR("HELLO",0); //---------------------------------------------------------------------------- private void SND_STR(String command_text, int command_tag) { if (connection_busy) return; connection_busy=true; MemoLog("●SND_STR(" command_text "," My.IntToStr(command_tag) ") 開始"); if (IdTCPClient1.Connected()) IdTCPClient1.Disconnect(); IdTCPClient1.Host = textBox2.Text; try { try { IdTCPClient1.Connect(); IdTCPClient1.IOHandler.Write(1,true); //Command_Id => 1:SND_STR 2:GET_STR 3:SND_FILE 4:GET_FILE IdTCPClient1.IOHandler.WriteLn(command_text); //Command_Text IdTCPClient1.IOHandler.Write(command_tag,true); //Command_Tag } catch { MemoLog("連結失敗"); } } finally { IdTCPClient1.Disconnect(); connection_busy=false; MemoLog("○SND_STR() 結束"); } } //---------------------------------------------------------------------------- //Example : My.ShowMessage("SERVER TIME IS " GET_STR("TIME",0)); //---------------------------------------------------------------------------- private String GET_STR(String command_text, int command_tag) { string r=""; if (connection_busy) return r; connection_busy=true; MemoLog("●GET_STR(" command_text "," My.IntToStr(command_tag) ") 開始"); if (IdTCPClient1.Connected()) IdTCPClient1.Disconnect(); IdTCPClient1.Host = textBox2.Text; try { try { IdTCPClient1.Connect(); IdTCPClient1.IOHandler.Write(2,true); //Command_Id => 1:SND_STR 2:GET_STR 3:SND_FILE 4:GET_FILE IdTCPClient1.IOHandler.WriteLn(command_text); //Command_Text IdTCPClient1.IOHandler.Write(command_tag,true); //Command_Tag r=IdTCPClient1.IOHandler.ReadLn(); } catch { MemoLog("連結失敗"); } } finally { IdTCPClient1.Disconnect(); connection_busy=false; MemoLog("○GET_STR() 結束"); } return r; } //---------------------------------------------------------------------------- //Example : if (openFileDialog1.ShowDialog() == DialogResult.OK) SND_FILE(openFileDialog1.FileName,0); //---------------------------------------------------------------------------- private void SND_FILE(String command_text, int command_tag) { if (connection_busy) return; connection_busy=true; MemoLog("●SND_FILE(" command_text "," My.IntToStr(command_tag) ") 開始"); if (IdTCPClient1.Connected()) IdTCPClient1.Disconnect(); IdTCPClient1.Host = textBox2.Text; FileStream fstream = null; //using System.IO String filename; int filesize; int readcount; int fileoffset; byte[] buff=new byte[1024]; try { try { fstream = new FileStream(command_text, FileMode.Open, FileAccess.Read); filename=My.ExtractFileName(command_text); filesize=(int)fstream.Length; fileoffset=0; IdTCPClient1.Connect(); IdTCPClient1.IOHandler.Write(3,true); //Command_Id => 1:SND_STR 2:GET_STR 3:SND_FILE 4:GET_FILE IdTCPClient1.IOHandler.WriteLn(filename); //Command_Text IdTCPClient1.IOHandler.Write(filesize,true); //Command_Tag MemoLog("發送檔案:" command_text); fstream.Position=0; while (fstream.Position < filesize) { if ((filesize - fstream.Position) >= buff.Length) readcount = buff.Length; else readcount = filesize - (int)fstream.Position; fstream.Read(buff, 0, readcount); IdTCPClient1.Socket.Write(buff); } MemoLog("發送檔案完成 (" My.IntToStr(filesize) " bytes)"); fstream.Close(); } catch (Exception ex) { MessageBox.Show(ex.Message); MemoLog("連結失敗"); } } finally { IdTCPClient1.Disconnect(); connection_busy=false; MemoLog("○SND_FILE() 結束"); } } //---------------------------------------------------------------------------- //Example : GET_FILE("PG_DOWNLOAD",0); //---------------------------------------------------------------------------- private void GET_FILE(String command_text, int command_tag) { if (connection_busy) return; connection_busy=true; MemoLog("●GET_FILE(" command_text "," My.IntToStr(command_tag) ") 開始"); if (IdTCPClient1.Connected()) IdTCPClient1.Disconnect(); IdTCPClient1.Host = textBox2.Text; FileStream fstream = null; //using System.IO string filename; int filesize; int readcount; byte[] buff=new byte[1024]; string get_file_path; try { try { IdTCPClient1.Connect(); IdTCPClient1.IOHandler.Write(4,true); //Command_Id => 1:SND_STR 2:GET_STR 3:SND_FILE 4:GET_FILE IdTCPClient1.IOHandler.WriteLn(command_text); //Command_Text IdTCPClient1.IOHandler.Write(command_tag,true); //Command_Tag get_file_path=""; if (My.Trim(command_text)=="PG_DOWNLOAD") get_file_path="C:\\PG"; //讀回檔案可能有多個 String fn_list = IdTCPClient1.Socket.ReadLn(); //讀回檔名列 String fs_list = IdTCPClient1.Socket.ReadLn(); //讀回 File Size 列 if (My.Trim(fn_list)!="") { for (int i=1; i<=My.StrSegCount(fn_list,','); i ) { filename=My.StrSeg(fn_list,',',i); filesize=My.StrToInt(My.StrSeg(fs_list,',',i)); //假如 Client 端已存在該檔案要先刪除 filename = get_file_path "\\" filename; My.ForceDirectories(get_file_path); if (My.FileExists(filename)) My.DeleteFile(filename); try { MemoLog("接收檔案:" filename); fstream = new FileStream(filename, FileMode.Create, FileAccess.Write); //接收端檔名路徑 while (filesize > fstream.Length) { if ((filesize - fstream.Length) > buff.Length) readcount = buff.Length; else readcount = filesize - (int)fstream.Length; //MemoLog("接收 bytes:" IntToStr(readcount)); IdTCPClient1.Socket.ReadBytes(ref buff, readcount, false); fstream.Write(buff, 0, readcount); } } finally { fstream.Close(); //fstream.Dispose(); MemoLog("接收檔案完成 (" My.IntToStr(filesize) " bytes)"); } } } } catch (Exception ex) { //MessageBox.Show(ex.Message); MemoLog("連結失敗"); } } finally { IdTCPClient1.Disconnect(); connection_busy=false; MemoLog("○GET_FILE() 結束"); } } 動態產生 TCPServer 控件 private TCPServer IdTCPServer1 = new TCPServer(); 並在其 OnExecute() 事件中處理可以所有命令需求 private void Form1_Load(object sender, System.EventArgs e) { IdTCPServer1.OnConnect = new TIdServerThreadEvent(TCPServerConnect); IdTCPServer1.OnExecute = new TIdServerThreadEvent(TCPServerExecute); IdTCPServer1.DefaultPort = 6501; IdTCPServer1.Active = true; } private void TCPServerExecute(Context AContext) { int command_id; int command_tag; string command_text; string client_ip=AContext.Connection.Socket.Binding.PeerIP; //同 AContext.Binding.PeerIP; FileStream fstream = null; //using System.IO String filename; int filesize; int readcount; byte[] buff=new byte[1024]; string fn_list, fs_list; try { command_id=AContext.Connection.IOHandler.ReadInteger(true); //Command_Id => 1:SND_STR 2:GET_STR 3:SND_FILE 4:GET_FILE try { switch(command_id) { case 1 : //收到 SND_STR command_text=AContext.Connection.IOHandler.ReadLn(); command_tag=AContext.Connection.IOHandler.ReadInteger(true); MemoLog(client_ip "(SND_STR): " command_text "(" My.IntToStr(command_tag) ")"); if (command_text=="POS_CONNECT") { ;; } break; case 2 : //收到 GET_STR command_text=AContext.Connection.IOHandler.ReadLn(); command_tag=AContext.Connection.IOHandler.ReadInteger(true); MemoLog(client_ip "(GET_STR): " command_text "(" My.IntToStr(command_tag) ")"); if (command_text=="TIME") { AContext.Connection.IOHandler.WriteLn(My.FormatDateTime("yyyy/mm/dd hh:nn:ss", My.Now())); } break; case 3 : //收到 SND_FILE command_text=AContext.Connection.IOHandler.ReadLn(); command_tag=AContext.Connection.IOHandler.ReadInteger(true); MemoLog(client_ip "(SND_FILE): " command_text "(" My.IntToStr(command_tag) ")"); filename="C:\\" command_text; filesize=command_tag; if (My.FileExists(filename)) My.DeleteFile(filename); MemoLog(client_ip " (SND_FILE): SERVER 接收檔案 = " filename); fstream = new FileStream(filename, FileMode.Create, FileAccess.Write); while (filesize>fstream.Length) { if ((filesize-fstream.Length) > buff.Length) readcount = buff.Length; else readcount = filesize - (int)fstream.Length; //MemoLog(client_ip " (SND_FILE): read_bytes = " IntToStr(readcount)); AContext.Connection.Socket.ReadBytes(ref buff, readcount, false); fstream.Write(buff, 0, readcount); } fstream.Close(); MemoLog(client_ip " (SND_FILE): SERVER 接收檔案完成 (" filesize.ToString() " bytes)"); break; case 4 : //收到 GET_FILE command_text=AContext.Connection.IOHandler.ReadLn(); command_tag=AContext.Connection.IOHandler.ReadInteger(true); MemoLog(client_ip "(GET_FILE): " command_text "(" My.IntToStr(command_tag) ")"); TStringList TmpList = new TStringList(); if (command_text=="PG_DOWNLOAD") { My.GetFileList(ref TmpList, "C:\\ABCPSV\\UPDATE\\*.*"); fn_list=""; fs_list=""; for (int i=0; i<=TmpList.Count-1; i ) { fn_list=fn_list My.ExtractFileName(TmpList.Strings(i)) ","; fs_list=fs_list My.FileSize(TmpList.Strings(i)) ","; } fn_list=My.CutRight(fn_list,1); //減掉最後一個 "," fs_list=My.CutRight(fs_list,1); //減掉最後一個 "," AContext.Connection.IOHandler.WriteLn(fn_list); AContext.Connection.IOHandler.WriteLn(fs_list); //傳送檔案 for (int i=0; i<=TmpList.Count-1; i ) { filename=TmpList.Strings(i); fstream = new FileStream(filename, FileMode.Open, FileAccess.Read); filesize = (int)fstream.Length; //filesize = My.StrToInt(My.StrSeg(fs_list,',',i 1)); MemoLog(client_ip " (GET_FILE): SERVER 回傳檔案 = " filename); fstream.Position=0; while (fstream.Position < filesize) { if ((filesize - fstream.Position) >= buff.Length) readcount = buff.Length; else readcount = filesize - (int)fstream.Position; //debug 用, 打開的話傳大檔會慢很多 //MemoLog(client_ip " (GET_FILE): send_bytes = " IntToStr(readcount)); //回傳遞二個以後的檔都會毀損?? //fstream.Read(buff, 0, readcount); //AContext.Connection.Socket.Write(buff); //要用這種方法 byte[] buff2=new byte[readcount]; fstream.Read(buff2, 0, readcount); AContext.Connection.Socket.Write(buff2); } fstream.Close(); MemoLog(client_ip " (GET_FILE): SERVER 回傳檔案完成 (" filesize.ToString() " bytes)"); } } break; } } catch (Exception E) { MemoLog(E.Message); throw; } } finally { AContext.Connection.Disconnect(); } } [/code] ■ 相關參考及源碼下載 : http://tw.myblog.yahoo.com/bruce0211/article?mid=282&prev=-1&next=269
編輯記錄
digitraveler 重新編輯於 2010-05-30 15:40:51, 註解 無‧
digitraveler 重新編輯於 2010-05-30 15:42:08, 註解 無‧ digitraveler 重新編輯於 2010-05-30 17:54:09, 註解 無‧ digitraveler 重新編輯於 2010-05-30 20:04:23, 註解 無‧ |
digitraveler
初階會員 發表:89 回覆:91 積分:46 註冊:2005-06-01 發送簡訊給我 |
INDY 10 在 Linux Lazarus 下無法運作的解決方案
在 Unbutu 10.04 之 Lazarus 0.9.28 下灌好 INDY 10 後, 看起來都很正常, 高興之餘拉了一個 TIdTcpServer 元件到一個空白專案中 , 在 Form Active 時寫了兩行 procedure TForm1.FormActivate(Sender: TObject); begin IdTCPServer1.DefaultPort:= 6501; IdTCPServer1.Active:=true; end; 結果程式編譯完一 RUN , 程式就馬上自動結束掉 (也就是 DO NOTHING), 連錯誤訊息都沒有, 換了其它 Server 類的元件, 全部都是如此, 完了.... INDY 10 的 Server 類元件在 Linux 上無法運作 ?? 去網路查, 好像真的有 BUG ... 還說是什麼 pthread_kill problem 造成....怪不得 google 都沒找到有人在 Linux 上寫過的範例 , 搞了兩個多禮拜, 無意中發現這個問題是 Muti Thread 的問題造成 INDY 10 的 README 中有說, 在 UNIX 系統中編譯的時後要加入 "-dUseCThreads" 參數 在你的 INDY 專案主選單 -> Project -> Compiler Options 之 Other 頁, 加入 "-dUseCThreads" 編譯參數 在 Linux 跟 WIN32 環境中, 驅動 TIdTcpServer 的寫法也有不同 WIN32 : procedure TForm1.FormActivate(Sender: TObject); begin IdTCPServer1.DefaultPort:= 6501; IdTCPServer1.Active:=true; end; Linux procedure TForm1.FormActivate(Sender: TObject); begin //uses idGlobal , the Id_IPv4 force the IdTCPServer to work in Id_IPV4 mode. IdTCPServer1.Bindings.Add.IPVersion := Id_IPv4; //否則將出現 with socket error # 98 , address already in use IdTCPServer1.Bindings.Add.IP:='127.0.0.1'; IdTCPServer1.Bindings.Add.Port:= 6501; IdTCPServer1.Active:=true; end; 在 IdTCPServer1 的 OnExecute() 事件若要處理 VCL , 請使用 TIdSync 同步物件; 否則, 直接在 OnExecute() 事件中處理 VCL 顯示類的 CODE , 將導致被連線幾次後整個 Server 程式就 Crash 掉 TIdSync 同步物件的使用, 請參照以下連結下載源碼 詳細內容請參考 Lazarus 源碼任務INDY 10 在 Linux Lazarus 下無法運作的解決方案http://tw.myblog.yahoo.com/bruce0829/article?mid=58&prev=-1&next=55 |
本站聲明 |
1. 本論壇為無營利行為之開放平台,所有文章都是由網友自行張貼,如牽涉到法律糾紛一切與本站無關。 2. 假如網友發表之內容涉及侵權,而損及您的利益,請立即通知版主刪除。 3. 請勿批評中華民國元首及政府或批評各政黨,是藍是綠本站無權干涉,但這裡不是政治性論壇! |