glm_java
glm_java

Reputation: 19

Android Client/ Laptop Server

I'm trying to create a client/server application where, a laptop acts like server and share its internet connection with an android phone that acts like client, I can enstablish the connection between client and server, the problem is that when the client try to write on the socket, it get stuck there. This is the android xml

<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="com.example.giuseppe.client">
<uses-permission android:name="android.permission.INTERNET" >
</uses-permission>

<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" >
</uses-permission>

<application
    android:allowBackup="true"
    android:icon="@mipmap/ic_launcher"
    android:label="@string/app_name"
    android:roundIcon="@mipmap/ic_launcher_round"
    android:supportsRtl="true"
    android:theme="@style/AppTheme">
    <activity android:name=".MainActivity">
        <intent-filter>
            <action android:name="android.intent.action.MAIN" />

            <category android:name="android.intent.category.LAUNCHER" />
        </intent-filter>
    </activity>
</application>

This is the android client

package com.example.giuseppe.client;

import java.io.*;
import java.net.*;


import android.app.Activity;
import android.os.Bundle;
import android.view.View;
import android.widget.EditText;
import android.widget.TextView;


import org.w3c.dom.Text;

import static java.net.InetAddress.*;

public class MainActivity extends Activity {
    private Socket socket;
    private static final int port=5555;
private static final String addr="192.168.1.37";


@Override
protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.activity_main);
    new Thread(new Client()).start();
}

public void onClick(View view){
    try{
        TextView tx=(TextView) findViewById(R.id.txt);

        EditText et= (EditText) findViewById(R.id.et);
        String str= et.getText().toString();
        DataOutputStream out= new DataOutputStream(new BufferedOutputStream(socket.getOutputStream())) ;
        out.writeUTF(str);
        out.close();
        socket.close();

    }catch(UnknownHostException e){
        e.printStackTrace();
    }catch (IOException e){
        e.printStackTrace();
    }catch (Exception e){
        e.printStackTrace();
    }
}

class Client implements Runnable {
    @Override
    public void run() {
        try {
            TextView tx= (TextView) findViewById(R.id.txt);
            tx.setText("Before connection");
            InetAddress server = InetAddress.getByName(addr);
            socket = new Socket("192.168.1.37", port);
            tx.setText("After connection");
        } catch (UnknownHostException a) {

        } catch (IOException a) {

        } catch (Exception a){

        }
    }
}

This is the server code

 import java.io.*;
 import java.net.*;
public class Server {

public static void main(String[] args) {
    int port=5555;
    byte[] buff =new byte[1024];
    String str; 
    // TODO Auto-generated method stub
    try {
        ServerSocket server=new ServerSocket(port);
        System.out.println("Before accept");
        Socket client=server.accept(); 
        System.out.println("After accept");
        DataInputStream in=new DataInputStream(new BufferedInputStream(client.getInputStream()));
        str=in.readUTF();

        
        System.out.println("Message received");
        in.close();
        client.close();
    } catch (IOException e) {
        // TODO Auto-generated catch block
        e.printStackTrace();
    } 
}

}

I suppose the problem is in the client because I also tried to use the server to send a string and while the server send it, the client doesn't receive it. Sorry for my bad english. Thanks to all

+++++EDIT+++++

I tried also OutputStream out=socket.getOutputStream(); and then out.write(str.getBytes()), but in this case it get stuck here, when I try to write in the socket, could be any android's configuration the problem?

Upvotes: 0

Views: 142

Answers (2)

momo
momo

Reputation: 16

That is an Art Producer / Consumer Problem. After the Server return from accept , the Client has an etablished Connection to the Server. While the Sever is waiting for data to read (Consumer) , The Client (Producer ) is doing nothing. The Client should write something on The Socket In order to continue.

Upvotes: 0

hagrawal7777
hagrawal7777

Reputation: 14668

Disclaimer: I cannot validate the correctness of your Android code so I am assuming that is fine, and only commenting on your networking code, which is the root cause of your issue.

2 main problems in your code are:

  1. In your server code you are reading and reading, and doing nothing
  2. Your server is single threaded

You main problem is #1 above and as soon as you resolve your #1, you will get another problem which is #2.

Your #1 problem is that you need to define some logic on how you want to consider the end of stream or input, refer below code example (read the comments in the code), also you don't necessarily need to use readUTF method, instead you can use "I/O bridge classes" like InputStreamReader which acts as a bridge between your byte stream and character stream, so you can use InputStreamReader clientSocketReader = (new InputStreamReader(clientSocket.getInputStream(), "UTF8"));, and I cannot say why you really need DataInputStream and can't use a InputStreamReader but in my opinion you can go for using a bridge class.

    int portNumber = 8001;
    try {
        ServerSocket serverSocket = new ServerSocket(portNumber);
        Socket clientSocket = serverSocket.accept();
        PrintWriter out = new PrintWriter(clientSocket.getOutputStream(), true);
        BufferedReader in = new BufferedReader(new InputStreamReader(clientSocket.getInputStream()));
        String inputLine;
        while ((inputLine = in.readLine()) != null) { // **** this basically means that read one full line, you have to specify condition like this, so suppose you have created a telnet session with this server now keep on typing and as soon you will hit entered then while block processing will start. 
            System.out.println("@@@ " + inputLine);
            out.println(inputLine); // *** here same input is written back to the client, so suppose you have telnet session then same input can be seen
        }
    } catch (IOException e) {
        System.out.println(
                "Exception caught when trying to listen on port " + portNumber + " or listening for a connection");
        System.out.println(e.getMessage());
    }

Now your #2 problem is that your server is single threaded, you need to have a multi-threaded server which basically means that you should process each client request in a new thread. Read this answer of mine which throws more light on single threaded v/s multi-threaded server. See below code example for a multi-threaded server:

import java.io.*;
import java.net.InetAddress;
import java.net.ServerSocket;
import java.net.Socket;
import java.net.SocketException;
import java.net.SocketTimeoutException;

import com.learn.Person;

/**
 * @author himanshu.agrawal
 *
 */
public class TestWebServer2 {

    public static void main(String[] args) throws IOException {
        startWebServer();
    }

    /**
     * test "backlog" in ServerSocket constructor
test -- If <i>bindAddr</i> is null, it will default accepting
     * connections on any/all local addresses.
     * @throws IOException
     */

    private static void startWebServer() throws IOException {
        InetAddress address = InetAddress.getByName("localhost");
        ServerSocket serverSocket = new ServerSocket(8001, 1, address);
        // if set it to 1000 (1 sec.) then after 1 second porgram will exit with SocketTimeoutException because server socket will only listen for 1 second.
        // 0 means infinite
        serverSocket.setSoTimeout(/*1*/0000);

        while(true){
            /*Socket clientSocket = serverSocket.accept();*/ // a "blocking" call which waits until a connection is requested
            System.out.println("1");
            TestWebServer2.SocketThread socketThread = new TestWebServer2().new SocketThread();
            try {
                socketThread.setClientSocket(serverSocket.accept());
                Thread thread = new Thread(socketThread);
                thread.start();
                System.out.println("2");
            } catch (SocketTimeoutException socketTimeoutException) {
                System.err.println(socketTimeoutException);
            }
        }

    }

    public class SocketThread implements Runnable{

        Socket clientSocket;

        public void setClientSocket(Socket clientSocket) throws SocketException {
            this.clientSocket = clientSocket;
            //this.clientSocket.setSoTimeout(2000); // this will set timeout for reading from client socket.
        }

        public void run(){
            System.out.println("####### New client session started." + clientSocket.hashCode() + " | clientSocket.getLocalPort(): " + clientSocket.getLocalPort()
                    + " | clientSocket.getPort(): " + clientSocket.getPort());
            try {
                listenToSocket(); // create this method and you implement what you want to do with the connection.
            } catch (IOException e) {
                System.err.println("#### EXCEPTION.");
                e.printStackTrace();
            }
        }


    }

}

Upvotes: 1

Related Questions