Добрый день! Знаком с клиент-серверной разработкой буквально пару часов, написал свой сервер на 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: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.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 Method)
at android.support.v7.app.AppCompatViewInflater$DeclaredOnClickListener.onClick(AppCompatViewInflater.java:288)
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)
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)
Проблема была в том, что я выполнял соединение с сервером в основном потоке, нужно выделить побочный поток.
Кофе для программистов: как напиток влияет на продуктивность кодеров?
Рекламные вывески: как привлечь внимание и увеличить продажи
Стратегії та тренди в SMM - Технології, що формують майбутнє сьогодні
Выделенный сервер, что это, для чего нужен и какие характеристики важны?
Современные решения для бизнеса: как облачные и виртуальные технологии меняют рынок
Хочу начать работу с Kaitai Struct, для обработки бинарных файловИзначально там требуется написать
Приложение использует spring-mvc, spring-data и spring-security на Tomcat 9При попытке запустить томкат отказывается делать деплой с таким сообщением
Добрый день, подскажите пожалуйста, есть ли возможность получить название столбцов выгрузки SQL запроса в Hibernate? Суть вопроса, есть веб-сервис...