यह ट्यूटोरियल Android में TCP Sockets का उपयोग करके दो डिवाइस (या एक ही डिवाइस पर दो ऐप्स) के बीच एक साधारण चैट एप्लिकेशन बनाने का प्रदर्शन करता है। इसमें एक Server ऐप और एक Client ऐप शामिल है जो स्थानीय नेटवर्क पर संचार करते हैं।
आर्किटेक्चर अवलोकन
- Server: निर्दिष्ट पोर्ट (8080) पर सुनता है, कनेक्शन स्वीकार करता है, संदेश पढ़ता/लिखता है
- Client: Server IP/पोर्ट से कनेक्ट होता है, संदेश भेजता/प्राप्त करता है
- थ्रेडिंग: नेटवर्क संचालन UI थ्रेड को ब्लॉक न करने के लिए पृष्ठभूमि थ्रेड्स पर चलते हैं
runOnUiThread()का उपयोग करके UI अपडेट किए जाते हैं
आवश्यक अनुमतियाँ (दोनों ऐप्स के लिए)
<uses-permission android:name="android.permission.INTERNET" /> <uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" /> <!-- Server के लिए स्थानीय IP प्राप्त करने हेतु --> <uses-permission android:name="android.permission.ACCESS_WIFI_STATE" />
भाग A: Server ऐप
1. Server Manifest
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="https://schemas.android.com/apk/res/android"
package="com.example.socketserver">
<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
android:allowBackup="true"
android:icon="@mipmap/ic_launcher"
android:label="Socket Server"
android:roundIcon="@mipmap/ic_launcher_round"
android:supportsRtl="true"
android:theme="@style/AppTheme">
<activity
android:name=".MainActivity"
android:exported="true">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
</application>
</manifest>
2. Server Layout (res/layout/activity_main.xml)
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="https://schemas.android.com/apk/res/android"
xmlns:tools="https://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:padding="16dp"
tools:context=".MainActivity">
<TextView
android:id="@+id/tvIP"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="IP: प्रतीक्षा 중..."
android:textAppearance="@style/TextAppearance.AppCompat.Medium" />
<TextView
android:id="@+id/tvPort"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_below="@id/tvIP"
android:text="Port: 8080"
android:textAppearance="@style/TextAppearance.AppCompat.Medium" />
<TextView
android:id="@+id/tvConnectionStatus"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_below="@id/tvPort"
android:layout_marginTop="8dp"
android:text="कनेक्शन की प्रतीक्षा..."
android:textAppearance="@style/TextAppearance.AppCompat.Medium"
android:textStyle="bold" />
<TextView
android:id="@+id/tvMessages"
android:layout_width="match_parent"
android:layout_height="0dp"
android:layout_above="@id/etMessage"
android:layout_below="@id/tvConnectionStatus"
android:layout_marginTop="8dp"
android:background="#F5F5F5"
android:padding="12dp"
android:inputType="textMultiLine"
android:textAppearance="@style/TextAppearance.AppCompat.Medium" />
<EditText
android:id="@+id/etMessage"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_above="@id/btnSend"
android:layout_marginBottom="8dp"
android:hint="संदेश दर्ज करें"
android:inputType="text" />
<Button
android:id="@+id/btnSend"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_alignParentBottom="true"
android:text="भेजें" />
</RelativeLayout>
3. Server MainActivity.java
package com.example.socketserver;
import android.annotation.SuppressLint;
import android.net.wifi.WifiInfo;
import android.net.wifi.WifiManager;
import android.os.Bundle;
import android.view.View;
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.InetAddress;
import java.net.ServerSocket;
import java.net.Socket;
import java.net.UnknownHostException;
import java.nio.ByteBuffer;
import java.nio.ByteOrder;
@SuppressLint("SetTextI18n")
public class MainActivity extends AppCompatActivity {
private static final int SERVER_PORT = 8080;
private ServerSocket serverSocket;
private Thread serverThread;
private PrintWriter output;
private BufferedReader input;
private TextView tvIP, tvPort, tvConnectionStatus, tvMessages;
private EditText etMessage;
private Button btnSend;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
tvIP = findViewById(R.id.tvIP);
tvPort = findViewById(R.id.tvPort);
tvConnectionStatus = findViewById(R.id.tvConnectionStatus);
tvMessages = findViewById(R.id.tvMessages);
etMessage = findViewById(R.id.etMessage);
btnSend = findViewById(R.id.btnSend);
// स्थानीय IP प्राप्त करें
try {
String localIp = getLocalIpAddress();
tvIP.setText("IP: " + localIp);
tvPort.setText("Port: " + SERVER_PORT);
} catch (UnknownHostException e) {
tvIP.setText("IP: अनुपलब्ध");
e.printStackTrace();
}
// Server थ्रेड प्रारंभ करें
startServerThread();
btnSend.setOnClickListener(v -> {
String msg = etMessage.getText().toString().trim();
if (!msg.isEmpty() && output != null) {
new Thread(new SendThread(msg)).start();
}
});
}
private String getLocalIpAddress() throws UnknownHostException {
WifiManager wifiManager = (WifiManager) getApplicationContext().getSystemService(WIFI_SERVICE);
if (wifiManager == null) throw new UnknownHostException("WifiManager null");
WifiInfo wifiInfo = wifiManager.getConnectionInfo();
int ipInt = wifiInfo.getIpAddress();
if (ipInt == 0) throw new UnknownHostException("IP नहीं मिला");
byte[] ipBytes = ByteBuffer.allocate(4).order(ByteOrder.LITTLE_ENDIAN).putInt(ipInt).array();
return InetAddress.getByAddress(ipBytes).getHostAddress();
}
private void startServerThread() {
serverThread = new Thread(() -> {
try {
serverSocket = new ServerSocket(SERVER_PORT);
runOnUiThread(() -> tvConnectionStatus.setText("कनेक्शन की प्रतीक्षा... (Port " + SERVER_PORT + ")"));
Socket socket = serverSocket.accept(); // ब्लॉक करता है जब तक क्लाइंट कनेक्ट न हो
output = new PrintWriter(socket.getOutputStream(), true);
input = new BufferedReader(new InputStreamReader(socket.getInputStream()));
runOnUiThread(() -> tvConnectionStatus.setText("कनेक्टेड: " + socket.getInetAddress().getHostAddress()));
// आने वाले संदेशों को सुनें
new Thread(new ReceiveThread()).start();
} catch (IOException e) {
e.printStackTrace();
runOnUiThread(() -> tvConnectionStatus.setText("Server त्रुटि: " + e.getMessage()));
}
});
serverThread.start();
}
private class ReceiveThread implements Runnable {
@Override
public void run() {
try {
String msg;
while ((msg = input.readLine()) != null) {
String finalMsg = msg;
runOnUiThread(() -> tvMessages.append("Client: " + finalMsg + "\n"));
}
} catch (IOException e) {
e.printStackTrace();
} finally {
// क्लाइंट डिस्कनेक्ट - नए कनेक्शन के लिए पुनरारंभ
runOnUiThread(() -> tvConnectionStatus.setText("क्लाइंट डिस्कनेक्ट। प्रतीक्षा..."));
startServerThread();
}
}
}
private class SendThread implements Runnable {
private final String message;
SendThread(String message) { this.message = message; }
@Override
public void run() {
output.println(message);
runOnUiThread(() -> {
tvMessages.append("Server: " + message + "\n");
etMessage.setText("");
});
}
}
@Override
protected void onDestroy() {
super.onDestroy();
try {
if (serverSocket != null) serverSocket.close();
if (output != null) output.close();
if (input != null) input.close();
} catch (IOException e) { e.printStackTrace(); }
}
}
भाग B: Client ऐप
1. Client Manifest
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="https://schemas.android.com/apk/res/android"
package="com.example.socketclient">
<uses-permission android:name="android.permission.INTERNET" />
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
<application
android:allowBackup="true"
android:icon="@mipmap/ic_launcher"
android:label="Socket Client"
android:roundIcon="@mipmap/ic_launcher_round"
android:supportsRtl="true"
android:theme="@style/AppTheme">
<activity
android:name=".MainActivity"
android:exported="true">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
</application>
</manifest>
2. Client Layout (res/layout/activity_main.xml)
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="https://schemas.android.com/apk/res/android"
xmlns:tools="https://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:padding="16dp"
tools:context=".MainActivity">
<EditText
android:id="@+id/etIP"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:hint="Server IP पता"
android:inputType="text" />
<EditText
android:id="@+id/etPort"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_below="@id/etIP"
android:layout_marginTop="8dp"
android:hint="Port (डिफ़ॉल्ट 8080)"
android:inputType="number" />
<Button
android:id="@+id/btnConnect"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_below="@id/etPort"
android:layout_marginTop="16dp"
android:text="Server से कनेक्ट करें" />
<TextView
android:id="@+id/tvMessages"
android:layout_width="match_parent"
android:layout_height="0dp"
android:layout_above="@id/etMessage"
android:layout_below="@id/btnConnect"
android:layout_marginTop="8dp"
android:background="#F5F5F5"
android:padding="12dp"
android:inputType="textMultiLine"
android:textAppearance="@style/TextAppearance.AppCompat.Medium" />
<EditText
android:id="@+id/etMessage"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_above="@id/btnSend"
android:layout_marginBottom="8dp"
android:hint="संदेश दर्ज करें"
android:inputType="text" />
<Button
android:id="@+id/btnSend"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_alignParentBottom="true"
android:text="भेजें" />
</RelativeLayout>
3. Client MainActivity.java
package com.example.socketclient;
import android.os.Bundle;
import android.view.View;
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;
public class MainActivity extends AppCompatActivity {
private Thread clientThread;
private PrintWriter output;
private BufferedReader input;
private Socket socket;
private EditText etIP, etPort, etMessage;
private TextView tvMessages;
private Button btnConnect, btnSend;
private String serverIp = "";
private int serverPort = 8080;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
etIP = findViewById(R.id.etIP);
etPort = findViewById(R.id.etPort);
tvMessages = findViewById(R.id.tvMessages);
etMessage = findViewById(R.id.etMessage);
btnConnect = findViewById(R.id.btnConnect);
btnSend = findViewById(R.id.btnSend);
btnConnect.setOnClickListener(v -> connectToServer());
btnSend.setOnClickListener(v -> sendMessage());
}
private void connectToServer() {
serverIp = etIP.getText().toString().trim();
String portStr = etPort.getText().toString().trim();
if (serverIp.isEmpty()) {
etIP.setError("IP दर्ज करें");
return;
}
if (portStr.isEmpty()) {
serverPort = 8080;
} else {
serverPort = Integer.parseInt(portStr);
}
tvMessages.setText("कनेक्ट हो रहा है " + serverIp + ":" + serverPort + "...\n");
clientThread = new Thread(() -> {
try {
socket = new Socket(serverIp, serverPort);
output = new PrintWriter(socket.getOutputStream(), true);
input = new BufferedReader(new InputStreamReader(socket.getInputStream()));
runOnUiThread(() -> tvMessages.append("Server से कनेक्टेड!\n"));
// संदेश प्राप्त करने के लिए थ्रेड प्रारंभ करें
new Thread(new ReceiveThread()).start();
} catch (IOException e) {
e.printStackTrace();
runOnUiThread(() -> tvMessages.append("कनेक्शन विफल: " + e.getMessage() + "\n"));
}
});
clientThread.start();
}
private void sendMessage() {
String msg = etMessage.getText().toString().trim();
if (!msg.isEmpty() && output != null) {
new Thread(() -> {
output.println(msg);
runOnUiThread(() -> {
tvMessages.append("Client: " + msg + "\n");
etMessage.setText("");
});
}).start();
}
}
private class ReceiveThread implements Runnable {
@Override
public void run() {
try {
String msg;
while ((msg = input.readLine()) != null) {
String finalMsg = msg;
runOnUiThread(() -> tvMessages.append("Server: " + finalMsg + "\n"));
}
} catch (IOException e) {
e.printStackTrace();
runOnUiThread(() -> tvMessages.append("कनेक्शन खो गया\n"));
}
}
}
@Override
protected void onDestroy() {
super.onDestroy();
try {
if (socket != null) socket.close();
if (output != null) output.close();
if (input != null) input.close();
} catch (IOException e) { e.printStackTrace(); }
}
}
चलाने के निर्देश
- दोनों ऐप्स को दो Android डिवाइस पर इंस्टॉल करें (या एक डिवाइस + एमुलेटर)।
- सुनिश्चित करें कि दोनों एक ही Wi-Fi नेटवर्क पर हैं।
- Server ऐप लॉन्च करें - यह अपना IP पता प्रदर्शित करेगा (उदाहरण: 192.168.1.15)।
- Client ऐप लॉन्च करें - Server का IP और पोर्ट 8080 दर्ज करें, Connect दबाएं।
- "Connected!" दिखाई देने पर, किसी भी तरफ से संदेश टाइप करें और Send दबाएं।
महत्वपूर्ण तकनीकी नोट्स
| विषय | विवरण |
|---|---|
| थ्रेडिंग | नेटवर्क I/O मुख्य थ्रेड को ब्लॉक करता है → हमेशा पृष्ठभूमि थ्रेड्स का उपयोग करें |
| UI अपडेट | runOnUiThread() या Handler का उपयोग करना आवश्यक |
| लाइन-आधारित प्रोटोकॉल | PrintWriter.println() + BufferedReader.readLine() सरल टेक्स्ट के लिए |
| बाइनरी डेटा | DataOutputStream/DataInputStream या कस्टम प्रोटोकॉल का उपयोग करें |
| कनेक्शन जीवनचक्र | डिस्कनेक्ट, पुनः कनेक्शन, टाइमआउट को उचित तरीके से संभालें |
| फायरवॉल | सुनिश्चित करें कि नेटवर्क पोर्ट 8080 की अनुमति देता है |
उत्पादन विचार
- OkHttp / Netty / KryoNet जैसे लाइब्रेरी का उपयोग करें मजबूत नेटवर्किंग के लिए
- TLS/SSL लागू करें सुरक्षित संचार के लिए (
SSLSocket) - कनेक्शन पूलिंग, पुनः प्रयास तर्क, हार्टबीट जोड़ें
- सीरियलाइज़ेशन: JSON (Gson/Moshi), Protocol Buffers, या MessagePack का उपयोग करें
- जीवनचक्र:
ViewModel+Coroutine/Flowके साथ नेटवर्क स्थिति प्रबंधित करें
निष्कर्ष
यह उदाहरण Android में कच्चे TCP Socket संचार का प्रदर्शन करता है। जबकि शैक्षिक उद्देश्यों के लिए कार्यात्मक, उत्पादन ऐप्स को उच्च-स्तरीय नेटवर्किंग लाइब्रेरी, उचित त्रुटि प्रबंधन, सुरक्षा और जीवनचक्र प्रबंधन का उपयोग करना चाहिए।