Implementing Basic Socket Communication in Android

Socket communication enables networked processes to exchange data using a standardized interface. In a network environment, each process is identified by a unique combination of IP address, protocol, and port number, which allows for reliable inter-process communication.

The underlying mechanism of socket programming originates from Unix systems where everything is treated as a file. Sockets provide an abstraction layer over network connections, allowing applications to perform standard I/O operations like open, read, write, and close.

TCP/IP Protocol Overview

The Transmission Control Protocol (TCP) works alongside the Internet Protocol (IP) to ensure reliable data transmission. While IP handles routing packets between hosts, TCP guarantees delivery order and error checking through mechanisms such as acknowledgments and retransmissions.

Creating a TCP Server Using ServerSocket

A server establishes a listening socket on a specific port and waits for incoming cleint connections. When a conncetion request arrives, the server accepts it and creates a new socket for communication with that client.

Below is the implementation of a basic server that supports multiple clients:

import java.io.IOException;
import java.io.OutputStream;
import java.net.InetAddress;
import java.net.ServerSocket;
import java.net.Socket;
import java.util.ArrayList;

public class NetworkServer {
    private static ArrayList<Socket> clientSockets = new ArrayList<>();

    public static void main(String[] args) {
        try {
            InetAddress localAddress = InetAddress.getLocalHost();
            System.out.println("Server IP: " + localAddress.getHostAddress());
            ServerSocket serverSocket = new ServerSocket(30000);

            while (true) {
                Socket clientSocket = serverSocket.accept();
                OutputStream output = clientSocket.getOutputStream();
                output.write("Welcome to the chat server\n".getBytes("UTF-8"));
                clientSockets.add(clientSocket);
                new Thread(new ChatHandler(clientSocket)).start();
                System.out.println("Connected clients: " + clientSockets.size());
            }
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
}

Each connected client is handled by a separate thread that listens for messages and broadcasts them to all other connected clients:

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.OutputStream;
import java.net.Socket;

public class ChatHandler implements Runnable {
    private BufferedReader reader;
    private Socket clientSocket;

    public ChatHandler(Socket socket) {
        try {
            this.clientSocket = socket;
            this.reader = new BufferedReader(new InputStreamReader(socket.getInputStream(), "UTF-8"));
        } catch (IOException e) {
            e.printStackTrace();
        }
    }

    @Override
    public void run() {
        String message;
        try {
            while ((message = reader.readLine()) != null) {
                broadcastMessage(message);
            }
        } catch (IOException e) {
            NetworkServer.clientSockets.remove(clientSocket);
        }
    }

    private void broadcastMessage(String msg) {
        for (Socket socket : NetworkServer.clientSockets) {
            try {
                OutputStream out = socket.getOutputStream();
                out.write((msg + "\n").getBytes("UTF-8"));
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
    }
}

Android Client Implemantation

An Android application can connect to the server using a dedicated client thread. Below is the layout definition for the UI component:

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:orientation="vertical">

    <LinearLayout
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:orientation="horizontal">

        <EditText
            android:id="@+id/messageInput"
            android:layout_width="0dp"
            android:layout_height="wrap_content"
            android:layout_weight="1" />

        <Button
            android:id="@+id/sendButton"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:text="Send" />
    </LinearLayout>

    <ScrollView
        android:layout_width="match_parent"
        android:layout_height="match_parent">

        <TextView
            android:id="@+id/receivedMessages"
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:background="#ffffff"
            android:textSize="14sp" />
    </ScrollView>
</LinearLayout>

The client activity manages sending and receiving messages via background threads:

public class ChatClientActivity extends AppCompatActivity {
    private EditText inputField;
    private TextView displayArea;
    private Handler messageHandler;
    private ClientConnection clientThread;

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

        inputField = findViewById(R.id.messageInput);
        displayArea = findViewById(R.id.receivedMessages);

        messageHandler = new Handler(msg -> {
            if (msg.what == 0x123) {
                displayArea.append("\n" + msg.obj.toString());
            }
            return true;
        });

        clientThread = new ClientConnection(messageHandler);
        new Thread(clientThread).start();

        Button sendButton = findViewById(R.id.sendButton);
        sendButton.setOnClickListener(v -> {
            Message msg = Message.obtain();
            msg.what = 0x345;
            msg.obj = inputField.getText().toString();
            clientThread.messageSender.sendMessage(msg);
            inputField.setText("");
        });
    }
}

The client thread handles both reading from the server and writing to it:

public class ClientConnection implements Runnable {
    private Handler receiveHandler;
    public Handler messageSender;
    private BufferedReader reader;
    private OutputStream writer;

    public ClientConnection(Handler handler) {
        this.receiveHandler = handler;
    }

    @Override
    public void run() {
        try {
            Socket socket = new Socket("192.168.1.110", 30000);
            reader = new BufferedReader(new InputStreamReader(socket.getInputStream(), "UTF-8"));
            writer = socket.getOutputStream();

            new Thread(() -> {
                try {
                    String line;
                    while ((line = reader.readLine()) != null) {
                        Message msg = Message.obtain();
                        msg.what = 0x123;
                        msg.obj = line;
                        receiveHandler.sendMessage(msg);
                    }
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }).start();

            Looper.prepare();
            messageSender = new Handler(msg -> {
                try {
                    if (msg.what == 0x345) {
                        writer.write((msg.obj.toString() + "\r\n").getBytes("UTF-8"));
                    }
                } catch (IOException e) {
                    e.printStackTrace();
                }
                return true;
            });
            Looper.loop();
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
}

This setup demonstrates a simple multi-client chat system where messages sent by one client are relayed to all others through the central server.

Tags: socket networking Android tcp multithreading

Posted on Thu, 07 May 2026 10:01:02 +0000 by prosolutions