Computer >> कंप्यूटर ट्यूटोरियल >  >> प्रोग्रामिंग >> Android

Android में Client-Server प्रोग्रामिंग: Socket संचार ट्यूटोरियल

यह गाइड Android में Client-Server आर्किटेक्चर को TCP Sockets का उपयोग करके लागू करने का एक व्यापक अवलोकन प्रदान करता है। इसमें दोनों पक्षों के लिए पूर्ण, उत्पादन-तैयार कोड पैटर्न, उचित संसाधन प्रबंधन और आधुनिक Android सर्वोत्तम अभ्यास शामिल हैं।

आर्किटेक्चर सारांश

┌─────────────────┐                    ┌─────────────────┐
│    SERVER       │                    │    CLIENT       │
│  (Listener)     │◄── TCP Port 8080 ──►│  (Initiator)    │
│                 │                    │                 │
│ ServerSocket    │                    │ Socket          │
│ accept()        │                    │ connect()       │
│ Input/Output    │                    │ Input/Output    │
└─────────────────┘                    └─────────────────┘

साझा कॉन्फ़िगरेशन

// दोनों ऐप्स के लिए स्थिरांक
public final class NetworkConfig {
    public static final int DEFAULT_PORT = 8080;
    public static final int CONNECT_TIMEOUT_MS = 10000;
    public static final int READ_TIMEOUT_MS = 30000;
    public static final String CHARSET = "UTF-8";
}

Server पक्ष कार्यान्वयन

ServerManifest.xml

<manifest ... package="com.example.serversocket">
    <uses-permission android:name="android.permission.INTERNET" />
    <uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
    <uses-permission android:name="android.permission.ACCESS_WIFI_STATE" />
    <application ...>
        <activity android:name=".ServerActivity" android:exported="true">
            <intent-filter><action android:name="android.intent.action.MAIN"/><category android:name="android.intent.category.LAUNCHER"/></intent-filter>
        </activity>
    </application>
</manifest>

ServerActivity.java (आधुनिक, साफ संस्करण)

package com.example.serversocket;

import android.net.wifi.WifiInfo;
import android.net.wifi.WifiManager;
import android.os.Bundle;
import android.widget.Button;
import android.widget.EditText;
import android.widget.TextView;
import android.widget.Toast;
import androidx.annotation.NonNull;
import androidx.appcompat.app.AppCompatActivity;
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.PrintWriter;
import java.net.InetAddress;
import java.net.ServerSocket;
import java.net.Socket;
import java.net.UnknownHostException;
import java.nio.ByteBuffer;
import java.nio.ByteOrder;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;

public class ServerActivity extends AppCompatActivity {

    private static final int PORT = NetworkConfig.DEFAULT_PORT;

    private ServerSocket serverSocket;
    private Socket clientSocket;
    private PrintWriter out;
    private BufferedReader in;
    private ExecutorService executor = Executors.newSingleThreadExecutor();

    private TextView tvIp, tvStatus, tvLog;
    private EditText etMessage;
    private Button btnSend;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_server);

        tvIp = findViewById(R.id.tvIP);
        tvStatus = findViewById(R.id.tvConnectionStatus);
        tvLog = findViewById(R.id.tvMessages);
        etMessage = findViewById(R.id.etMessage);
        btnSend = findViewById(R.id.btnSend);

        displayLocalIp();
        startListening();

        btnSend.setOnClickListener(v -> sendMessage());
    }

    private void displayLocalIp() {
        executor.execute(() -> {
            try {
                String ip = getLocalIpAddress();
                runOnUiThread(() -> tvIp.setText("Server IP: " + ip));
            } catch (UnknownHostException e) {
                runOnUiThread(() -> tvIp.setText("IP अनुपलब्ध"));
            }
        });
    }

    private String getLocalIpAddress() throws UnknownHostException {
        WifiManager wm = (WifiManager) getApplicationContext().getSystemService(WIFI_SERVICE);
        WifiInfo wi = wm.getConnectionInfo();
        int ipInt = wi.getIpAddress();
        if (ipInt == 0) throw new UnknownHostException("Wi-Fi कनेक्टेड नहीं");
        byte[] bytes = ByteBuffer.allocate(4).order(ByteOrder.LITTLE_ENDIAN).putInt(ipInt).array();
        return InetAddress.getByAddress(bytes).getHostAddress();
    }

    private void startListening() {
        executor.execute(() -> {
            try {
                serverSocket = new ServerSocket(PORT);
                serverSocket.setSoTimeout(0); // अनंत प्रतीक्षा
                runOnUiThread(() -> appendLog("Server प्रारंभ हुआ पोर्ट " + PORT + " पर"));

                while (!Thread.currentThread().isInterrupted()) {
                    try {
                        clientSocket = serverSocket.accept();
                        clientSocket.setSoTimeout(NetworkConfig.READ_TIMEOUT_MS);
                        out = new PrintWriter(clientSocket.getOutputStream(), true);
                        in = new BufferedReader(new InputStreamReader(clientSocket.getInputStream(),
                                java.nio.charset.StandardCharsets.UTF_8));

                        runOnUiThread(() -> {
                            tvStatus.setText("कनेक्टेड: " + clientSocket.getInetAddress().getHostAddress());
                            appendLog("क्लाइंट कनेक्टेड: " + clientSocket.getInetAddress().getHostAddress());
                        });

                        handleClient();

                    } catch (IOException e) {
                        if (!Thread.currentThread().isInterrupted()) {
                            runOnUiThread(() -> appendLog("कनेक्शन त्रुटि: " + e.getMessage()));
                        }
                    } finally {
                        closeClientSocket();
                    }
                }
            } catch (IOException e) {
                runOnUiThread(() -> appendLog("Server त्रुटि: " + e.getMessage()));
            }
        });
    }

    private void handleClient() {
        executor.execute(() -> {
            try {
                String line;
                while ((line = in.readLine()) != null) {
                    String finalLine = line;
                    runOnUiThread(() -> appendLog("Client: " + finalLine));
                }
            } catch (IOException e) {
                runOnUiThread(() -> appendLog("क्लाइंट डिस्कनेक्ट: " + e.getMessage()));
            } finally {
                closeClientSocket();
                runOnUiThread(() -> tvStatus.setText("कनेक्शन की प्रतीक्षा..."));
            }
        });
    }

    private void sendMessage() {
        String msg = etMessage.getText().toString().trim();
        if (msg.isEmpty() || out == null) return;

        out.println(msg);
        appendLog("Server: " + msg);
        etMessage.setText("");
    }

    private void appendLog(String msg) {
        tvLog.append(msg + "\n");
        // ऑटो-स्क्रॉल के लिए ScrollView का उपयोग करें
    }

    private void closeClientSocket() {
        try {
            if (in != null) in.close();
            if (out != null) out.close();
            if (clientSocket != null) clientSocket.close();
        } catch (IOException ignored) {}
        clientSocket = null;
        in = null;
        out = null;
    }

    @Override
    protected void onDestroy() {
        super.onDestroy();
        executor.shutdownNow();
        try {
            if (serverSocket != null) serverSocket.close();
        } catch (IOException ignored) {}
        closeClientSocket();
    }
}

Client पक्ष कार्यान्वयन

ClientManifest.xml

<manifest ... package="com.example.clientsocket">
    <uses-permission android:name="android.permission.INTERNET" />
    <uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
    <application ...>
        <activity android:name=".ClientActivity" android:exported="true">
            <intent-filter><action android:name="android.intent.action.MAIN"/><category android:name="android.intent.category.LAUNCHER"/></intent-filter>
        </activity>
    </application>
</manifest>

ClientActivity.java (आधुनिक, साफ संस्करण)

package com.example.clientsocket;

import android.os.Bundle;
import android.widget.Button;
import android.widget.EditText;
import android.widget.TextView;
import androidx.appcompat.app.AppCompatActivity;
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.PrintWriter;
import java.net.Socket;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;

public class ClientActivity extends AppCompatActivity {

    private Socket socket;
    private PrintWriter out;
    private BufferedReader in;
    private ExecutorService executor = Executors.newSingleThreadExecutor();

    private EditText etIp, etPort, etMessage;
    private TextView tvLog;
    private Button btnConnect, btnSend;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_client);

        etIp = findViewById(R.id.etIP);
        etPort = findViewById(R.id.etPort);
        tvLog = findViewById(R.id.tvMessages);
        etMessage = findViewById(R.id.etMessage);
        btnConnect = findViewById(R.id.btnConnect);
        btnSend = findViewById(R.id.btnSend);

        btnConnect.setOnClickListener(v -> connect());
        btnSend.setOnClickListener(v -> send());
    }

    private void connect() {
        String ip = etIp.getText().toString().trim();
        String portStr = etPort.getText().toString().trim();

        if (ip.isEmpty()) { etIp.setError("IP आवश्यक"); return; }
        int port = portStr.isEmpty() ? NetworkConfig.DEFAULT_PORT : Integer.parseInt(portStr);

        appendLog("कनेक्ट हो रहा है " + ip + ":" + port + "...");

        executor.execute(() -> {
            try {
                socket = new Socket();
                socket.connect(new java.net.InetSocketAddress(ip, port), NetworkConfig.CONNECT_TIMEOUT_MS);
                socket.setSoTimeout(NetworkConfig.READ_TIMEOUT_MS);

                out = new PrintWriter(socket.getOutputStream(), true);
                in = new BufferedReader(new InputStreamReader(socket.getInputStream(),
                        java.nio.charset.StandardCharsets.UTF_8));

                runOnUiThread(() -> {
                    appendLog("Server से कनेक्टेड!");
                    btnConnect.setEnabled(false);
                    btnSend.setEnabled(true);
                });

                listenForMessages();

            } catch (IOException e) {
                runOnUiThread(() -> appendLog("कनेक्शन विफल: " + e.getMessage()));
            }
        });
    }

    private void listenForMessages() {
        executor.execute(() -> {
            try {
                String line;
                while ((line = in.readLine()) != null) {
                    String finalLine = line;
                    runOnUiThread(() -> appendLog("Server: " + finalLine));
                }
            } catch (IOException e) {
                runOnUiThread(() -> appendLog("डिस्कनेक्ट: " + e.getMessage()));
            } finally {
                runOnUiThread(() -> {
                    btnConnect.setEnabled(true);
                    btnSend.setEnabled(false);
                });
                closeResources();
            }
        });
    }

    private void send() {
        String msg = etMessage.getText().toString().trim();
        if (msg.isEmpty() || out == null) return;

        out.println(msg);
        appendLog("Client: " + msg);
        etMessage.setText("");
    }

    private void appendLog(String msg) {
        tvLog.append(msg + "\n");
    }

    private void closeResources() {
        try {
            if (in != null) in.close();
            if (out != null) out.close();
            if (socket != null) socket.close();
        } catch (IOException ignored) {}
        socket = null; in = null; out = null;
    }

    @Override
    protected void onDestroy() {
        super.onDestroy();
        executor.shutdownNow();
        closeResources();
    }
}

लेआउट XML (दोनों के लिए समान संरचना)

पिछले लेख (1005061523) के लेआउट देखें - RelativeLayout जिसमें IP/Port इनपुट (Client), स्टेटस TextView, मैसेज लॉग TextView, इनपुट EditText, Send Button शामिल हैं।


मजबूती के लिए मुख्य सुधार

क्षेत्रमूलसुधारा गया
थ्रेडिंगकच्चे ThreadExecutorService (SingleThreadExecutor)
संसाधन सफाईन्यूनतमonDestroy() में व्यापक
टाइमआउटकोई नहींकनेक्ट/रीड टाइमआउट सेट
एन्कोडिंगप्लेटफ़ॉर्म डिफ़ॉल्टस्पष्ट UTF-8
ऑटो-फ्लशमैन्युअलPrintWriter(..., true)
पुनः कनेक्शनकेवल Serverदोनों पक्ष पुनः कनेक्ट कर सकते हैं

उत्पादन के लिए उन्नत विषय

  1. प्रोटोकॉल डिज़ाइन: लंबाई-पूर्वनिर्धारित फ्रेम, JSON, Protobuf, MessagePack
  2. सुरक्षा: TLS/SSL (SSLSocketFactory), प्रमाणपत्र पिनिंग
  3. खोज: मैन्युअल IP प्रविष्टि के बजाय mDNS/Bonjour/NSD
  4. जीवनचक्र: ViewModel + Kotlin Coroutines/Flow
  5. पृष्ठभूमि: Foreground Service + WorkManager भरोसेमंद कनेक्टिविटी के लिए
  6. परीक्षण: MockWebServer, स्थानीय सर्वर के लिए एमुलेटर पोर्ट फ़ॉरवर्डिंग

निष्कर्ष

यह Client-Server Socket कार्यान्वयन Android नेटवर्क प्रोग्रामिंग के लिए एक ठोस आधार प्रदान करता है। मुख्य पैटर्न: पृष्ठभूमि निष्पादन के लिए ExecutorService, संसाधन प्रबंधन के लिए try-with-resources, स्पष्ट एन्कोडिंग, टाइमआउट, और उचित जीवनचक्र सफाई। वास्तविक दुनिया के ऐप्स के लिए, रखरखाव और मजबूती के लिए OkHttp, Ktor, या gRPC जैसे उच्च-स्तरीय फ्रेमवर्क पर विचार करें।

  1. एंड्रॉइड में CheckedTextView का उपयोग कैसे करें? एंड्रॉइड में CheckedTextView का उपयोग कैसे करें?

    एंड्रॉइड में CheckedTextView का उपयोग CheckedTextView TextView का विस्तार है जो Checkable इंटरफ़ेस को लागू करता है, जिससे यह चेक करने योग्य स्थिति बनाए रख सकता है और चेक मार्क प्रदर्शित कर सकता है। चरण 1: नया प्रोजेक्ट बनाएं Android Studio में File → New Project चुनें। चरण 2: लेआउट फ़ाइल (activity

  1. Android में ToggleButton का उदाहरण Android में ToggleButton का उदाहरण

    Android ToggleButton - ऑन/ऑफ स्टेट्स के साथ बटन ToggleButton एक दो-स्थिति वाला बटन है (चेक्ड/अनचेक्ड) जो CompoundButton से विरासत में मिला है। ऑन/ऑफ सेटिंग्स के लिए आदर्श। चरण 1: प्रोजेक्ट बनाएं Android Studio: File → New Project। चरण 2: लेआउट (activity_main.xml) <?xml version=1.0 encoding=utf-

  1. प्रोग्रामिंग और कोडिंग में महारत हासिल करने के लिए टॉप Android ऐप्स प्रोग्रामिंग और कोडिंग में महारत हासिल करने के लिए टॉप Android ऐप्स

    क्या आप अपना सॉफ्टवेयर बनाना चाहते हैं या वेबसाइट या एप्लिकेशन विकास में करियर की योजना बना रहे हैं? तब कोडिंग पर अच्छी पकड़ होना अनिवार्य है। यदि आप तकनीकी रूप से मजबूत व्यक्ति हैं और इस क्षेत्र में रुचि रखते हैं, तो आप सीधे इंटरनेट से सॉफ्टवेयर डाउनलोड कर सकते हैं और कोडिंग सीखना शुरू कर सकते हैं।