В настоящее время я пишу приложение, которое может запускать различные мини-игры, такие как Snake, Tic Tac Toe и т. Д. На интерактивном светодиодном столе.Приложение работает на Raspi без дисплея и получает данные о взаимодействии пользователя с самостоятельно написанным приложением для Android, которое связывается с Pi с помощью TCP Socket
s.
, поскольку Sockets
самине знаю, где еще подключена другая сторона связи. Теперь я хочу реализовать собственную логику keep-alive
, которая заставляет сервер завершать работу клиентского потока после трехкратного ожидания сообщения подтверждения активности в течение 200 мс каждый раз.в случае неожиданного сбоя клиента.
У меня уже есть работающая обычная функция подключения / отключения, которая отключает поток, когда клиент отключается, выходя из приложения.Однако, так как мне нужно, чтобы за светодиодным столом одновременно управлял только один человек (чтобы другие не могли просто подключиться к телефону и закрыть игру во время игры), я хочу быть на 100% уверенным, что если соединение неожиданно оборветсяон будет обнаружен в течение короткого периода времени (около 600 - 5000 мс).
В настоящее время для логики поддержания активности я использую этот код на стороне сервера (создаваемый соответствующим клиентским потоком):
public class KeepAlive implements Runnable {
private ClientThread endPoint;
private InputStream in;
private OutputStream out;
public KeepAlive(Socket keepAliveSocket, ClientThread endPoint) {
try {
in = keepAliveSocket.getInputStream();
out = keepAliveSocket.getOutputStream();
} catch (IOException e) {
}
this.endPoint = endPoint;
}
@Override
public void run() {
boolean waitingForResponse = true;
int keepAlive_waitCycles = 3;
int keepAlive_waitedCycles = 0;
while (endPoint.isConnected()) {
sleep();
try {
out.write(1);
System.out.println("sending");
} catch (IOException e) {
}
sleep();
try {
while (waitingForResponse && keepAlive_waitedCycles < keepAlive_waitCycles) {
if (in.available() > 0) {
in.read();
waitingForResponse = false;
} else {
keepAlive_waitedCycles++;
sleep();
}
System.out.println("receiving - cycle: " + keepAlive_waitedCycles);
}
if (waitingForResponse && keepAlive_waitedCycles == 3) {
endPoint.setConnection(false);
} else {
keepAlive_waitedCycles = 0;
}
} catch (IOException e) {
}
}
}
private void sleep() {
int keepAlive_timeout = 3000;
try {
Thread.sleep(keepAlive_timeout);
} catch (InterruptedException e) {
}
}
}
И этот код на стороне клиента:
public class KeepAlive implements Runnable{
private InputStream in;
private OutputStream out;
KeepAlive(String serverIP) {
int keepAlivePort = 42000;
Log.d("KeepAlive-Test", "KeepAlive created");
try {
Socket keepAliveSocket = new Socket(serverIP, keepAlivePort);
out = keepAliveSocket.getOutputStream();
in = keepAliveSocket.getInputStream();
} catch (IOException e) {}
}
@Override
public void run() {
boolean waitingForResponse = true;
int keepAlive_waitCycles = 3;
int keepAlive_waitedCycles = 0;
Log.d("KeepAlive-Test", "KeepAlive running");
while(NetworkController.isConnected()) {
Log.d("KeepAlive-Test", "while-loop");
sleep();
try {
while (waitingForResponse && keepAlive_waitedCycles < keepAlive_waitCycles) {
if (in.available() > 0) {
in.read();
waitingForResponse = false;
} else {
keepAlive_waitedCycles++;
sleep();
}
Log.d("KeepAlive-Test", "receiving - cycle: " + keepAlive_waitedCycles);
}
if (waitingForResponse && keepAlive_waitedCycles == 3) {
NetworkController.setConnection(false);
} else {
keepAlive_waitedCycles = 0;
}
} catch (IOException e) {}
if (NetworkController.isConnected()) {
sleep();
try {
out.write(1);
Log.d("KeepAlive-Test", "sending");
} catch (IOException e) {}
}
}
}
private void sleep() {
int keepAlive_timeout = 3000;
try {
Thread.sleep(keepAlive_timeout);
} catch (InterruptedException e) {}
}
}
Проблема этого подхода заключается в том, что мне кажется, что я не могу получить какие-либо данные на стороне клиента, что, вероятно,вызвано использованием сокета на сервере, который предназначен для регулярного взаимодействия с клиентом (передается в качестве параметра в конструкторе).
После неудачной попытки я попытался использовать DatagramSocket, я действительно не понялкак правильно их использовать для этого.Сейчас я думаю об использовании ServerSocket, однако боюсь, что порт, который я хочу назначить для ServerSocket, может быть заблокирован, например, сокетом для клиентского потока при подключении клиента.
Подводя итог: есть ли способ исключить порт от назначения ServerSocket.accept ()?Таким образом, я мог легко заблокировать этот порт для последующего использования моего ServerSocket в потоке keep-alive.