Search code examples
javasocketsraspberry-piclientserversocket

Java + Raspberry Pi + ServerSocket


Hello StackOverflow Community,

I have a specific question launching a java.net.ServerSocket on a Raspberry Pi Zero and connect to it with a java.net.Socket. The RPi is configured as a Wireless Access Point, so I can connect to it via WLAN with more than one Laptop/Tablets. The purpose is to launch a server-client game with the RPi as the server (without the need of a separate network and a server running on a device) and some devices as the clients (that can connect to the RPi).

I tried the following four situations, all more than once to prove that they always show the same result:

  1. I connected to the RPi via WLAN with a tablet. Then i launched the ServerSocket on that tablet. After that I launched a Socket on that tablet and connected it to the ServerSocket. The connection worked and data was transmitted in both directions.

  2. I connected to the RPi via WLAN with a tablet. Then i launched the ServerSocket on that tablet. After that I launched a Socket on the RPi and connected it to the ServerSocket running on my tablet. The connection worked and data was transmitted in both directions.

  3. I connected to the RPi via WLAN with a tablet. Then i launched the ServerSocket on the RPi. After that I launched a Socket on my tablet and connected it to the ServerSocket running on my RPi. The first weird thing was that the IP of the ServerSocket is 0.0.0.0, the second problem that the client failed to connect to the RPi and therefore was not able to transmit data.

  4. I connected to the RPi via WLAN with a tablet. Then i launched the ServerSocket on the RPi and bind it to a specified IP address. After that I launched a Socket on my tablet and connect it to the ServerSocket running on my RPi. The ServerSocket failed to bind to the given IP address, therefore the Socket failed to connect to the Server and therefore no data was transmitted.

Why is no IP bound (except 0.0.0.0) to the ServerSocket? Why can't I connect to the IP-Address 0.0.0.0? How can I get the ServerSocket running on the RPi with Java?

Here are the java source codes I used for all three situations:

Server:

import java.net.ServerSocket;
import java.net.InetAddress;
import java.net.Socket;
import java.net.InetSocketAddress;

import java.io.BufferedReader;
import java.io.BufferedWriter;
import java.io.InputStreamReader;
import java.io.OutputStreamWriter;

public class Server {
    private     ServerSocket    ss;

    public static void main(String[] args) {
        new Server();       // call the constructor
    }

    public Server() {
        try {
            ss = new ServerSocket(4444);    // create the ServerSocket
            new Thread(new Runnable() {     // create new Thread for listening to new clients
                public void run() {
                    startAccept();          // run the accept-clients method
                }
            }).start();     // don't forget to start the thread
            System.out.println(InetAddress.getLocalHost().getHostAddress());    // print the IP-Address
            System.out.println("4444");     // print the Port
        } catch (Exception e) {
            e.printStackTrace();        // show exceptions
        }
    }

    public void startAccept() {
        while (true) {      // listen to new clients
            try {
                Socket so = ss.accept();    // accept the clients and create reader/writer
                BufferedReader bure = new BufferedReader(new InputStreamReader(so.getInputStream()));
                BufferedWriter buwr = new BufferedWriter(new OutputStreamWriter(so.getOutputStream()));
                new Thread(new Runnable() {     // start new thread for reading from the client
                    public void run() {
                        readSocket(bure, buwr); // run the read/write method of the client
                    }
                }).start();     // don't forget to start the thread
            } catch (Exception e) {
                e.printStackTrace();        // show exceptions
            }
        }
    }

    public void readSocket(BufferedReader bure, BufferedWriter buwr) {
        while (true) {      // listen to all messages sent by the client
            try {
                String l1 = bure.readLine();            // read first line
                System.out.println("Rec1: <"+l1+">");   // show it
                String l2 = bure.readLine();            // read second line
                System.out.println("Rec2: <"+l2+">");   // show it
                buwr.write(l1+" + "+l2+" = "+(Integer.parseInt(l1)+Integer.parseInt(l2))+"\n");
                buwr.flush();       // convert both lines to integers and send the sum of them
            } catch (Exception e) {
                e.printStackTrace();        // show exceptions
            }
        }
    }
}

Client:

import java.net.InetAddress;
import java.net.InetSocketAddress;
import java.net.Socket;

import java.io.BufferedReader;
import java.io.BufferedWriter;
import java.io.InputStreamReader;
import java.io.OutputStreamWriter;

public class Client {
    public static void main(String[] args) {        // start the program
        try {
            Socket so = new Socket();       // create an unbound socket
            so.connect(new InetSocketAddress("0.0.0.0", 4444), 10000);
                // bind socket to the IP-address printed by the Server and create reader/writer
            BufferedReader bure = new BufferedReader(new InputStreamReader(so.getInputStream()));
            BufferedWriter buwr = new BufferedWriter(new OutputStreamWriter(so.getOutputStream()));
            buwr.write("7\n4\n");   // send 7 and 4, both followed by a new line
            buwr.flush();
            System.out.println("Sent: <7\n4\n>");   // show the user what has been sent
            System.out.println("Message from Server: "+bure.readLine());    // sum sent by the server
            so.close();     // close socket
        } catch (Exception e) {
            e.printStackTrace();    // show exception
        }
    }
}

I appreciate in advance for any help on this topic.


Solution

  • Finally i found a solution on my own.

    The core problem was setting up the RPi as a WAP with this tutorial (without installing a brigde with bridge-utils). It is not possible to access the RPI without a defined static IP address, therefore it is not possible to bind a ServerSocket to any IP address.

    Add a static IP address to the RPi WAP works that way:

    Edit the file /etc/network/interfaces with

    sudo nano /etc/network/interfaces
    

    and write the following lines to the end of the file.

    auto wlan0
    iface wlan0 inet static
        address 192.168.5.1    #Use own IP address here
        netmask 255.255.255.0
    

    Notes: There needs to be an empty line at the end of this file. It is not required that the static IP address is within the range defined in /etc/dnsmasq.conf, but it only works if the subnet mask fits (in my case it is 192.168.5.xxx).

    The next problem was that I did not know to which IP the ServerSocket is bound to. I got weird outputs (see the comments) by calling

    System.out.println(InetAddress.getLocalHost().getHostAddress());
    System.out.println(ss.getInetAddress().getHostAddress());
    

    and the query of ss.isBound() always returned true. The solution to this problem is to bind the ServerSocket to a specific IP address, which is the same as defined above in the interfaces file on the RPi. Instead of calling

    ss = new ServerSocket(4444);
    

    I used

    ss = new ServerSocket();
    ss.bind(new InetSocketAddress("192.168.5.1", 4444));
    

    so the ServerSocket started bound to the static IP address I defined. Now I was able to send a message to the Server, there the message got parsed and the result was sent back to the client.