🚀 go-pugleaf

RetroBBS NetNews Server

Inspired by RockSolid Light RIP Retro Guy

Thread View: pl.comp.lang.java
4 messages
4 total messages Started by TheGuru Wed, 11 Sep 2013 09:08
"Usieciowienie" gier
#153864
Author: TheGuru
Date: Wed, 11 Sep 2013 09:08
405 lines
12645 bytes
Witajcie,

napisałem kilka gier logicznych (kolejne czekają ) 
https://play.google.com/store/apps/developer?id=TheGuru#?t=W251bGwsbnVsbCxudWxsLDEsImNvbS50aGVndXJ1Lm1hdGhncmFwaCJd. 
Gry tracą na atrakcyjności kiedy można grać tylko na 1 urządzeniu (a 
niektóre nie mają sensu kiedy znasz "karty" przeciwnika).

Od jakiegoś czasu próbuje dodać do nich obsługę sieci ale idzie mi gorzej 
niż po grudzie.
Przerobiłem podobne wątki na tym forum ale nie ogarnąłem tematu.

Może mam złe założenia i w ogóle nie idę w dobrym kierunku.

Komunikację wyobrażam to sobie jak w np GG. Pierwszy zawodnik wykonuje ruch 
i w formie krótkiego stringa wysyłam informację np 10050906 co by znaczyło 
że z pola 10:5 wykonuje ruch na pole 9:6.

W sieci znalazłem kod prostego komunikatora napisanego w C. Próbowałem go 
przerobić na interfejs androida ale cos mi nie poszło bo nie mam 
komunikacji.

Aplikacje uruchamiam w 2 oknach AVD licząc, że będę mógł pisać z jednego do 
drugiego, jak to działało w przykładzie C.
Niestety na andku nie działa. Jak by co to mam wykupiony serwer (co prawda 
do zdjęć, ale mam dostęp do ftp i chyba mogę go użyć jeśli będzie taka 
potrzeba).

Będę zobowiązany jeśli ktoś poświęci swój czas by mi pomóc.

Poniżej przesyłam kod.
To NIE JEST użyteczna aplikacja tylko program testujący :-)




activity_main.xml

<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:orientation="vertical">

    <Button
        android:id="@+id/bStworz"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="Utwórz połączenie" />

    <Button
        android:id="@+id/bPolacz"
        android:layout_width="168dp"
        android:layout_height="wrap_content"
        android:text="Połącz" />

    <TextView
        android:id="@+id/tvTresc"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:layout_weight="0.37"
        android:hint="Tereść rozmowy" />

    <EditText
        android:id="@+id/etZdanie"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:ems="10"
        android:hint="napisz" />

    <Button
        android:id="@+id/bWyslij"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="Wyślij" />

</LinearLayout>


MainActivity.java

package com.example.komunikator;

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

public class MainActivity extends Activity implements OnClickListener {

    Serwer serwer;
    Klient klient;
    TextView tvWyswietl;
    EditText etNapisz;
    Button bStworz, bPolacz, bWyslij;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

        tvWyswietl = (TextView) findViewById(R.id.tvTresc);
        etNapisz = (EditText) findViewById(R.id.etZdanie);
        bStworz = (Button) findViewById(R.id.bStworz);
        bPolacz = (Button) findViewById(R.id.bPolacz);
        bWyslij = (Button) findViewById(R.id.bWyslij);

        bStworz.setOnClickListener(this);
        bPolacz.setOnClickListener(this);
        bWyslij.setOnClickListener(this);

        serwer = new Serwer(tvWyswietl,etNapisz);
        klient = new Klient("127.0.0.1");

    }

    @Override
    public void onClick(View v) {

        switch (v.getId()) {
        case R.id.bStworz:
            serwer.startRunning();
            //tvWyswietl.setText("start running");
            break;
        case R.id.bPolacz:

            break;
        case R.id.bWyslij:

            break;
        }
    }

}

Serwer.java

Kod:
package com.example.komunikator;

import java.io.EOFException;
import java.io.IOException;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.net.ServerSocket;
import java.net.Socket;

import android.widget.Button;
import android.widget.EditText;
import android.widget.TextView;

public class Serwer {

    private ObjectOutputStream output;
    private ObjectInputStream input;
    private ServerSocket server;
    private Socket connection;
    private TextView tvTresc;
    private EditText etZdanie;

    // constructor
    public Serwer(TextView tvT, EditText etT) {

        tvTresc = tvT;
        etZdanie = etT;

    }

    // ustanowienie i uruchomienie serwera
    public void startRunning() {
        try {
            tvTresc.append("\npróba \n");
            server = new ServerSocket(6789, 100);
            tvTresc.append("Serwer : " + String.valueOf(server));
            while (true) {
                tvTresc.append("próba 2");
                try {

                    waitForConnection();
                    setupStreams();
                    whileChatting();
                } catch (EOFException eofException) {
                    showMessage("\n Server zakończył połączenie");
                } finally {
                    closeCrap();
                    tvTresc.setText("próba 3");
                }
            }
        } catch (IOException ioException) {
            ioException.printStackTrace();
        }
        tvTresc.append("\npróba 4");
    }

    // wait for connection and display info
    private void waitForConnection() throws IOException {
        showMessage("Czekaj na połączenie...\n");
        connection = server.accept();
        showMessage("Jesteś połączony z "
                + connection.getInetAddress().getHostName());
    }

    // get string to send and receive data
    private void setupStreams() throws IOException {
        output = new ObjectOutputStream(connection.getOutputStream());
        output.flush();
        input = new ObjectInputStream(connection.getInputStream());
        showMessage("\n Strumień danych ustanowiony! \n");
    }

    // podczas połączenia
    private void whileChatting() throws IOException {
        String message = "Jesteś teraz połączony! ";

        sendMessage(message);
        ableToType(true);
        do {
            try {
                message = (String) input.readObject();
                showMessage("\n" + message);

            } catch (ClassNotFoundException classNotFoundException) {
                showMessage("\n Nie rozpoznaję tego typu ");
            }
        } while (!message.equals("CLIENT - END"));
    }

    // zamknięcie soketu i połączenia po zakończeniu
    private void closeCrap() {
        showMessage("\n zamykam połączenie... \n");
        ableToType(false);
        try {
            output.close();
            input.close();
            connection.close();
        } catch (IOException ioException) {

            ioException.printStackTrace();
        }
    }

    private void sendMessage(String message) {
        try {
            output.writeObject("SERVER - " + message);
            output.flush();
            showMessage("\nSERVER + " + message);

        } catch (IOException ioException) {
            tvTresc.append("\n Błąd : Nie mogę wysłać wiadomości! ");

        }
    }

    private void showMessage(final String text) {

        //tvTresc.setText("próba 9");
        tvTresc.append(text);
    }

    // let the user type stuff to
    private void ableToType(final boolean tof) {

        /*
         * SwingUtilities.invokeLater(new Runnable() {
         *
         * @Override public void run() { userText.setEditable(tof); } });
         */
    }
}

Klient.java

Kod:
package com.example.komunikator;

import java.io.EOFException;
import java.io.IOException;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.net.InetAddress;
import java.net.Socket;

import android.widget.Button;
import android.widget.EditText;
import android.widget.TextView;

public class Klient{

    private ObjectOutputStream output;
    private ObjectInputStream input;
    private String message = "";
    private String serverIP;
    private Socket connection;
    private TextView tvTresc;
    private EditText etZdanie;

    public Klient(String host) {
        serverIP = host;

    }

    public void startRunning() {
        // Połącz z serwerem
        try {
            connectToServer();
            setupStreams();
            whileChatting();
        } catch (EOFException eofException) {
            showMessage("\n Klient zakończył połączenie");
        } catch (IOException ioException) {
            ioException.printStackTrace();
        } finally {
            closeCrap();
        }
    }

    // connect to server
    private void connectToServer() throws IOException {

        showMessage("Próbuje sie połączyć...\n");
        connection = new Socket(InetAddress.getByName(serverIP), 6789);
        showMessage("Połączony z : "
                + connection.getInetAddress().getHostName());

    }

    // ustawienie strumienia i odbiór wiadomości
    private void setupStreams() throws IOException {

        output = new ObjectOutputStream(connection.getOutputStream());
        output.flush();
        input = new ObjectInputStream(connection.getInputStream());
        showMessage("\n strumień gotowy");
    }

    // podczas przesyłania wiadomości
    private void whileChatting() throws IOException {

        //ableToType(true);
        do {
            try {
                message = (String) input.readObject();
                showMessage("\n" + message);
            } catch (ClassNotFoundException classNotFoundException) {
                showMessage("\n nie rozpoznaja typu");
            }

        } while (!message.equals("SERVER - END"));

    }

    //zamknięcie strumienia i soketu
    private void closeCrap() {
        showMessage("\n połączenie zakończone...");
        ableToType(false);
        try {
            output.close();
            input.close();
            connection.close();

        } catch (IOException ioException) {

            ioException.printStackTrace();
        }

    }

    // wysyłanie wiadomości do serwera
    private void sendMessage(String message) {
        try {
            output.writeObject("CLIENT - " + message);
            output.flush();
            showMessage("\nCLIENT - " + message);
        } catch (IOException ioException) {
            tvTresc.append("\n cos poszło nie tak !");
        }
    }

    // change / update chatWindow
    private void showMessage(final String m) {
        tvTresc.append(m);
        /*
        SwingUtilities.invokeLater(new Runnable() {
            @Override
            public void run() {
                chatWindow.append(m);
            }
        });*/
    }

    // gives user permissions to type crap into the text box
    private void ableToType(final boolean tof){
        /*
        SwingUtilities.invokeLater(
                new Runnable() {
                    public void run(){
                        userText.setEditable(tof);
                    }

                }
                );*/
    }
} 
Re: "Usieciowienie" gier
#153865
Author: TheGuru
Date: Sun, 22 Sep 2013 16:49
10 lines
1298 bytes
Znalazłem miejsce, które sprawia mi kłopot ale nie umiem go rozwiązać.

Przy okazji szukania rozwiązania natknąłem się na AndEngine nie moge znaleźć 
dokumentacji do rozszerzenia multiplayer. na ich stronie tez niczego nie 
widzę.

Macie jakąś dokumentację do tych bibliotek?

pozdrawiam licząc na pomoc
robert 
Re: "Usieciowienie" gier
#153866
Author: Arivald
Date: Mon, 23 Sep 2013 05:00
156 lines
7043 bytes
W dniu 2013-09-11 11:08, TheGuru pisze:
> Witajcie,
>
> napisałem kilka gier logicznych (kolejne czekają )
> https://play.google.com/store/apps/developer?id=TheGuru#?t=W251bGwsbnVsbCxudWxsLDEsImNvbS50aGVndXJ1Lm1hdGhncmFwaCJd.
> Gry tracą na atrakcyjności kiedy można grać tylko na 1 urządzeniu (a
> niektóre nie mają sensu kiedy znasz "karty" przeciwnika).
>
> Od jakiegoś czasu próbuje dodać do nich obsługę sieci ale idzie mi
> gorzej niż po grudzie.
> Przerobiłem podobne wątki na tym forum ale nie ogarnąłem tematu.
>
> Może mam złe założenia i w ogóle nie idę w dobrym kierunku.
>
> Komunikację wyobrażam to sobie jak w np GG. Pierwszy zawodnik wykonuje
> ruch i w formie krótkiego stringa wysyłam informację np 10050906 co by
> znaczyło że z pola 10:5 wykonuje ruch na pole 9:6.
>
> W sieci znalazłem kod prostego komunikatora napisanego w C. Próbowałem
> go przerobić na interfejs androida ale cos mi nie poszło bo nie mam
> komunikacji.
>
> Aplikacje uruchamiam w 2 oknach AVD licząc, że będę mógł pisać z jednego
> do drugiego, jak to działało w przykładzie C.
> Niestety na andku nie działa. Jak by co to mam wykupiony serwer (co
> prawda do zdjęć, ale mam dostęp do ftp i chyba mogę go użyć jeśli będzie
> taka potrzeba).
>
> Będę zobowiązany jeśli ktoś poświęci swój czas by mi pomóc.
>
> Poniżej przesyłam kod.
> To NIE JEST użyteczna aplikacja tylko program testujący :-)
>

Trochę teorii:

Są dwie metody komunikacji.

1) klient - serwer - klient
Ta metoda jest najpopularniejsza. Wymaga działającego serwera w 
internecie. Każdy klient komunikuje się tylko z serwerem, a serwer 
rozsyła dane jednego klienta do innych.

Co do twojego "serwera do zdjęć i ftp", to może się nie nadawać. Tzn 
żeby działał jako serwer aplikacji, musiał byś mieć dostęp do 
programowania na nim. Np. możliwość umieszczania servletów Javy, albo 
chociaż strony WWW z PHP. Oczywiście kod serwera jest zupełnie różny od 
kodu klientów ;-)


2) peer - to - peer
Wtedy każda aplikacja Androidowa jest równocześnie serwerem i klientem. 
Zaleta że nie wymaga serwera, wada że trudniej zestawić połączenie. 
Użytkownicy raczej nie będą wpisywać numerów IP, tym bardziej że 
aktualne IP może się zmieniać. Można to rozwiązać np. wysyłając 
"broadcasty", ale to działa tylko w aktualnej domenie rozgłoszeniowej, 
czyli w tym wypadku w aktualnej sieci WiFi.


Są też metody hybrydowe, np używa się serwera w internecie do 
zestawiania połączeń, przebijania NATów, etc, a potem realna transmisja 
jest już peer-to-peer.


Zobacz jeszcze komentarze w kodzie.

>     @Override
>     protected void onCreate(Bundle savedInstanceState) {
>         super.onCreate(savedInstanceState);
>         setContentView(R.layout.activity_main);
>
>         tvWyswietl = (TextView) findViewById(R.id.tvTresc);
>         etNapisz = (EditText) findViewById(R.id.etZdanie);
>         bStworz = (Button) findViewById(R.id.bStworz);
>         bPolacz = (Button) findViewById(R.id.bPolacz);
>         bWyslij = (Button) findViewById(R.id.bWyslij);
>
>         bStworz.setOnClickListener(this);
>         bPolacz.setOnClickListener(this);
>         bWyslij.setOnClickListener(this);
>
>         serwer = new Serwer(tvWyswietl,etNapisz);
>         klient = new Klient("127.0.0.1");

Na pewno "127.0.0.1"? ten adres zawsze oznacza połączenie do samego 
siebie. Zauważ że każdy AVD czy działające urządzenie to osobny 
komputer, i dla każdego z nich "127.0.0.1" oznacza "ja".

Żeby połączyć się z innym AVD musisz znać jego IP, tak jak ono wygląda z 
aktualnego AVD. A najprawdopodobniej go nie ma, ponieważ każdy AVD jest 
połączony z hostem poprzez NAT.

Tu masz rozwiązanie problemu:
http://stackoverflow.com/questions/4683854/connecting-2-emulator-instances-in-android/4738690#4738690


>     @Override
>     public void onClick(View v) {
>
>         switch (v.getId()) {
>         case R.id.bStworz:
>             serwer.startRunning();
>             //tvWyswietl.setText("start running");
>             break;
>         case R.id.bPolacz:
>
>             break;
>         case R.id.bWyslij:
>
>             break;
>         }
[...]
>     // ustanowienie i uruchomienie serwera
>     public void startRunning() {
>         try {
>             tvTresc.append("\npróba \n");
>             server = new ServerSocket(6789, 100);
>             tvTresc.append("Serwer : " + String.valueOf(server));
>             while (true) {
>                 tvTresc.append("próba 2");
>                 try {
>
>                     waitForConnection();
>                     setupStreams();
>                     whileChatting();
>                 } catch (EOFException eofException) {
>                     showMessage("\n Server zakończył połączenie");
>                 } finally {
>                     closeCrap();
>                     tvTresc.setText("próba 3");
>                 }
>             }

Tu uruchamiasz nieskończoną pętlę, a chwilę wcześniej wołasz 
startRunning() z wątku GUI... To przepis na powieszenie aplikacji.
Zrestą whileChatting() też zawiera niekończoną pętlę, ergo blokujesz 
pętlę w startRunning() dopóki klient się nie rozłączy...

Generalnie pętla serwera powinna działać w osobnym wątku. startRunning() 
powinno tylko uruchamiać ten wątek, i od razu zwracać kontrolę. A sam 
serwer powinien uruchamiać nowy wątek dla każdego podłączonego klienta. 
Wtedy pętle na socketach nie będą blokować nic innego.

I oczywiście z wątków komunikacji sieciowej nie wolno Ci odwoływać się 
bezpośrednio do GUI, musisz to robić poprzez odpowiedni mechanizm 
przesyłana komunikatów ( klasa Handler() ).


Osobiście radził bym Ci zrobić do komunikacji sieciowej osobną usługę 
(obiekt Service), żeby połączenia nie były zależne od aktualnego Activity.


Sporo nauki przed Tobą ;-)

-- 
Arivald
Re: "Usieciowienie" gier
#153867
Author: Piotr Rezmer
Date: Wed, 25 Sep 2013 17:19
19 lines
1677 bytes
TheGuru pisze:

> Komunikację wyobrażam to sobie jak w np GG. Pierwszy zawodnik wykonuje
> ruch i w formie krótkiego stringa wysyłam informację np 10050906 co by
> znaczyło że z pola 10:5 wykonuje ruch na pole 9:6.

Z tego co widzę to dojrzałe gry online na tablety korzystają mocno z 
mechanizmów transakcji. Jest to zauważalne na słabszych sprzętach lub 
wolnych maszynach wirtualnych. Tam często zdarza się rollback (np. ubywa 
Ci punktów jeśli aplikacja się nie wyrobi z synchronizacją z głównym 
serwerem gry.
Dodatkowo, wykorzystywane jest zapamiętywanie operacji które mają być 
zsynchronizowane. Np. zamykasz grę w trakcie wykonywania synchronizacji, 
przy ponownym jej uruchomieniu synchronizacja jest uzupełniana.

-- 
pozdrawiam
Piotr
XLR250&bmw_f650_dakar
Thread Navigation

This is a paginated view of messages in the thread with full content displayed inline.

Messages are displayed in chronological order, with the original post highlighted in green.

Use pagination controls to navigate through all messages in large threads.

Back to All Threads