【问题标题】:Android send image over socket, but always receiving empty on server sideAndroid通过套接字发送图像,但总是在服务器端接收空
【发布时间】:2016-08-20 17:10:12
【问题描述】:

我使用Socket 发送位图,其中客户端是我的.apk,服务器是Delphi 可执行文件。

位图发送成功,但在服务器上接收时,Bitmap 为空,大小为 0KB。

所以,如果可能的话,我想要任何建议或解决方案,以解决这个问题。

到目前为止,这是我的代码:

Android(客户端)

public class MainActivity extends Activity {

    Socket clientSocket;

    private static final int SERVERPORT = 60;
    private static final String SERVER_IP = "192.168.25.227";

    byte[] tmpbytes = null;


    @Override
    protected void onCreate(Bundle savedInstanceState) {

        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

        new Thread(new ClientThread()).start();

    }

        public Bitmap takeScreenshot() {

           View rootView = findViewById(android.R.id.content).getRootView();
           rootView.setDrawingCacheEnabled(true);
           return rootView.getDrawingCache();

        }

        public void getBytes() throws IOException {

            try
            {

            Bitmap bmp = takeScreenshot();

            int bytes = bmp.getByteCount();
            ByteBuffer buffer = ByteBuffer.allocate(bytes); 
            bmp.copyPixelsToBuffer(buffer); 

            byte[] array = buffer.array(); 
            int start=0;
            int len=array.length;
            if (len < 0)
            throw new IllegalArgumentException("Negative length not allowed");
            if (start < 0 || start >= array.length)
            throw new IndexOutOfBoundsException("Out of bounds: " + start);

            OutputStream out = clientSocket.getOutputStream(); 
            DataOutputStream dos = new DataOutputStream(out);

            dos.writeInt(len);
            if (len > 0) {
            dos.write(array, start, len);
            }



          }

            catch (UnknownHostException e) {
                //System.out.println(e.toString());
            } 

            catch (IOException e) {
                //System.out.println(e.toString());
            } 

            catch (Exception e1) {
                //Log.e("clients", e1.toString());
                //Toast.makeText(MainActivity.this, e1.toString(), Toast.LENGTH_LONG).show();
                System.out.println(e1.toString());
            }

        }

        class ClientThread implements Runnable { 

            @Override
            public void run() {

                try {

                    InetAddress serverAddr = InetAddress.getByName(SERVER_IP);

                    clientSocket = new Socket(serverAddr, SERVERPORT);

                    //new Thread(new CommsThread()).start();

                    Thread.sleep(1000);

                    getBytes();

                } catch (Exception e1) {
                    //Log.e("clients", e1.toString());
                    //Toast.makeText(MainActivity.this, e1.toString(), Toast.LENGTH_LONG).show();
                    System.out.println(e1.toString());
                } 

            }
        }

}

Delphi(服务器)

var
 Form1: TForm1;

stSize: integer;   
Stream: TMemoryStream; 
bmp: TBitmap; 
FSize: Integer;
writing: Boolean;

procedure TForm1.FormCreate(Sender: TObject);
begin
Stream:= TMemoryStream.Create;
writing:= False;
end;

procedure TForm1.ServerSocket1ClientRead(Sender: TObject;
  Socket: TCustomWinSocket);
var
  BytesReceived: Longint;
  CopyBuffer: Pointer; { buffer for copying }
  ChunkSize: Integer;
  TempSize: Integer;
const
  MaxChunkSize: Longint = 8192; { copy in 8K chunks }
begin

  If FSize=0 then
  begin
    If Socket.ReceiveLength>SizeOf(TempSize) then
    begin
      Socket.ReceiveBuf(TempSize,SizeOf(TempSize));
      Stream.SetSize(TempSize);
      FSize:= TempSize //Threadsafe code!
    End;
  End;

  If (FSize>0) and not(writing) then
  begin
    GetMem(CopyBuffer, MaxChunkSize); { allocate the buffer }
    writing:= True;
    While Socket.ReceiveLength>0 do
    Begin
      ChunkSize:= Socket.ReceiveLength;
      If ChunkSize > MaxChunkSize then ChunkSize:= MaxChunkSize;
      BytesReceived:= Socket.ReceiveBuf(CopyBuffer^,ChunkSize);
      Stream.Write(CopyBuffer^, BytesReceived); { ...write chunk }
      Dec(FSize,BytesReceived);
    End;
  end;

  If FSize=0 then begin

  Stream.Position := 0;
  bmp:=TBitmap.Create; 
  bmp.LoadFromStream(Stream); 
  Image1.Picture.Graphic := bmp; 
  Stream.SetSize(0);
  bmp.Free;
  FSize:= 0;
end;

FreeMem(CopyBuffer, MaxChunkSize); { allocate the buffer }
Writing:= False;
end;

在 Remy Lebeau 的建议下,我所做的更改仍然不起作用 :-(

德尔福

procedure TForm1.ServerSocket1ClientRead(Sender: TObject;
  Socket: TCustomWinSocket);
var
  BytesReceived: Longint;
  CopyBuffer: Pointer;
  ChunkSize: Integer;
  TempSize: Integer;
const
  MaxChunkSize: Longint = 8192;
begin

  If FSize=0 then
  begin
    If Socket.ReceiveLength>SizeOf(TempSize) then
    begin
      Socket.ReceiveBuf(TempSize,SizeOf(TempSize));
      TempSize := ntohl(TempSize); // Changed to ntohl
      Stream.SetSize(TempSize);
      FSize:= TempSize
    End;
  End;

  If (FSize>0) and not(writing) then
  begin
    GetMem(CopyBuffer, MaxChunkSize);
    writing:= True;
    While Socket.ReceiveLength>0 do
    Begin
      ChunkSize:= Socket.ReceiveLength;
      If ChunkSize > MaxChunkSize then ChunkSize:= MaxChunkSize;
      BytesReceived:= Socket.ReceiveBuf(CopyBuffer^,ChunkSize);
      Stream.Write(CopyBuffer^, BytesReceived);
      Dec(FSize,BytesReceived);
    End;
  end;

  If FSize=0 then begin

  Stream.Position := 0;
  png:=TPngImage.Create;  // Changed to TPNGImage here
  png.LoadFromStream(Stream);
  Image1.Picture.Assing(png);
  Stream.SetSize(0);
  png.Free;
  FSize:= 0;
end;

FreeMem(CopyBuffer, MaxChunkSize);
Writing:= False;
end;

Android

public void getBytes() throws IOException {

            try
            {

            Bitmap bmp = takeScreenshot();

            ByteArrayOutputStream bos = new ByteArrayOutputStream(); 
            bmp.compress(CompressFormat.PNG, 0 /*ignored for PNG*/, bos); 
            byte[] array = bos.toByteArray();
            OutputStream out = socket.getOutputStream(); 
            DataOutputStream dos = new DataOutputStream(out);
            dos.writeInt(array.length);
            dos.write(array, 0, array.length);

          }

            catch (UnknownHostException e) {
                //System.out.println(e.toString());
            } 

            catch (IOException e) {
                //System.out.println(e.toString());
            } 

            catch (Exception e1) {
                //Log.e("clients", e1.toString());
                //Toast.makeText(MainActivity.this, e1.toString(), Toast.LENGTH_LONG).show();
                System.out.println(e1.toString());
            }

        }

【问题讨论】:

  • 再一次,你没有花时间描述你的代码应该做什么和真正做什么。您只是在倾倒大量代码。已经是第三次了。
  • I'm sending a Bitmap using Socket。不。您正在发送字节数组的len 字节。您用位图中的像素填充了字节数组。在服务器端,您应该收到len 字节。现在你在服务器上收到了什么?您抱怨位图的大小为 0。但位图仅在之后从接收到的字节构造,所以起初无关紧要。现在准确地告诉你发送了多少字节,你收到了多少。从一些基本的调试开始。
  • @greenapps,在服务器端:Socket.ReceiveLength 接收大小为 4。`
  • 我看到您上次询问时仍未接受我的批评意见。这甚至不是建议。当您连接多个客户端时,您的 Delphi 代码将不起作用。而你甚至给混乱添上了更多东西。

标签: java android sockets delphi


【解决方案1】:

你的代码有很多问题。

你没有注意ReceiveBuf()的返回值。它返回实际读取的字节数,可能比您请求的字节数少,或者它可以在断开连接时返回 0,或者在错误时返回 -1(特别是如果您在非阻塞模式下使用服务器)。你需要处理这些情况。您需要循环读取TempSize。当您在读取像素时收到准确的FSize 字节数时,您需要停止循环。

您没有考虑字节序。 DataOutputStream.writeInt()big endian 字节顺序写入整数字节。 Windows 上的 Delphi 是 little endian。您对ReceiveBuf(TempSize,SizeOf(TempSize)) 的调用正在读取整数字节原样,因此TempSize 将采用大端序。在使用它之前,您需要将值转换为小端。您可以为此使用ntohl()

TempSize := ntohl(TempSize);

您的客户端仅发送原始像素数据,但TBitmap.LoadFrom...() 需要完整的.bmp 文件,包括描述位图及其像素的BITMAPFILEHEADERBITMAPINFOHEADER 标头(请参阅Bitmap Storage)。您需要发送这些标头,或者至少在将像素读入其中之前使用它们填充您的Stream

但是,Android 对bmp 格式的支持不是很好,因此最好使用Bitmap.compress() 将位图数据提取为PNG,然后在Delphi 端使用TPNGImage加载它。

【讨论】:

  • 非常感谢您的回答:-)。您可以使用 Delphi(服务器端)中的代码示例编辑您的答案吗?
  • 我已经对客户端和服务器进行了一些更改(按照您的建议),但仍然无法正常工作。我编辑了我的问题以显示它。
  • @Sormanne 您需要在阅读TempSize 之后 调用ntohl(),而不是之前。而且你没有循环阅读,就像我说的那样。而且您仍然没有正确处理ReceiveBuf() 的返回值,或者一般来说循环正确。
  • 我改变了它,但直到现在都没有成功,然后来到this error message。您可以在答案中提供一个代码示例吗?
  • 你同时想要的东西太多了。我已经说过,您应该检查接收的字节数是否等于发送的字节数。但你什么也没提。此时您应该开始比较发送的array.length 和接收的TempSize。现在价值观是什么?做一些基本的调试!
猜你喜欢
  • 2014-07-17
  • 2011-10-22
  • 1970-01-01
  • 1970-01-01
  • 2019-08-08
  • 1970-01-01
  • 2020-07-10
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多