2012-07-24 31 views
1

我試圖通過套接字將圖像作爲字節數組發送到客戶端,以便它可以查看圖像,並且一切都很順利,除了查看圖像時它的碎片,我可以查看頂部的第10張圖像的,但它的其餘部分是灰色和黑色的像素和我無法弄清楚,爲什麼插槽上的碎片圖像字節數組

繼承人一塊我的服務器代碼:

public synchronized void nextFrame(VideoFrame frame) { 
     // This method is called when a new frame is ready. 
     // Don't forget to recycle it when done dealing with the frame. 

     // draw the new frame onto the JLabel 
      go = true; 
      pic = frame.getBytes(); 
      go = false; 
      label.getGraphics().drawImage(frame.getBufferedImage(), 0, 0, width, height, null); 
      frame.recycle(); 

    } 
} 

class server extends Thread{ 
    int port; 
    ServerSocket socket; 
    Socket temps = null; 
    boolean go = true; 
    server(int p){ 
     port = p; 
     start(); 
    } 

    public void run(){  

     while(go == true){ 
      try { 
       socket = new ServerSocket(port, 10); 
       socket.setSoTimeout(10000); 
       temps = socket.accept(); 
       new connect(temps); 
       port += 1; 
      } catch (IOException e) { 
       if(e.getMessage().toString().equalsIgnoreCase("Accept timed out")){ 
        go = false; 
       }else{ 
        e.printStackTrace(); 
       } 
       break; 
      } 

     } 
     try { 
      socket.close(); 
      System.out.println("Closing socket server(no more connections will be created)"); 
     } catch (IOException e) { 
      e.printStackTrace(); 
     } 
    } 
} 

class connect extends Thread{ 
    Socket connection; 
    ObjectOutputStream out; 
    int port; 
    String host; 
    GetInput in; 
    connect(Socket s){ 
     try { 
      connection = s; 
      out = new ObjectOutputStream(connection.getOutputStream()); 
      host = connection.getInetAddress().getHostName(); 
      port = connection.getPort(); 
      System.out.println("Connected to " + host + ":" + port); 
      in = new GetInput(connection); 
      start(); 
     } catch (IOException e) { 
      e.printStackTrace(); 
     } 
    } 

    public void run(){ 
     try { 
      out.writeInt(Main.pic.length); 
     } catch (IOException e1) { 
      e1.printStackTrace(); 
     } 
     while(in.isAlive()){ 
      if(Main.go){  
       try { 
        out.write(Main.pic); 
       } catch (IOException e) { 
         e.getMessage().toString(); 
       } 
      } 
     } 
     try { 
      out.close(); 
      connection.close(); 
      System.out.println("Closing " + host + ":" + port); 
     } catch (IOException e) { 
      e.printStackTrace(); 
     } 
    } 
} 
class GetInput extends Thread{ 
    ObjectInputStream in; 
    GetInput(Socket s){ 
     try { 
      in = new ObjectInputStream(s.getInputStream()); 
     } catch (IOException e) { 
      e.printStackTrace(); 
     } 
     start(); 
    } 
    public void run(){ 
     try{ 
      boolean go = in.readBoolean(); 
      int a = (go?1:0); 
      System.out.println(a); 
     } catch (IOException e) { 
       e.getMessage().toString(); 
     } 
     try { 
      in.close(); 
     } catch (IOException e) { 
      e.printStackTrace(); 
     } 
    } 
} 

我知道圖像採集卡是正確的,因爲IM抓住圖像也顯示在服務器上的圖像,它看起來很好,這意味着字節數組不正確地發送通過套接字,但爲什麼?

編輯:繼承人我的客戶端代碼,它的Android應用

package org.smiley.doom; 

import java.io.IOException; 
import java.io.ObjectInputStream; 
import java.io.ObjectOutputStream; 

import java.net.InetAddress; 
import java.net.Socket; 
import java.net.UnknownHostException; 

import android.app.Activity; 
import android.graphics.Bitmap; 
import android.graphics.BitmapFactory; 
import android.os.Bundle; 
import android.view.View; 
import android.widget.Button; 
import android.widget.EditText; 
import android.widget.ImageView; 
import android.widget.TextView; 

public class ClientActivity extends Activity implements View.OnClickListener{ 

    Socket s; 
    InetAddress inet; 
    ObjectOutputStream out; 
    ObjectInputStream in; 
    TextView log; 
    ImageView im; 
    Button send; 
    EditText tip; 
    int rport; 
    String ip; 

    @Override 
    public void onCreate(Bundle savedInstanceState) { 
     super.onCreate(savedInstanceState); 
     setContentView(R.layout.main); 

     tip = (EditText) findViewById(R.id.etIP); 
     send = (Button) findViewById(R.id.bSEND); 
     im = (ImageView) findViewById(R.id.ivPIC); 
     log = (TextView) findViewById(R.id.tvLog); 

     s = null; 
     in = null; 
     out = null; 

     send.setOnClickListener(this); 
    } 

    @Override 
    public void onClick(View arg0) { 
     switch(arg0.getId()){ 
      case R.id.bSEND: 
       final int len; 
        try { 
         inet = InetAddress.getByName("192.168.0.2"); 
         s = new Socket(inet, 4321); 
         in = new ObjectInputStream(s.getInputStream()); 
         out = new ObjectOutputStream(s.getOutputStream()); 
         log.setText("Client opened"); 
         len = in.readInt(); 
         new Thread(new Runnable(){ 

          @Override 
          public void run() { 
            byte[] b = new byte[len]; 
            try { 
             in.read(b); 
             log.setText(""+s.getReceiveBufferSize()); 
            } catch (IOException e1) { 
             e1.printStackTrace(); 
            } 
            final byte[] l = b; 
            im.post(new Runnable(){ 
             @Override 
             public void run() { 
              Bitmap bmp = BitmapFactory.decodeByteArray(l, 0, l.length); 
              im.setImageBitmap(bmp);        
             } 
            }); 
            try { 
             out.writeBoolean(true); 
             out.close(); 
             in.close(); 
             s.close(); 
             //log.setText("Client closed"); 
            } catch (IOException e) { 
             e.printStackTrace(); 
            } 
          } 

         }).start();; 
        } catch (UnknownHostException e) { 
         e.printStackTrace(); 
        } catch (IOException e) { 
         e.printStackTrace(); 
        } 
      break; 
     } 
    } 
} 
+0

您需要發佈客戶端代碼。這是不完整的,無法回答。 – EJP 2012-07-25 07:24:32

回答

3

TCP只向當前可用的應用程序提供儘可能多的字節。由於底層網絡層(IP)是基於數據包的,因此在傳輸過程中,您的數據流將逐漸分塊。網絡堆棧在接收端將這些塊(數據包)從網卡中取出並緩存,直到應用程序從給定套接字讀取,此時您獲得緩衝區大小的min以及堆棧在OS每套接字緩衝區中的內容。

由於TCP連接代表,操作系統不知道任何有關您的應用程序消息,因此您有責任將所有事情重新組合在一起。

您必須從循環中讀取套接字,直到您知道所有數據。要知道最簡單的方法就是先告訴客戶端你要發送多少字節。

+0

你是上帝!謝謝!!! – MrFuzzles 2012-07-27 21:31:49

+1

令人毛骨悚然,但奉承... – 2012-07-28 22:44:54

0

機會是你的數據段(圖像)比你的緩衝區大得多。

不知何故,您必須找到一種緩衝輸出的方法,以便在溢出寫入緩衝區之前將其刷新。

+0

它似乎你的權利即時接收1020字節,當我需要接收37次,奇怪的是我檢查了我的接收緩衝區大小和我的發送緩衝區大小,他們都比圖片的大小更大其自我 – MrFuzzles 2012-07-25 04:17:22

0

Nikolai Fetissov的回答幫助我解決了這個問題。以下是我得到它的工作:

  1. 發送包含從發送預期消息 大小和消息類型接收器的JSON(或任何其他形式)。確保這是簡短而親切的。
  2. 立即發送您的數據。它可能是一個圖像/音頻/視頻或任何東西。

獎勵:這也適用於Android藍牙/ Wifi套接字。

代碼片段去:

byte[] fileBuffer = null; 
int bytes = 0, expectedFileSize = 0, messageType = Constants.TYPE_IMAGE; 
boolean isProcessing = false; 
while (isReading) { 
    try { 
     if (isProcessing) { 
      // Fragment arrived 
      byte[] buffer = new byte[1024]; 
      int currentSize = mmInStream.read(buffer); 

      // Keep appending to the fileBuffer 
      System.arraycopy(buffer, 0, fileBuffer, bytes, currentSize); 
      bytes += currentSize; 
      if (bytes == expectedFileSize) { 
       // Your message is ready. Send it! 
       sendIt(fileBuffer, messageType); 
       isProcessing = false; 
       bytes = 0; 
      } 
     } else { 
      byte[] buffer = new byte[1024]; 
      bytes = mmInStream.read(buffer); 
      try { 
       // Message is a JSON. Next set of messages will be audio or image. 
       JSONObject json = new JSONObject(new String(buffer, 0, bytes)); 
       expectedFileSize = json.getInt(Constants.MESSAGE_SIZE); 
       messageType = json.getInt(Constants.MESSAGE_TYPE); 
       fileBuffer = new byte[expectedFileSize]; 
       isProcessing = true; 
       bytes = 0; 
      } catch (JSONException e) { 
       // This is a normal message. Send it without processing. 
       sendIt(buffer, Constants.TYPE_TEXT); 
       isProcessing = false; 
       bytes = 0; 
      } 
     } 
    } catch (IOException e) { 
     e.printStackTrace(); 
    } 
} 

編輯的代碼來優化其進一步的歡迎!希望這可以幫助。