ThreadBlocking模式下Delphi服务端与Android客户端Socket连接问题咨询
Hey there, let's tackle this connection issue between your Android client and Delphi server. First off, Android's Socket operates in blocking mode by default—you don't need to explicitly set anything for that. The problem is likely elsewhere in your code or configuration. Let's break down the key issues and fixes:
一、先排查基础连接障碍
Before diving into code, rule out these common environment issues:
- Firewall/Network: Make sure the Delphi server's port (60) is open in its firewall, and both devices are on the same local network (your 192.168.15.13 IP looks like a local LAN address, which is good).
- Android Permissions: Ensure your AndroidManifest.xml includes:
For Android 9+, you also need to allow cleartext traffic (since plain Socket connections are considered cleartext):<uses-permission android:name="android.permission.INTERNET"/><application ... android:usesCleartextTraffic="true"> - Port Consistency: Double-check that Delphi's
ServerSocket1.Portis indeed set to 60, matching your Android client'sSERVERPORT.
二、Android端代码的关键问题
Your Android client has several stream-handling mistakes that could break connection or communication:
1. Repeatedly creating stream wrappers inside the loop
In your CommsThread.run() method, you create BufferedReader, PrintWriter, and later DataOutputStream inside the while loop. This is bad practice—repeatedly wrapping the same Socket stream causes buffer conflicts and unexpected behavior. Create these streams once before the loop:
class CommsThread implements Runnable { @Override public void run() { try { System.out.println("Waiting for server request"); // Create streams ONCE outside the loop BufferedReader reader = new BufferedReader(new InputStreamReader(clientSocket.getInputStream())); PrintWriter out = new PrintWriter(new BufferedWriter(new OutputStreamWriter(clientSocket.getOutputStream())), true); DataOutputStream dos = new DataOutputStream(clientSocket.getOutputStream()); String line; // Remove clientSocket.isConnected() check—readLine() will block until data or disconnect while ((line = reader.readLine()) != null) { System.out.println(line); if(line != null && !line.trim().isEmpty()) { if(line.equalsIgnoreCase("screencapture")){ // Take screenshot with MediaProjection api // Send to server ByteArrayOutputStream bos = new ByteArrayOutputStream(); bitmap.compress(Bitmap.CompressFormat.PNG, 100, bos); byte[] array = bos.toByteArray(); dos.writeInt(array.length); dos.write(array, 0, array.length); dos.flush(); } if(line.equalsIgnoreCase("exit")) { break; } } } System.out.println("Shutting down Socket!!"); // Close all streams and socket properly reader.close(); out.close(); dos.close(); clientSocket.close(); } catch (Exception e1) { System.out.println(e1.toString()); // Add cleanup in catch block to avoid resource leaks try { if(clientSocket != null) clientSocket.close(); } catch(Exception e) {} } } }
2. Avoid using reader.ready() in blocking mode
The ready() method checks if data is immediately available, but in blocking mode, readLine() will naturally wait until data arrives. Using ready() causes your loop to skip iterations if no data is present right now, leading to missed messages and unnecessary CPU usage. Just use while ((line = reader.readLine()) != null) as shown above—it will block until the server sends data or the connection is closed.
3. Don't mix character streams and byte streams
You're using PrintWriter (character stream) and DataOutputStream (byte stream) on the same Socket output stream. These streams have separate buffers, which can cause data to be sent out of order or not flushed properly. If you need to send both text commands and binary data, stick to byte streams for everything (use OutputStreamWriter for text if needed, but manage it carefully).
三、Delphi端代码的潜在问题
Your Delphi server has a small but important bug in the connection handling:
1. Incorrect assignment of ListView item data
In ServerSocket1ClientConnect, you set Item.Data := Socket.Data;—but Socket.Data is nil by default. Later, in PngReceived, you check Item.Data = ClientSocket, which will never be true. Fix this by assigning the Socket itself to the item data:
procedure TForm1.ServerSocket1ClientConnect(Sender: TObject; Socket: TCustomWinSocket); var Item: TListItem; begin Item := ListView1.Items.Add; Item.Caption := IntToStr(Socket.Handle); Item.SubItems.Add(Socket.RemoteAddress); Item.SubItems.Add(Socket.RemoteHost); stat1.Panels.Items[1].Text := 'Conectado'; // Assign the Socket itself, not Socket.Data Item.Data := Socket; end;
2. Verify ThreadBlocking mode setup
Double-check that your ServerSocket1 component has its SocketType set to stStream and ThreadedEvent set to True (since you're using a custom thread via OnGetThread). ThreadBlocking mode requires these settings to work correctly.
总结
The connection failure has nothing to do with blocking mode—Android's Socket is already blocking by default. Fix the stream handling in your Android client, add the necessary permissions, correct the Delphi ListView data assignment, and you should be able to establish a connection and exchange data properly.
内容的提问来源于stack exchange,提问作者user9120317

