none
無法顯示圖片?? RRS feed

  • 問題

  • 下面是小弟寫的接收圖片的程式

    debuge一切ok

    但當程式在執行時卻無法顯示傳輸過來的圖片

    pictureBox1.Image = Image.FromStream(mem);這行是出錯的地方,顯示如下狀況

    類型 'System.Runtime.InteropServices.ExternalException' 的未處理例外狀況發生於 system.drawing.dll

    其他資訊: 在 GDI+ 中發生泛用錯誤。

    請問是什麼部分有問題嗎

    找了好久想了很久還是不知道問題出在哪邊

    請給予指導...謝謝

     

    IPHostEntry serverIP = Dns.Resolve(Dns.GetHostName());
       
       IPAddress ipAddress = serverIP.AddressList[0];
       
       IPEndPoint local=new IPEndPoint(ipAddress,6800);  //主機IP與Port

       TcpListener tcpListener = new TcpListener(local) ; //接聽用戶端連接伺服端IP與port
       
       try
       {
        tcpListener.Start() ;  //開始接聽
       }

       catch (SocketException ex) //處理例外情況
       {
        return;
       }

       while(true)
       {
        TcpClient clientSocket=tcpListener.AcceptTcpClient();  //建立新的用戶端連結

        NetworkStream networkStream = clientSocket.GetStream();  //取得用戶端輸出入資料流
        
        int bytesread;

        if(networkStream.CanRead)  //如果資料流可接收
        {
         MemoryStream mem = new MemoryStream() ;  //建立資料流
         byte[] byteimg = new byte[1024];  //設暫存陣列

         while(networkStream.DataAvailable)  //測試dataavailable
         {
          try
          {
           bytesread = networkStream.Read(byteimg, 0, byteimg.Length);  //接收資料流
          }
          catch (SocketException ex) //處理例外情況
          {
           break;
          }
          mem.Write(byteimg, 0, byteimg.Length);  //寫入memorystream
          pictureBox1.Image = Image.FromStream(mem);  //接收圖片顯示到PICTUREBOX
          
          clientSocket.Close();
         }
      

        }
       
        else  //無法連接
        {
         return;
        }
       }

    2006年11月5日 下午 02:38

所有回覆

  • 這是小弟所寫的傳送圖片的程式

    順便附上

    希望可以找出無法顯示圖片的原因

    TcpClient tcpClient =  new TcpClient();  //產生TcpClient物件

       IPAddress serverAddress = Dns.Resolve(textBox1.Text).AddressList[0] ;  //伺服端IP位址
       
       try
       { 
        tcpClient.Connect(serverAddress,Int32.Parse(textBox2.Text));  //連線到指定伺服器
       }

       catch (SocketException ex)  //例外發生狀況
       {
        listBox1.Items.Add("Could not establish connection to Server!!!");
        return;
       }

       listBox1.Items.Add("Successfully establish connection to Server!!!");  //listBox顯示成功連結

       NetworkStream networkStream = tcpClient.GetStream();  //取得網路傳輸串流

       if(networkStream.CanWrite)  //如果可以傳輸資料流
       {
        MemoryStream mem = new MemoryStream() ;  //建立資料流
     
        pictureBox1.Image.Save(mem,System.Drawing.Imaging.ImageFormat.Bmp);  //取得指定影像與格式

        byte[] data = mem.ToArray();  //將資料流寫入資料流陣列
         
        networkStream.Write(data, 0, data.Length);  //傳送資料流

       }
       else  //無法連接
       {
        //listBox1.Items.Add("You cannot write data to this stream.");
        //tcpClient.Close();  //關閉用戶端窗口
        return;
       }
       
       tcpClient.Close();

    2006年11月5日 下午 02:51
  • 圖片資料確定有完全接收到?

        if(networkStream.CanRead)  //如果資料流可接收
        {
         MemoryStream mem = new MemoryStream() ;  //建立資料流
         byte[] byteimg = new byte[1024];  //設暫存陣列

         while(networkStream.DataAvailable)  //測試dataavailable
         {
          try
          {
           bytesread = networkStream.Read(byteimg, 0, byteimg.Length);  //接收資料流
          }
          catch (SocketException ex) //處理例外情況
          {
           break; // 發生錯誤直接中斷?
          }
          mem.Write(byteimg, 0, byteimg.Length);  //寫入memorystream // 才第一次收到資料就要顯示?資料有接全嗎?
          pictureBox1.Image = Image.FromStream(mem);  //接收圖片顯示到PICTUREBOX
          
          clientSocket.Close();
         } 

    2006年11月5日 下午 03:25
    版主
  • 那請問小朱前輩

    要如何確定每一次的傳輸都已將資料接收完全了呢

    因為目前構想在於寫在while迴圈裏面

    在建立好連線之後

    就將資料流接收到設的陣列當中

    再透過Image.FromStream將圖片顯示出來

    並且可以不斷的接收用戶端的請求

    請問小朱前輩要如何去修改呢

    謝謝

    2006年11月7日 下午 04:33
  • NetworkStream 中有沒有資料,可由 DataAvailable 來判斷,有資料可讀時都會是 true.

    如果你要實作一直可以聆聽 Client 的 Server,那你可以考量幾個部份:

    • Server 的 TcpListener 不能關閉,要一直保持聆聽狀態 .
    • 一旦 Server 使用 AcceptTcpClient() 收到用戶端的訊息時,交由新的 thread 去執行收取資料或溝通的工作 .
    • 設定 TcpClient 的收納陣列(可考慮用 Array 或 ArrayList 實作),這樣可以限制最大的連線數量 .

    以下程式碼取自 .NET Framework SDK 文件,你可以參考看看:

        TcpListener server=null;  
        try
        {
          // Set the TcpListener on port 13000.
          Int32 port = 13000;
          IPAddress localAddr = IPAddress.Parse("127.0.0.1");
         
          // TcpListener server = new TcpListener(port);
          server = new TcpListener(localAddr, port);

          // Start listening for client requests.
          server.Start();
            
          // Buffer for reading data
          Byte[] bytes = new Byte[256];
          String data = null;

          // Enter the listening loop. 注意,不能讓 server 停止聆聽
          while(true)
          {
            Console.Write("Waiting for a connection... ");
           
            // Perform a blocking call to accept requests.
            // You could also user server.AcceptSocket() here.
            // TODO: 可以考慮使用另外的執行緒來處理這個 TcpClient
            // 如果 Server 是可見的 Windows Form,可以試試看 BackgroundWorker 這個元件 .
            TcpClient client = server.AcceptTcpClient();        
       
            Console.WriteLine("Connected!");

            data = null;

            // Get a stream object for reading and writing
            NetworkStream stream = client.GetStream();

            int i;

            // Loop to receive all the data sent by the client.
            while((i = stream.Read(bytes, 0, bytes.Length))!=0)
            {  
              // Translate data bytes to a ASCII string.
              data = System.Text.Encoding.ASCII.GetString(bytes, 0, i);
              Console.WriteLine("Received: {0}", data);
          
              // Process the data sent by the client.
              data = data.ToUpper();

              byte[] msg = System.Text.Encoding.ASCII.GetBytes(data);

              // Send back a response.
              stream.Write(msg, 0, msg.Length);
              Console.WriteLine("Sent: {0}", data);           
            }
            
            // Shutdown and end connection
            client.Close();
          }
        }
        catch(SocketException e)
        {
          Console.WriteLine("SocketException: {0}", e);
        }
        finally
        {
           // Stop listening for new clients. 到要結束 Server 時才停止聆聽 .
           server.Stop();
        }

    2006年11月8日 上午 03:16
    版主
  • while(true)
       {
        TcpClient clientSocket=tcpListener.AcceptTcpClient();  //建立新的用戶端連結

        NetworkStream networkStream = clientSocket.GetStream();  //取得用戶端輸出入資料流
        
        pictureBox1.Image = Image.FromStream(mem);
        while(networkStream.DataAvailable) 
        {
         MemoryStream mem = new MemoryStream() ;  //建立資料流
         try
          {
           mem.Write(byteimg, 0, byteimg.Length);  //寫入memorystream
          }
          catch (SocketException ex) //處理例外情況
          {
          }
          pictureBox1.Image = Image.FromStream(mem);  //接收圖片顯示到PICTUREBOX
          
          clientSocket.Close();
         }
      

        }

    小朱前輩

    小弟將接收部分改成以上這樣

    在接收的過程中卻出現以下

    pictureBox1.Image = Image.FromStream(mem);//此行出錯

    類型 'System.ArgumentException' 的未處理例外狀況發生於 system.drawing.dll

    其他資訊: 使用無效的參數。

    請問還是資料沒有接收完全的關係嗎

    還是我的client有需要改善的地方

    還是小弟對於小朱前輩回覆的文章有弄錯意思的地方

    望小朱前輩給與指正

    2006年11月9日 上午 09:26
  •  Jelcass 寫信:

    while(true)
       {
        TcpClient clientSocket=tcpListener.AcceptTcpClient();  //建立新的用戶端連結

        NetworkStream networkStream = clientSocket.GetStream();  //取得用戶端輸出入資料流
        
        pictureBox1.Image = Image.FromStream(mem);
        while(networkStream.DataAvailable) 
        {
         MemoryStream mem = new MemoryStream() ;  //建立資料流
      // 註:這樣做不就前面收的都白搭了嗎?
         try
          {
           mem.Write(byteimg, 0, byteimg.Length); 
      //寫入memorystream 註:你如何這麼肯定才跑一次就可以收到所有的資料?

          }
          catch (SocketException ex) //處理例外情況
          {
          }
          pictureBox1.Image = Image.FromStream(mem);  //接收圖片顯示到PICTUREBOX
          
          clientSocket.Close();
         }
      

        }

    我比較好奇你改了哪裡 ...
    你怎麼能這麼肯定傳來的資料能夠一次接收完畢?
    前次程式我幫你註記的地方好像都沒改吧 ...

    你要不要真的先去了解一下網路資料的傳輸方法(Network I/O)再回來思考這個問題?
    之前我好像也對你這麼說過 ....

    我也回應過這樣的文章:http://forums.microsoft.com/msdn-cht/ShowPost.aspx?PostID=663174&SiteID=14

    這裡也有類似的討論串:http://www.programmer-club.com/pc2020v5/forum/ShowSameTitleN.asp?board_pc2020=csharp&id=7206&szKeyword=NetworkStream 

    你也可以回去看一下你問過的問題,好像都是植基在:你不夠了解網路的資料傳輸模式 .

    順便把我在別的討論區的回應也貼過來:

    NetworkStream.Read() 會傳回讀取資料的位元組數,你可以使用這個數值來控制目前資料的讀取位置 .

    假設你的 size 設定為 32768 ,若你的資料量很大:

    1. 32768 bytes
    2. +30829 bytes
    3. +29881 bytes
    4. +29911 bytes
    5. +32202 bytes
    6. +30991 bytes
    ....
    直到傳送完畢 .


    所以你可以設定一個目前讀取量的值,來控制目前資料已經讀到哪裡 .

    希望你真的去了解,再來思考這個問題,其實你之前不是已經有寫出來了嗎:
    http://forums.microsoft.com/MSDN-CHT/ShowPost.aspx?PostID=819795&SiteID=14

    2006年11月9日 上午 10:13
    版主
  • 小朱,那段 TcpClient 的程式碼看得好眼熟喔~ 好像是在新加坡我們兩個躲在 Developer Room 最後面討論的那段

    建議在無限回圈內加入:

    System.Threading.Thread.Sleep(1) 

    讓執行緒睡一下,來等新資料從網路進來,也把 CPU 資源放出來

    我先前是睡 0 毫秒,還是太吃 cpu 了,現在改睡 1 毫秒...

    另外給原提問者:

    Image 從 Stream 來的時候,即使位元組都正確,仍有可能無法識別,在 .Net 1.1 問題比較嚴重,到了 .Net 2.0 後,Image 類別有改善,問題變少了,但是仍有部分圖無法識別,建議你傳遞時,附帶檔名,主要是圖檔格式,然後存檔再讀讀看,Image 從 File 來的時候,會參考檔名來判斷圖檔類型,從 Stream 來的時候,是依據檔頭試解,這部份機制有點問題,在 VS2003 時有回報給 CSS ,也確認過是一個 bug,不知道 VS2003 SP1 有沒有修復。

    通常是非 Full Color 的圖檔,比如說 256 色的 PNG 、2 色的 BMP 、GIF 之類的。

    我是在做 http://tlcheng.spaces.live.com/blog/cns!145419920BFD55A7!403.entry 的時候發現的,因為從檔案來會鎖住檔案,造成不能編輯或刪除,所以我先載入到 MemoryStream ,在讀圖,這時候就發生這樣的問題,因為例子很簡單,所以 CSS 那邊也確認過了,且歐洲已經有人先回報了,所以很快就以不扣點方式結案。

    2006年11月9日 下午 12:20
  • to 小朱前輩

    小弟不才...在這邊也爬文爬很久了

    之前小弟寫出來的程式只是能傳輸單張圖片

    所以之後就想說該如何能連續傳送圖片

    於是又找了c#網路程式設計這本書來k

    在k完之後對於網路server與client這兩方的連接有了完整個概念

    於是修改了目前po文的程式...但相對的卻無法成功傳輸

    正如小朱前輩指正的小弟對於網路傳輸資料的概念目前是不清的

    小朱前輩鎖指出的錯誤

    mem.Write(byteimg, 0, byteimg.Length);  //寫入memorystream // 才第一次收到資料就要顯示?資料有接全嗎?

    真的不知該如何下手

    那該如確定所收到的資料已經是完全的了呢

    小弟有用DataAvailable來判斷NetworkStream 中有沒有資料

    while(true)
       {
        TcpClient clientSocket=tcpListener.AcceptTcpClient();  //建立新的用戶端連結

        NetworkStream networkStream = clientSocket.GetStream();  //取得用戶端輸出入資料流
        MemoryStream mem = new MemoryStream() ;  //建立資料流 
        if(networkStream.CanRead)  //如果資料流可接收
        {
         byte[] byteimg = new byte[1024];  //設暫存陣列

         while(networkStream.DataAvailable)  //測試dataavailable
         {
          mem.Write(byteimg, 0, byteimg.Length);  //要如何判斷已經接收到完全的資料呢?

          pictureBox1.Image = Image.FromStream(mem);  //接收圖片顯示到PICTUREBOX  
          clientSocket.Close();
         }

        }

       }

    那要是沒有接收完全該怎麼辦呢

    每次傳送的圖片大小約20k左右的bmp圖檔

    而小弟的程式加入多執行緒有幫助嗎

    因為小弟的資料都只會從一個client傳送過來

    最近也k了很多有關多執行緒的資料

    可是不知道該如何加入程式當中

    希望小朱前輩可以繼續給予幫助

    雖然小弟常問許多不是很好的問題

    謝謝

    2006年11月10日 上午 09:46
  • 迴圈一值收資料的,小朱有貼範例程式碼參考。

    個人建議是你每個圖檔傳遞前,先傳遞長度,這樣你在迴圈收資料時,收到目標長度後,後面的會是下個圖檔。

    比如說,Server 端傳出

    100 abcdefg...到100 50 abcde...到50

    是網路傳輸速度,可能一次進緩衝區,也有可能只收到部份,所以 tcpip 現有所有的協定,都有交談這部份,會定義到怎樣資料才傳完,所以你也必須定義如何交談,純粹傳檔,client 端是無法切割資料的。

    比如上面分二次均勻收到,所以一開始你收到 2 + 75 bytes ,前面 2 bytes 是資料長度,你就可以知道目前才收到 75/100 ,後面又收到 2 + 75 bytes 時,你就可以先切 25 bytes 把前面完檔,再讀 2 bytes ,知道下一個檔是 50 bytes 。

    2006年11月10日 下午 12:46
  • 請問前輩你建議我在每個圖檔傳輸前先傳遞長度

    請問前輩該如何先傳遞資料長度呢

    小弟對於網網I/O不是很清楚

    可否請前輩說的清楚一些呢

    小弟目前不清楚的是在傳送端將資料傳送出去後

    if(networkStream.CanWrite)  //如果可以傳輸資料流
       {
        MemoryStream mem = new MemoryStream() ;  //建立資料流
     
        pictureBox1.Image.Save(mem,System.Drawing.Imaging.ImageFormat.Bmp);  //取得指定影像與格式

        byte[] data = mem.ToArray();  //將資料流寫入資料流陣列
         
        networkStream.Write(data, 0, data.Length);  //傳送資料流

       }

    以上程式將資料傳輸到網路上

    應該是已確定將完整的資料傳輸上去

    小朱前輩說小弟接收端程式無法判斷是否已經將傳上網路的資料都接收下來

    這是小弟不懂的地方

    小弟看網路程式設計的書...在接收傳輸這部份的例子都是一般的文字傳輸

    他們都是直接傳輸與接收

    是否是因為傳輸圖片跟一般文字的難度是有差的嗎

    為什麼傳團片的話接收端會沒將資料都接收完畢呢

           mem.Write(byteimg, 0, byteimg.Length); 
      //寫入memorystream 註:你如何這麼肯定才跑一次就可以收到所有的資料?

    上面是小朱前輩指出的錯誤

     那寫迴圈多讓他跑幾次就可以完全接收到了嗎

    最後小弟的疑問是

    使用多執行緒去處理有好處嗎

    在接收圖片的步驟交給另外的thread執行緒去處理

    情況可以改善資料接收不完全的情形嗎

    小弟不懂該怎麼定義資料是否已經接收完全

    還有定義如何交談

    可以舉個例子嗎

    希望前輩給予幫助

     

    2006年11月15日 上午 09:56
  • 隨便挑個協定,比如說 FTP ,標準該怎樣傳?就是一個例子。
    2006年11月15日 下午 12:26
  • 謝謝前輩提示

    請問哪裡有ftp的例子可以參看呢

    2006年11月15日 下午 01:56
  • 我自己早期在 VB5 的作法:

    http://tlcheng.twbbs.org/TLCheng/Hermes/sendfile.htm

    2006年11月15日 下午 02:39
  • 前輩

    小弟不會vb程式.....所以看不懂

    是否可以提供c#程式的例子呢

    2006年11月15日 下午 03:35
  • 請問前輩該如何先傳遞資料長度呢

    小弟對於網網I/O不是很清楚

    可否請前輩說的清楚一些呢

    小弟目前不清楚的是在傳送端將資料傳送出去後

    if(networkStream.CanWrite)  //如果可以傳輸資料流
       {
        MemoryStream mem = new MemoryStream() ;  //建立資料流
     
        pictureBox1.Image.Save(mem,System.Drawing.Imaging.ImageFormat.Bmp);  //取得指定影像與格式

        byte[] data = mem.ToArray();  //將資料流寫入資料流陣列
         
        networkStream.Write(data, 0, data.Length);  //傳送資料流

       }

    以上程式將資料傳輸到網路上

    應該是已確定將完整的資料傳輸上去

    前輩說小弟接收端程式無法判斷是否已經將傳上網路的資料都接收下來

    這是小弟不懂的地方

    小弟看網路程式設計的書...在接收傳輸這部份的例子都是一般的文字傳輸

    他們都是直接傳輸與接收

    是否是因為傳輸圖片跟一般文字的難度是有差的嗎

    為什麼傳團片的話接收端會沒將資料都接收完畢呢

           mem.Write(byteimg, 0, byteimg.Length); 
      //寫入memorystream 註:你如何這麼肯定才跑一次就可以收到所有的資料?

    上面是前輩指出的錯誤

     那寫迴圈多讓他跑幾次就可以完全接收到了嗎

    最後小弟的疑問是

    使用多執行緒去處理有好處嗎

    在接收圖片的步驟交給另外的thread執行緒去處理

    情況可以改善資料接收不完全的情形嗎

    小弟不懂該怎麼定義資料是否已經接收完全

    還有定義如何交談

    希望前輩給予幫助

     

    2006年11月15日 下午 03:38
  • 也沒人跟你說過文字就會一次傳完。

    一般來說,在 Windows 內建設定上,數據機是每 512 bytes 切一次,寬頻是 1500 bytes 切一次。

    所以我習慣 Buffer 用 512 bytes 。

    交談就是兩方所用的命令,大部分是用字串,若是要快一點的話,可以自己定義用整數列舉,例如說:

    1 代表完成

    2 代表重傳

    3 代表長度

    4 代表位元陣列 (註:一般字串傳遞不會直接丟,免得用 Unicode 傳,通常會先轉為 Ascii 或是 big5)

    送出端:

    所以寫入 MemoryStream 可以先寫入 3 再寫入 Buffer.Length (或剩餘的 bytes 數) 再寫入 Buffer (Buffer 可扣掉 8 bytes 來讓一次剛好 512 bytes ,也可以不管,讓 Windows 自己切,讓 Windows 自己切,則大部分人習慣用 4 kb 或 32 kb),等待 接收端 回應

    接收端:

    讀 Int16 分析得到是位元組長度的命令,讀 Int16 分析得到是長度,讀指定長度的位元組,這時有可能還沒傳完,要用迴圈持續讀,前面小朱有給你程式碼範例。達到指定長度位元組時,傳回 1 ,若逾時還未達到指定長度位元組時,傳回 2 。

    送出端依據接收端回傳訊息,決定繼續往下傳或重傳這段。

    若是自定的列舉值有 Offset 之類的定義,就可以開多緒同時傳一個檔或位元陣列。

    2006年11月16日 上午 12:23
  • 前輩

    謝謝你所說的網路傳輸的概念

    可是小弟在閱讀有關於網路程式設計的書籍

    都沒有提到這些

    所以總是只會將連結給建立好

    但要怎樣建立完整的傳輸方式卻是完全不懂

    只是知道把要傳輸的檔案丟到資料流裡面去傳輸

    然後接收將它接收下來

    完全不知道還要考慮網路頻寬速度的問題

    所傳輸的檔案接收不完全的問題

    書中也沒寫

    請問有這方面詳細介紹如何傳輸檔案的書籍可以k嗎

    因為沒有範例...小弟程式功力又不足

    實在不知該如何下手

    2006年11月27日 下午 01:21