Не могу соединить клиент-приложение android с java сервером

460
19 августа 2017, 00:45

Добрый день! Знаком с клиент-серверной разработкой буквально пару часов, написал свой сервер на java и клиент на android. С клиента на java легко могу подключаться к своему серверу, но с андроида ничего не получается, прошу подсказать мне, что я делаю не так, возможно даже мое представление о работе клиент-сервера в корне неверное, вопрос задан скорее всего с целью разобраться с К-С разработкой и понять, так ли вообще я её понял, чем с целью пофиксить баг.(Возможно, ошибка из-за того, что мой сервер может взаимодействовать с клиентом только на одном компьютере, когда у них один ip?)

На java программа представляет консольный чат. Пытался визуализировать его на android.

Сервер на java:

package server;
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.PrintWriter;
import java.net.ServerSocket;
import java.net.Socket;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Iterator;
import java.util.List;
import main.Const;
public class Server {

    /**
     * Специальная "обёртка" для ArrayList, которая обеспечивает доступ к
     * массиву из разных нитей
     */
    private List<Connection> connections =
            Collections.synchronizedList(new ArrayList<Connection>());
    private ServerSocket server;
    /**
     * Конструктор создаёт сервер. Затем для каждого подключения создаётся
     * объект Connection и добавляет его в список подключений.
     */
    public Server() {
        try {
            server = new ServerSocket(Const.Port);
            while (true) {
                Socket socket = server.accept();
                // Создаём объект Connection и добавляем его в список
                Connection con = new Connection(socket);
                connections.add(con);
                // Инициализирует нить и запускает метод run(),
                // которая выполняется одновременно с остальной программой
                con.start();
            }
        } catch (IOException e) {
            e.printStackTrace();
        } finally {
            closeAll();
        }
    }
    /**
     * Закрывает все потоки всех соединений а также серверный сокет
     */
    private void closeAll() {
        try {
            server.close();
            // Перебор всех Connection и вызов метода close() для каждого. Блок
            // synchronized {} необходим для правильного доступа к одним данным
            // их разных нитей
            synchronized(connections) {
                Iterator<Connection> iter = connections.iterator();
                while(iter.hasNext()) {
                    ((Connection) iter.next()).close();
                }
            }
        } catch (Exception e) {
            System.err.println("Потоки не были закрыты!");
        }
    }
    /**
     * Класс содержит данные, относящиеся к конкретному подключению:
     * <ul>
     * <li>имя пользователя</li>
     * <li>сокет</li>
     * <li>входной поток BufferedReader</li>
     * <li>выходной поток PrintWriter</li>
     * </ul>
     * Расширяет Thread и в методе run() получает информацию от пользователя и
     * пересылает её другим
     *
     * @author Влад
     */
    private class Connection extends Thread {
        private BufferedReader in;
        private PrintWriter out;
        private Socket socket;
        private String name = "";
        /**
         * Инициализирует поля объекта и получает имя пользователя
         *
         * @param socket
         *            сокет, полученный из server.accept()
         */
        public Connection(Socket socket) {
            this.socket = socket;
            try {
                in = new BufferedReader(new InputStreamReader(
                        socket.getInputStream()));
                out = new PrintWriter(socket.getOutputStream(), true);
            } catch (IOException e) {
                e.printStackTrace();
                close();
            }
        }
        /**
         * Запрашивает имя пользователя и ожидает от него сообщений. При
         * получении каждого сообщения, оно вместе с именем пользователя
         * пересылается всем остальным.
         *
         * @see java.lang.Thread#run()
         */
        @Override
        public void run() {
            try {
                name = in.readLine();
                // Отправляем всем клиентам сообщение о том, что зашёл новый пользователь
                synchronized(connections) {
                    Iterator<Connection> iter = connections.iterator();
                    while(iter.hasNext()) {
                        ((Connection) iter.next()).out.println(name + " cames now");
                    }
                }
                String str = "";
                while (true) {
                    str = in.readLine();
                    if(str.equals("exit")) break;
                    // Отправляем всем клиентам очередное сообщение
                    synchronized(connections) {
                        Iterator<Connection> iter = connections.iterator();
                        while(iter.hasNext()) {
                            ((Connection) iter.next()).out.println(name + ": " + str);
                        }
                    }
                }
                synchronized(connections) {
                    Iterator<Connection> iter = connections.iterator();
                    while(iter.hasNext()) {
                        ((Connection) iter.next()).out.println(name + " has left");
                    }
                }
            } catch (IOException e) {
                e.printStackTrace();
            } finally {
                close();
            }
        }
        /**
         * Закрывает входной и выходной потоки и сокет
         */
        public void close() {
            try {
                in.close();
                out.close();
                socket.close();
                // Если больше не осталось соединений, закрываем всё, что есть и
                // завершаем работу сервера
                connections.remove(this);
                if (connections.size() == 0) {
                    Server.this.closeAll();
                    System.exit(0);
                }
            } catch (Exception e) {
                System.err.println("Потоки не были закрыты!");
            }
        }
    }
}

Клиент на android(пытался скопировать клиент с java):

package ua.bellkross.cchat;
import android.support.v7.app.AppCompatActivity;
import android.os.Bundle;
import android.view.View;
import android.widget.Button;
import android.widget.EditText;
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.PrintWriter;
import java.net.Socket;
public class ChatActivity extends AppCompatActivity {
    public static final int Port = 8283;
    private String name,ip;
    private BufferedReader in;
    private PrintWriter out;
    private Socket socket;
    Button btnSend, btnExit;
    private EditText etChat,etMessage;
    private Resender resend;
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_chat);
        btnSend = (Button)findViewById(R.id.btnSend);
        btnExit = (Button)findViewById(R.id.btnExit);
        etChat = (EditText) findViewById(R.id.etChat);
        etMessage = (EditText) findViewById(R.id.etMessage);
        name = getIntent().getExtras().getString("Name").toString();
        ip = getIntent().getExtras().getString("Ip").toString();
        try{
            socket = new Socket(ip, Port);
            in = new BufferedReader(new InputStreamReader(socket.getInputStream()));
            out = new PrintWriter(socket.getOutputStream(), true);
            out.println(name);
            resend = new Resender();
            resend.start();
        } catch (Exception e) {
            e.printStackTrace();
        }
    }
    private class Resender extends Thread {
        private boolean stoped;
        /**
         * Прекращает пересылку сообщений
         */
        public void setStop() {
            stoped = true;
        }
        /**
         * Считывает все сообщения от сервера и печатает их в консоль.
         * Останавливается вызовом метода setStop()
         *
         * @see java.lang.Thread#run()
         */
        @Override
        public void run() {
            try {
                while (!stoped) {
                    String str = in.readLine();
                    etChat.append(str);
                }
            } catch (IOException e) {
                System.err.println("Ошибка при получении сообщения.");
                e.printStackTrace();
            }
        }
    }
    private void close() {
        try {
            in.close();
            out.close();
            socket.close();
        } catch (Exception e) {
            System.err.println("Потоки не были закрыты!");
        }
    }
    public void send(View v){
        String str = etMessage.getText().toString();
        if(str.length()>0) {
            out.println(str);
        }
    }
    public void exit(View v){
        resend.setStop();
        close();
    }
}

Клиент на java:

package client;
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.PrintWriter;
import java.net.Socket;
import java.util.Scanner;
import main.Const;
/**
 * Обеспечивает работу программы в режиме клиента
 *
 */
public class Client {
    private BufferedReader in;
    private PrintWriter out;
    private Socket socket;
    /**
     * Запрашивает у пользователя ник и организовывает обмен сообщениями с
     * сервером
     */
    public Client() {
        Scanner scan = new Scanner(System.in);
        System.out.println("Введите IP для подключения к серверу.");
        System.out.println("Формат: xxx.xxx.xxx.xxx");
        String ip = scan.nextLine();
        try {
            // Подключаемся в серверу и получаем потоки(in и out) для передачи сообщений
            socket = new Socket(ip, Const.Port);
            in = new BufferedReader(new InputStreamReader(socket.getInputStream()));
            out = new PrintWriter(socket.getOutputStream(), true);
            System.out.println("Введите свой ник:");
            out.println(scan.nextLine());
            // Запускаем вывод всех входящих сообщений в консоль
            Resender resend = new Resender();
            resend.start();
            // Пока пользователь не введёт "exit" отправляем на сервер всё, что
            // введено из консоли
            String str = "";
            while (!str.equals("exit")) {
                str = scan.nextLine();
                out.println(str);
            }
            resend.setStop();
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            close();
        }
    }
    /**
     * Закрывает входной и выходной потоки и сокет
     */
    private void close() {
        try {
            in.close();
            out.close();
            socket.close();
        } catch (Exception e) {
            System.err.println("Потоки не были закрыты!");
        }
    }
    /**
     * Класс в отдельной нити пересылает все сообщения от сервера в консоль.
     * Работает пока не будет вызван метод setStop().
     *
     * @author Влад
     */
    private class Resender extends Thread {
        private boolean stoped;
        /**
         * Прекращает пересылку сообщений
         */
        public void setStop() {
            stoped = true;
        }
        /**
         * Считывает все сообщения от сервера и печатает их в консоль.
         * Останавливается вызовом метода setStop()
         *
         * @see java.lang.Thread#run()
         */
        @Override
        public void run() {
            try {
                while (!stoped) {
                    String str = in.readLine();
                    System.out.println(str);
                }
            } catch (IOException e) {
                System.err.println("Ошибка при получении сообщения.");
                e.printStackTrace();
            }
        }
    }
}

При нажатии на кнопку "Send", т.е. при отправке сообщения с андроид клиента выдает такую ошибку:

08-17 09:03:20.861 10296-10296/ua.bellkross.cchat E/AndroidRuntime: FATAL EXCEPTION: main
                                                                    Process: ua.bellkross.cchat, PID: 10296
                                                                    java.lang.IllegalStateException: Could not execute method for android:onClick
                                                                        at android.support.v7.app.AppCompatViewInflater$DeclaredOnClickListener.onClick(AppCompatViewInflater.java:293)
                                                                        at android.view.View.performClick(View.java:5610)
                                                                        at android.view.View$PerformClick.run(View.java:22265)
                                                                        at android.os.Handler.handleCallback(Handler.java:751)
                                                                        at android.os.Handler.dispatchMessage(Handler.java:95)
                                                                        at android.os.Looper.loop(Looper.java:154)
                                                                        at android.app.ActivityThread.main(ActivityThread.java:6077)
                                                                        at java.lang.reflect.Method.invoke(Native Method)
                                                                        at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:866)
                                                                        at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:756)
                                                                     Caused by: java.lang.reflect.InvocationTargetException
                                                                        at java.lang.reflect.Method.invoke(Native Method)
                                                                        at android.support.v7.app.AppCompatViewInflater$DeclaredOnClickListener.onClick(AppCompatViewInflater.java:288)
                                                                        at android.view.View.performClick(View.java:5610at android.view.View$PerformClick.run(View.java:22265at android.os.Handler.handleCallback(Handler.java:751at android.os.Handler.dispatchMessage(Handler.java:95at android.os.Looper.loop(Looper.java:154at android.app.ActivityThread.main(ActivityThread.java:6077at java.lang.reflect.Method.invoke(Native Methodat com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:866at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:756Caused by: java.lang.NullPointerException: Attempt to invoke virtual method 'void java.io.PrintWriter.println(java.lang.String)' on a null object reference
                                                                        at ua.bellkross.cchat.ChatActivity.send(ChatActivity.java:98)
                                                                        at java.lang.reflect.Method.invoke(Native Methodat android.support.v7.app.AppCompatViewInflater$DeclaredOnClickListener.onClick(AppCompatViewInflater.java:288at android.view.View.performClick(View.java:5610at android.view.View$PerformClick.run(View.java:22265at android.os.Handler.handleCallback(Handler.java:751at android.os.Handler.dispatchMessage(Handler.java:95at android.os.Looper.loop(Looper.java:154at android.app.ActivityThread.main(ActivityThread.java:6077at java.lang.reflect.Method.invoke(Native Methodat com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:866at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:756

UPD: Так же, в самом начале(в андроид клиенте), как только я перехожу на активити чата и пытаюсь соединиться с сокетом получаю такую ошибку: (Пишет, что Permission denied, возможно Permission нужно прописать в манифест для работы с сокетами, но какой?)

08-17 10:26:30.632 3570-3570/ua.bellkross.cchat W/System.err: java.net.SocketException: Permission denied
08-17 10:26:30.632 3570-3570/ua.bellkross.cchat W/System.err:     at java.net.Socket.createImpl(Socket.java:454)
08-17 10:26:30.633 3570-3570/ua.bellkross.cchat W/System.err:     at java.net.Socket.<init>(Socket.java:423)
08-17 10:26:30.633 3570-3570/ua.bellkross.cchat W/System.err:     at java.net.Socket.<init>(Socket.java:210)
08-17 10:26:30.633 3570-3570/ua.bellkross.cchat W/System.err:     at ua.bellkross.cchat.ChatActivity.onCreate(ChatActivity.java:39)
08-17 10:26:30.634 3570-3570/ua.bellkross.cchat W/System.err:     at android.app.Activity.performCreate(Activity.java:6662)
08-17 10:26:30.634 3570-3570/ua.bellkross.cchat W/System.err:     at android.app.Instrumentation.callActivityOnCreate(Instrumentation.java:1118)
08-17 10:26:30.634 3570-3570/ua.bellkross.cchat W/System.err:     at android.app.ActivityThread.performLaunchActivity(ActivityThread.java:2599)
08-17 10:26:30.634 3570-3570/ua.bellkross.cchat W/System.err:     at android.app.ActivityThread.handleLaunchActivity(ActivityThread.java:2707)
08-17 10:26:30.634 3570-3570/ua.bellkross.cchat W/System.err:     at android.app.ActivityThread.-wrap12(ActivityThread.java)
08-17 10:26:30.634 3570-3570/ua.bellkross.cchat W/System.err:     at android.app.ActivityThread$H.handleMessage(ActivityThread.java:1460)
08-17 10:26:30.634 3570-3570/ua.bellkross.cchat W/System.err:     at android.os.Handler.dispatchMessage(Handler.java:102)
08-17 10:26:30.634 3570-3570/ua.bellkross.cchat W/System.err:     at android.os.Looper.loop(Looper.java:154)
08-17 10:26:30.634 3570-3570/ua.bellkross.cchat W/System.err:     at android.app.ActivityThread.main(ActivityThread.java:6077)
08-17 10:26:30.635 3570-3570/ua.bellkross.cchat W/System.err:     at java.lang.reflect.Method.invoke(Native Method)
08-17 10:26:30.635 3570-3570/ua.bellkross.cchat W/System.err:     at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:866)
08-17 10:26:30.635 3570-3570/ua.bellkross.cchat W/System.err:     at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:756)

Добавил в манифест разрешения, запустил, получил новый эксепшн:

08-17 10:36:13.071 12809-12809/ua.bellkross.cchat W/System.err: android.os.NetworkOnMainThreadException
08-17 10:36:13.072 12809-12809/ua.bellkross.cchat W/System.err:     at android.os.StrictMode$AndroidBlockGuardPolicy.onNetwork(StrictMode.java:1303)
08-17 10:36:13.072 12809-12809/ua.bellkross.cchat W/System.err:     at java.net.AbstractPlainSocketImpl.doConnect(AbstractPlainSocketImpl.java:333)
08-17 10:36:13.072 12809-12809/ua.bellkross.cchat W/System.err:     at java.net.AbstractPlainSocketImpl.connectToAddress(AbstractPlainSocketImpl.java:196)
08-17 10:36:13.072 12809-12809/ua.bellkross.cchat W/System.err:     at java.net.AbstractPlainSocketImpl.connect(AbstractPlainSocketImpl.java:178)
08-17 10:36:13.072 12809-12809/ua.bellkross.cchat W/System.err:     at java.net.SocksSocketImpl.connect(SocksSocketImpl.java:356)
08-17 10:36:13.072 12809-12809/ua.bellkross.cchat W/System.err:     at java.net.Socket.connect(Socket.java:586)
08-17 10:36:13.072 12809-12809/ua.bellkross.cchat W/System.err:     at java.net.Socket.connect(Socket.java:535)
08-17 10:36:13.072 12809-12809/ua.bellkross.cchat W/System.err:     at java.net.Socket.<init>(Socket.java:427)
08-17 10:36:13.074 12809-12809/ua.bellkross.cchat W/System.err:     at java.net.Socket.<init>(Socket.java:210)
08-17 10:36:13.074 12809-12809/ua.bellkross.cchat W/System.err:     at ua.bellkross.cchat.ChatActivity.onCreate(ChatActivity.java:39)
08-17 10:36:13.075 12809-12809/ua.bellkross.cchat W/System.err:     at android.app.Activity.performCreate(Activity.java:6662)
08-17 10:36:13.075 12809-12809/ua.bellkross.cchat W/System.err:     at android.app.Instrumentation.callActivityOnCreate(Instrumentation.java:1118)
08-17 10:36:13.075 12809-12809/ua.bellkross.cchat W/System.err:     at android.app.ActivityThread.performLaunchActivity(ActivityThread.java:2599)
08-17 10:36:13.075 12809-12809/ua.bellkross.cchat W/System.err:     at android.app.ActivityThread.handleLaunchActivity(ActivityThread.java:2707)
08-17 10:36:13.075 12809-12809/ua.bellkross.cchat W/System.err:     at android.app.ActivityThread.-wrap12(ActivityThread.java)
08-17 10:36:13.075 12809-12809/ua.bellkross.cchat W/System.err:     at android.app.ActivityThread$H.handleMessage(ActivityThread.java:1460)
08-17 10:36:13.075 12809-12809/ua.bellkross.cchat W/System.err:     at android.os.Handler.dispatchMessage(Handler.java:102)
08-17 10:36:13.076 12809-12809/ua.bellkross.cchat W/System.err:     at android.os.Looper.loop(Looper.java:154)
08-17 10:36:13.076 12809-12809/ua.bellkross.cchat W/System.err:     at android.app.ActivityThread.main(ActivityThread.java:6077)
08-17 10:36:13.076 12809-12809/ua.bellkross.cchat W/System.err:     at java.lang.reflect.Method.invoke(Native Method)
08-17 10:36:13.077 12809-12809/ua.bellkross.cchat W/System.err:     at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:866)
08-17 10:36:13.077 12809-12809/ua.bellkross.cchat W/System.err:     at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:756)
Answer 1

Проблема была в том, что я выполнял соединение с сервером в основном потоке, нужно выделить побочный поток.

READ ALSO
Где можно найти классы для kaitai struct?

Где можно найти классы для kaitai struct?

Хочу начать работу с Kaitai Struct, для обработки бинарных файловИзначально там требуется написать

232
Проблема с запуском приложения на spring-mvc и spring-security

Проблема с запуском приложения на spring-mvc и spring-security

Приложение использует spring-mvc, spring-data и spring-security на Tomcat 9При попытке запустить томкат отказывается делать деплой с таким сообщением

227
Получение названия столбцов через Hibernate

Получение названия столбцов через Hibernate

Добрый день, подскажите пожалуйста, есть ли возможность получить название столбцов выгрузки SQL запроса в Hibernate? Суть вопроса, есть веб-сервис...

284
Как передать массив byte из java в c++

Как передать массив byte из java в c++

В java объявлен метод

231