線上訂房服務-台灣趴趴狗聯合訂房中心
發文 回覆 瀏覽次數:5206
推到 Plurk!
推到 Facebook!

ServerSocket 與 ClientSocket 傳送資料時, 發生資料遺失的問題

尚未結案
antonov_lin
一般會員


發表:5
回覆:11
積分:8
註冊:2005-08-23

發送簡訊給我
#1 引用回覆 回覆 發表時間:2005-12-06 19:56:06 IP:220.130.xxx.xxx 未訂閱
我最終的目的是想要實現簡單的遠端控制, 先試作畫面傳送; 我所使用的是 ServerSocket 與 ClientSocket; 在我自訂資料結構中, 訂定了 資料包序號(由0 起算), 總資料包數, 資料大小, 傳輸資料及 crc 碼共五項, crc 碼計算序號, 總資料包數及傳輸資料三項; 理想的情況應該是由第0 包開始依序從 server 丟到 client, 並且每個資料 包在 client 接收後, 經計算序號, 總資料包數及傳輸資料, 必須要等於資料 包中的 crc 碼, 但是實際遇到的狀況是的確是由第0 包開始丟, 但是在中途 會出現資料包其序號不正常的現象, 所謂不正常是指序號會超出 0-總資料包數 , 而且有些資料包經計算後, 會發生不符合 crc 碼的現象, 實在是想不透到底 是為什麼, 不知有哪位先進可以指教. 我是在公司的網路環境下實作的. 以下是我的程式碼:    ------ Server 端------    
#include 
#pragma hdrstop    #include "Unit1.h"
#include "jpeg.hpp"    #define ReADataMaxSize 1000
//--------------------------------------------------------------------
#pragma package(smart_init)
#pragma resource "*.dfm"
TForm1 *Form1;    typedef struct {
        unsigned char ReADatPackNo;
        unsigned char ReATotalPacks;
        unsigned long ReATotalSize;
        unsigned char ReADataC[ReADataMaxSize];
        BYTE          ReAPackCRC;
} ReADatPack;
//--------------------------------------------------------------------
__fastcall TForm1::TForm1(TComponent* Owner)
        : TForm(Owner)
{
   ServerSocket1->Open();
}
//--------------------------------------------------------------------
void __fastcall TForm1::FormClose(TObject *Sender, TCloseAction &Action)
{
   ServerSocket1->Close();
}
//--------------------------------------------------------------------
void __fastcall TForm1::ServerSocket1ClientConnect(TObject *Sender,
      TCustomWinSocket *Socket)
{
   HDC hwDC=GetDC(0);
   TCanvas *wCanvas=new TCanvas;
   Graphics::TBitmap *wBmpPic=new Graphics::TBitmap;
   TJPEGImage *wJpegPic=new TJPEGImage;
   TMemoryStream *ReAMStm=new TMemoryStream;
   ReADatPack *ReAServerPack=new ReADatPack;
   unsigned int ReAPacksize=ReADataMaxSize;
   unsigned int index;       Label1->Caption="Connect from: " ServerSocket1->Socket->Connections[0]->RemoteAddress;       wCanvas->Handle=hwDC;
   wBmpPic->Width=Screen->Width;
   wBmpPic->Height=Screen->Height;
   wBmpPic->Canvas->CopyRect(Rect(0, 0, wBmpPic->Width, wBmpPic->Height),
      wCanvas, Rect(0, 0, Screen->Width, Screen->Height));
   wJpegPic->CompressionQuality=20;
   wJpegPic->Assign(wBmpPic);
   wJpegPic->SaveToStream(ReAMStm);
   ReAMStm->SaveToFile("d:\\BCBpractice\\Remote Screen Capture (Server)\\ReA.jpg");       ReAServerPack->ReATotalPacks=(ReAMStm->Size%ReADataMaxSize==0)?
      (ReAMStm->Size/ReADataMaxSize):(ReAMStm->Size/ReADataMaxSize 1);
   ReAServerPack->ReATotalSize=ReAMStm->Size;
   Label2->Caption="Total packages: " IntToStr(ReAServerPack->ReATotalPacks);
   Label3->Caption="Total data size: " IntToStr(ReAServerPack->ReATotalSize);
   for(ReAServerPack->ReADatPackNo=0;
      ReAServerPack->ReADatPackNoReATotalPacks;
      ReAServerPack->ReADatPackNo  )
   {
      ReAServerPack->ReAPackCRC=ReAServerPack->ReADatPackNo;
      ReAServerPack->ReAPackCRC =ReAServerPack->ReATotalPacks;
      if((ReAServerPack->ReADatPackNo 1)==ReAServerPack->ReATotalPacks)
         ReAPacksize=ReAServerPack->ReATotalSize-ReAServerPack->ReADatPackNo*ReADataMaxSize;
      ZeroMemory(ReAServerPack->ReADataC, sizeof(unsigned char)*ReADataMaxSize);
      ReAMStm->Position=ReAServerPack->ReADatPackNo*ReADataMaxSize;
      ReAMStm->Read(ReAServerPack->ReADataC, ReAPacksize);
      for(index=0; indexReAPackCRC =ReAServerPack->ReADataC[index];
      ServerSocket1->Socket->Connections[0]->SendBuf(ReAServerPack, sizeof(ReADatPack));
      Sleep(10);
   }       ReleaseDC(0, hwDC);
   delete wCanvas;
   delete wBmpPic;
   delete wJpegPic;
   delete ReAMStm;
   delete ReAServerPack;
}
//--------------------------------------------------------------------
------ Client 端------
#include 
#pragma hdrstop    #include "Unit1.h"
#include "jpeg.hpp"    #define ReADataMaxSize 1000
//--------------------------------------------------------------------
#pragma package(smart_init)
#pragma resource "*.dfm"
TForm1 *Form1;    typedef struct {
        unsigned char ReADatPackNo;
        unsigned char ReATotalPacks;
        unsigned long ReATotalSize;
        unsigned char ReADataC[ReADataMaxSize];
        BYTE          ReAPackCRC;
} ReADatPack;    TMemoryStream *ReAMStm=new TMemoryStream;
//--------------------------------------------------------------------
__fastcall TForm1::TForm1(TComponent* Owner)
        : TForm(Owner)
{
   ClientSocket1->Host="10.34.36.162";
}
//--------------------------------------------------------------------
void __fastcall TForm1::FormClose(TObject *Sender, TCloseAction &Action)
{
   ClientSocket1->Close();
}
//--------------------------------------------------------------------
void __fastcall TForm1::FormCreate(TObject *Sender)
{
   ClientSocket1->Open();
}
//--------------------------------------------------------------------
void __fastcall TForm1::ClientSocket1Read(TObject *Sender,
      TCustomWinSocket *Socket)
{
   ReADatPack *ReAClientPack=new ReADatPack;
   BYTE ReADatPackCRCCounter;
   unsigned int index;       ZeroMemory(ReAClientPack, sizeof(ReADatPack));
   ClientSocket1->Socket->ReceiveBuf(ReAClientPack, sizeof(ReADatPack));
   ReADatPackCRCCounter=ReAClientPack->ReADatPackNo;
   ReADatPackCRCCounter =ReAClientPack->ReATotalPacks;
   for(index=0; indexReADataC[index];
   if(ReADatPackCRCCounter!=ReAClientPack->ReAPackCRC)
      Memo1->Lines->Add(IntToStr(ReAClientPack->ReADatPackNo));          delete ReAClientPack;
}
//--------------------------------------------------------------------
發表人 - antonov_lin 於 2005/12/06 19:58:00
antonov_lin
一般會員


發表:5
回覆:11
積分:8
註冊:2005-08-23

發送簡訊給我
#2 引用回覆 回覆 發表時間:2005-12-07 13:00:49 IP:220.130.xxx.xxx 未訂閱
我這個問題原來是在兩部電腦上實作的, 後來我把 server 和 client 做在同 一部電腦上, 並把位址改為 "127.0.0.1", 但是有同樣的問題, 真是令人費解.
antonov_lin
一般會員


發表:5
回覆:11
積分:8
註冊:2005-08-23

發送簡訊給我
#3 引用回覆 回覆 發表時間:2005-12-07 15:54:27 IP:220.130.xxx.xxx 未訂閱
在把 server 和 client 實作在同一部電腦的問題還是沒有解決, 不過, 我修 改原來的作法達到我的目的了; 原來的作法在 server 端是用一個 for 廻圈 一直丟資料到 client, 改成一次丟一個, 等待 client 回應接收後, 再決定 要丟下一個資料, 還是要重丟一次, 以這樣的作法, 在同一部電腦上, 就可以 實現畫面傳送; 接下來, 我會再試著把這樣的修改套用到兩部電腦的實作上, 然後再上來報告.
antonov_lin
一般會員


發表:5
回覆:11
積分:8
註冊:2005-08-23

發送簡訊給我
#4 引用回覆 回覆 發表時間:2005-12-08 00:46:19 IP:61.70.xxx.xxx 未訂閱
在實驗後, 的確, 利用一次丟一個資料包, 等確認後再丟下一個才能正確地傳 送畫面到遠端, 不過, 這其中的道理實在是不清楚, 有可能網路環境過於複雜 引起的, 不知是不是有哪位先進能解決我這個疑惑.
cashyy
高階會員


發表:117
回覆:322
積分:212
註冊:2004-04-30

發送簡訊給我
#5 引用回覆 回覆 發表時間:2005-12-09 02:38:20 IP:59.104.xxx.xxx 未訂閱
您好! 看到您的問題跟我一樣!所以上來聊一下! 您的做法是:利用一次丟一個資料包, 等確認後再丟下一個才能正確地傳 送畫面到遠端。<>如果利用這種方法的話,那遠端傳輸效率會很低。 我的做法是:
antonov_lin
一般會員


發表:5
回覆:11
積分:8
註冊:2005-08-23

發送簡訊給我
#6 引用回覆 回覆 發表時間:2005-12-09 12:27:04 IP:220.130.xxx.xxx 未訂閱
cashyy 你好, 很感謝你回應來討論這個問題; 你所提到的, 我有想過, 這個問題其實有一個前提是在別篇討論中有提到的, 就是我目前使用 serversocket, clientsocket 的方式只能在區域網路中實作, 無法跨到別的區段, 所以我認為應該可以不必考慮網路頻寬的問題, 但是盡量 提昇傳輸效率仍是程式設計應該要考量的; 另外, 遠端傳輸應該區分為螢幕畫面和檔案兩個部分來看, 為何? 螢幕畫面 大小(bmp)幾乎可以說是固定, 而且螢幕畫面可以透過轉換為 jpeg 的格式並 加大jpeg 的壓縮率來達到縮小資料量的目的, 第二個方法就是在傳輸量的 限制下儘量加大資料包的大小, 來達到減少資料包數量的目的; 但若傳輸的是檔案, 大小就不定了, 只能靠第二個方法了; 我想, 不管是哪一種方法, 重點是資料要能正確地傳輸; 以上是我個人的淺見.
cashyy
高階會員


發表:117
回覆:322
積分:212
註冊:2004-04-30

發送簡訊給我
#7 引用回覆 回覆 發表時間:2005-12-10 14:28:27 IP:59.104.xxx.xxx 未訂閱
引言: cashyy 你好, 很感謝你回應來討論這個問題; 你所提到的, 我有想過, 這個問題其實有一個前提是在別篇討論中有提到的, 就是我目前使用 serversocket, clientsocket 的方式只能在區域網路中實作, 無法跨到別的區段, 所以我認為應該可以不必考慮網路頻寬的問題, 但是盡量 提昇傳輸效率仍是程式設計應該要考量的; 另外, 遠端傳輸應該區分為螢幕畫面和檔案兩個部分來看, 為何? 螢幕畫面 大小(bmp)幾乎可以說是固定, 而且螢幕畫面可以透過轉換為 jpeg 的格式並 加大jpeg 的壓縮率來達到縮小資料量的目的, 第二個方法就是在傳輸量的 限制下儘量加大資料包的大小, 來達到減少資料包數量的目的; 但若傳輸的是檔案, 大小就不定了, 只能靠第二個方法了; 我想, 不管是哪一種方法, 重點是資料要能正確地傳輸; 以上是我個人的淺見.
您好! ServerSocket與ClientSocket在區網中loss的機會應該很低才對。所以在區網中應可以一直傳送封包,而不需要傳一次,確認一次! 關於第二個方法:雖然加大封包大小可以減少封包傳送的數量沒錯,但封包大小變大時,是不是更容易loss呢?? 如果您目前只是要在區網中傳送的話,我再把我的程式碼po上來一起討論。 真高興有人跟我一起討論這問題!謝謝啦!
DavidLo
高階會員


發表:17
回覆:225
積分:168
註冊:2004-07-21

發送簡訊給我
#8 引用回覆 回覆 發表時間:2005-12-10 21:33:20 IP:218.169.xxx.xxx 未訂閱
間隔插花一下! 曾做過即時影像傳輸,於內部網路傳輸時,沒問題!但運用到Internet時,影像傳輸錯誤(封包miss)及延遲(封包順序錯亂)相當嚴重.我的解決方法是:偵測網路延遲時間(ping time delay),將此項延遲時間(加入sendbuf for loop中)加入封包傳送迴路中.就解決了影像亂掉問題. 發表人 - DavidLo 於 2005/12/10 21:35:59
cashyy
高階會員


發表:117
回覆:322
積分:212
註冊:2004-04-30

發送簡訊給我
#9 引用回覆 回覆 發表時間:2005-12-11 00:04:36 IP:59.104.xxx.xxx 未訂閱
DavidLo您好! 想請問您是如何偵測(網路延遲時間)的呢? 是否可將方法提供給有需求的人呢?
DavidLo
高階會員


發表:17
回覆:225
積分:168
註冊:2004-07-21

發送簡訊給我
#10 引用回覆 回覆 發表時間:2005-12-11 05:29:57 IP:218.169.xxx.xxx 未訂閱
參考研究,網路延遲時間TSWaitTime
void __fastcall TFormMain1::ClientSocket1Connect(TObject *Sender,
      TCustomWinSocket *Socket)
{
     ClientOK=true;
     if(language_mode==0)LabelConnectStatusN->Caption="網路連結成功!";
     else LabelConnectStatusN->Caption="Network connect success!";
     try
     {
     IdIcmpClient1->Host=CLIENT1;
     IdIcmpClient1->Ping();
     TSWaitTime=IdIcmpClient1->ReplyStatus.MsRoundTripTime;
     if(TSWaitTime<=5)TSWaitTime=5;
     }
     catch(...) { TSWaitTime=50; }
}
cashyy
高階會員


發表:117
回覆:322
積分:212
註冊:2004-04-30

發送簡訊給我
#11 引用回覆 回覆 發表時間:2005-12-12 00:43:49 IP:59.104.xxx.xxx 未訂閱
DavidLo您好! 小弟功力太低,不知可否解釋一下??謝謝!
DavidLo
高階會員


發表:17
回覆:225
積分:168
註冊:2004-07-21

發送簡訊給我
#12 引用回覆 回覆 發表時間:2005-12-12 11:10:36 IP:61.228.xxx.xxx 未訂閱
網路連結成功後,透過Indy元件IdIcmpClient1之Ping功能,回傳ReplyStatus.取出網路延遲時間,加入Sendbuf迴路中如下.
    if(ClientOK)
      {
      FormMain1->ClientSocket1->Socket->SendBuf(temp, 2002);
      ::Sleep(TSWaitTime);
      }
當時測試,若於內部網路是不需延遲.影像傳送非常即時漂亮.但透過internet卻出現許多錯誤,加延遲後錯誤率降低,但影像傳輸就有延遲現象,抓不到適當延遲時間,突發奇想將Ping的網路延遲時間加入Sendbuf迴路中,這樣子不管內部或外部網路皆適用,影像傳送從此就不再出現亂掉情況.
antonov_lin
一般會員


發表:5
回覆:11
積分:8
註冊:2005-08-23

發送簡訊給我
#13 引用回覆 回覆 發表時間:2005-12-12 13:02:38 IP:220.130.xxx.xxx 未訂閱
cashyy and DavidLo 兩位你好, 我目前是在公司內部區網實作, 實際上也發現, 如果資料量很小 (例如只有幾 個byte), 的確是沒有 loss 的問題, 但是對於螢幕畫面來說, 資料量並不小, 勢必要分解成幾個資料包, 若分成小資料包, 資料包數量就會很多, 我猜想就 會有比較大的機率出錯, 所以我才選擇減少資料包數量的方式去做; 另外, 請 教一下如果要能跨出區網, 那又該怎麼做呢 ? 能否指教. Indy 元件用起來沒有問題嗎 ? 那為什麼又會有更新版本出現嗎 ? 看過站上 有不少討論及文章是用 Indy 元件來實作的, 真是讓我很想要用又有點不敢用.
cashyy
高階會員


發表:117
回覆:322
積分:212
註冊:2004-04-30

發送簡訊給我
#14 引用回覆 回覆 發表時間:2005-12-12 13:40:57 IP:140.127.xxx.xxx 未訂閱
引言: cashyy and DavidLo 兩位你好, 我目前是在公司內部區網實作, 實際上也發現, 如果資料量很小 (例如只有幾 個byte), 的確是沒有 loss 的問題, 但是對於螢幕畫面來說, 資料量並不小, 勢必要分解成幾個資料包, 若分成小資料包, 資料包數量就會很多, 我猜想就 會有比較大的機率出錯, 所以我才選擇減少資料包數量的方式去做; 另外, 請 教一下如果要能跨出區網, 那又該怎麼做呢 ? 能否指教. Indy 元件用起來沒有問題嗎 ? 那為什麼又會有更新版本出現嗎 ? 看過站上 有不少討論及文章是用 Indy 元件來實作的, 真是讓我很想要用又有點不敢用.
您好! 個人覺得將封包大小變大會比較容易loss,因為在internet傳輸時,可能傳到一半,後面另一半的資料就loss了!我目前是用1k來測試啦! 請留您的mail,寄給您我目前的程式!
antonov_lin
一般會員


發表:5
回覆:11
積分:8
註冊:2005-08-23

發送簡訊給我
#15 引用回覆 回覆 發表時間:2005-12-12 15:34:06 IP:220.130.xxx.xxx 未訂閱
cashyy, 你好, 我的郵件位址是 nexee_lin@wistron.com.tw 請問, 你的程式可以跨過區域網路嗎 ?
DavidLo
高階會員


發表:17
回覆:225
積分:168
註冊:2004-07-21

發送簡訊給我
#16 引用回覆 回覆 發表時間:2005-12-12 17:35:51 IP:61.228.xxx.xxx 未訂閱
大家好! 點對點傳輸,需注意防火牆問題. 封包我同意1K是很棒的選擇!我用的是2K. 聽說如何穿透防火牆,才是關鍵所在.
cashyy
高階會員


發表:117
回覆:322
積分:212
註冊:2004-04-30

發送簡訊給我
#17 引用回覆 回覆 發表時間:2005-12-12 23:42:59 IP:59.104.xxx.xxx 未訂閱
引言: cashyy, 你好, 我的郵件位址是 nexee_lin@wistron.com.tw 請問, 你的程式可以跨過區域網路嗎 ?
您好! 已寄給您了!不過我把(重送封包機制、收到loss封包處理的功能拿掉了),因為寫的太亂,怕您看不懂,如果您需要的話,我可以再放上來讓您參考!說參考好像不對喔!應該說討論啦! 我的程式可以跨區網,可是封包還會loss,要等到期末考完,才會試DavidLo大大的"網路延遲時間",所以目前還沒加上偵測網路延遲時間的功能。 (這是個人測試的程式啦,寫的不好,請大大多指導)。 再次感謝DavidLo大大提供程式碼!謝謝 發表人 - cashyy 於 2005/12/13 00:00:09
Ktop_Robot
站務副站長


發表:0
回覆:3511
積分:0
註冊:2007-04-17

發送簡訊給我
#18 引用回覆 回覆 發表時間:2007-04-18 17:32:21 IP:000.000.xxx.xxx 未訂閱
提問者您好:


以上回應是否已得到滿意的答覆?


若已得到滿意的答覆,請在一週內結案,否則請在一週內回覆還有什麼未盡事宜,不然,
將由版主(尚無版主之區域將由副站長或站長)自由心證,選擇較合適之解答予以結案處理,
被選上之答題者同樣會有加分獎勵同時發問者將受到扣 1 分的處分。不便之處,請見諒。


有問有答有結案,才能有良性的互動,良好的討論環境需要大家共同維護,感謝您的配合。

------
我是機器人,我不接受簡訊.
系統時間:2024-03-29 17:31:57
聯絡我們 | Delphi K.Top討論版
本站聲明
1. 本論壇為無營利行為之開放平台,所有文章都是由網友自行張貼,如牽涉到法律糾紛一切與本站無關。
2. 假如網友發表之內容涉及侵權,而損及您的利益,請立即通知版主刪除。
3. 請勿批評中華民國元首及政府或批評各政黨,是藍是綠本站無權干涉,但這裡不是政治性論壇!