Unit Sockets - Free Pascal

Odpowiedz Nowy wątek
2012-03-09 00:10
0

Może trochę przydługi wstęp będzie ale to mój pierwszy post tutaj i jeszcze nie ogarniam wszystkich zasad tego forum.

Piszę grę dla dwóch osób. Gra turowa i dobrze by było gdyby gracze nie widzieli swoich ruchów więc opcja "hot seats" odpada. Zostaje mi tylko przesyłanie danych przez sieć. Żeby uprościć działanie gry założymy że będą to szachy (oczywiście szachy to nie są, co można wywnioskować chociażby z tego że gracze nie powinni widzieć swoich ruchów).

Mamy mapę podzieloną na pola i pionki na mapie na odpowiednich polach. Pierwszy gracz wykonuje ruch i po zakończeniu ruchu chcę, żeby dane z mapy były przesłane do drugiego gracza, następnie on wykona ruch i uaktualnione dane z mapy były wysłane z powrotem do gracza numer 1.

Wybrałem kompilator FPC i to co chce napisać to jest raczej trolling niż programowanie bo do rysowania używam WinGraph znalezionego na necie a grafika to nic innego jak rysowanie bitmap z 256-bitowego obrazka bmp a nie żadne opengl czy directx. Więc jak już troluje to troluje na całego i tu pojawia się moja prośba: Czy ktoś z forumowiczów był by tak miły i opisał unit Sockets wraz z prostymi krótkimi przykładowymi programami? Jak nawiązać połączenie? Jak przesłać dane? Czy muszę przesyłać tylko stringi czy mogą to być dane typu Byte lub całe tablice? Czy jest limit wielkości przesłanych danych? W internecie tego szukałem ale nie mogłem znaleźć opisu "dla idiotów" z przykładowymi prostymi programami. Bardzo bym był wdzięczy za pomoc.

edytowany 3x, ostatnio: babubabu, 2012-03-09 00:17
jesli, jak sam napisales, jeszcze nie ogarniasz zasad: http://4programmers.net/Forum/Delphi_Pascal/39079-Zanim_cosnapiszesz-_CZYTAJ_TO - cimak 2012-03-09 13:30

Pozostało 580 znaków

2012-03-09 07:14
2012-03-09 15:08
-123
0

Lepszym pomysłem niż użycie dosyć cienkiego sockets, jest użycie Synapse ( http://www.ararat.cz/synapse/doku.php/start i tu http://wiki.lazarus.freepascal.org/Synapse ). Jest ono wieloplatformowe i wspiera wszystko co do sieci normalnym ludziom potrzeba. Jest od niego masa tutków w necie, więc chyba to najlepszy wybór.

Jeżeli mimo wszystko chcesz Sockets to masz tutaj: http://www.freepascal.org/docs-html/rtl/sockets/index.html - powinny gdzieś być przykłady.

@Patryk27, Synapse<>Sockets

Pozostało 580 znaków

2012-03-09 16:59
0

Uh chyba porwałem się z motyką na słońce... Zobaczę co to to Synapse skoro tak polecacie. W razie jak bym miał jakieś problemy to są tematy na forum odnośnie Synapse bym nie spamował tutaj tylko sobie poczytał?

Pozostało 580 znaków

2012-03-09 17:11
-123
0

Zobaczę co to to Synapse skoro tak polecacie. W razie jak bym miał jakieś problemy to są tematy na forum odnośnie Synapse bym nie spamował tutaj tylko sobie poczytał?

Przecież dałem już link do tutoriala angielskiego całkiem dobrego do Synapse. Skoro nie znasz ang. to nie licz na jakikolwiek lepszy tutorial (chociaż pewnie pare gdzieś jest), a jeżeli znasz ang. to wpisanie hasła w google nie powinno być dla ciebie problemem.

Uh chyba porwałem się z motyką na słońce...

Od czegoś trzeba zacząć zabawę z socketami. Jeżeli będziesz mieć jakieś konkretne problemy śmiało pytaj spróbuję rozjaśnić problemy z synapse (chociaż za eksperta w tej sprawie się nie uważam). Tylko oczywiście musisz conieco wiedzieć o programowaniu i wykazać inicjatywę w postaci przeszukania googla i poeksperymentowania.

Pare przydatnych linków o synapse:
http://wiki.lazarus.freepascal.org/Synapse - tutek i instalacja pod Lazarusem (warto ściągnąć Lazarusa i go ogarnąć jak się już troche umie kodzić, bo wygląda i działa o niebo lepiej niż IDE FPC a kompilator jest ten sam).
http://synapse.ararat.cz/doc/help/ - Dokumentacja Synapse, osobiście uważam ją za nie specjalnie przydatną, ale czasami warto zajrzeć.
http://www.ararat.cz/synapse/doku.php/public:howto - Tutki o Synapse, bardzo dobrze uczą jeżeli używa się ich do referencji względem dem dołączonych do Synapse.

Pozostało 580 znaków

2012-03-09 20:57
0

Dobra trochę poczytałem i spłodziłem coś takiego:

{$MODE DELPHI}
Program Serwer;
Uses Crt,
     blcksock;
Var
  Server : TTCPBlockSocket;
  Buff   : Byte;

Begin
  ClrScr;

  Write ('Czekanie na połaczenie...');
  Server := TTCPBlockSocket.Create;
  Server.Bind('192.168.0.2', '1234');
  If Server.LastError <> 0 Then
  Begin
    Write ('Błąd: ');
    Writeln (Server.LastErrorDesc);
    ReadKey;
    Halt (Server.LastError);
  end;
  Server.Listen;
  Server.Accept;
  Writeln ('Połączono.');
  Writeln;

  Writeln ('Otrzymane dane:');
  Repeat
    Buff := Server.RecvByte (2000);
    Writeln (Buff);
  Until Buff = 0;
  Writeln;
  Writeln ('Koniec');
  Readkey;
end.
{$MODE DELPHI}
Program Klient;
Uses Crt,
     blcksock;
Var
  Client : TTCPBlockSocket;
  Buff   : Byte;

Begin
  ClrScr;
  Randomize;

  Write ('Łączenie...');
  Client := TTCPBlockSocket.Create;
  Client.Connect('192.168.0.2', '1234');
  If Client.LastError <> 0 Then
  Begin
    Write ('Błąd: ');
    Writeln (Client.LastErrorDesc);
    ReadKey;
    Halt (Client.LastError);
  end;
  Writeln ('Połączono');
  Writeln;

  Writeln ('Wysyłanie');
  Repeat
    Buff := Random (256);
    Writeln (Buff);
    Client.SendByte (Buff);
  until buff = 0;
  Writeln ('Koniec Wysyłania');
  Readkey;
end.

I krótki opis jak to powinno działać oraz jak działa:

  1. Jak powinno działać:

Wiadomo serwer czeka na połączenie, klient próbuje się połączyć. Po połączeniu klient losuje liczby z przedziału od 0 do 255 wypisuje na ekran i wysyła do serwera. Serwer Odbiera liczby i również wypisuje na ekran. Gdy klient wylosuje 0 oba programy kończą pracę.

  1. Jak działa:

Po odpaleniu serwera wyświetla się "Czekanie na połączenie...". No to odpalam klienta. Klient łączy się z serwerem i wypisuje wylosowane liczby ostatnia to "0" i potem następna linijka to "Koniec". A w serwerze (po odpaleniu klienta) wypisuje "Czekanie na połączenie...Połączono", linijka przerwy, "Otrzymane dane:" i po dwóch sekundach (taki timeout) "0" linijka przerwy i "Koniec".

Jakaś interakcja między dwoma programami jest ale albo klient nie wysyła danych, albo serwer ich nie odbiera. Żeby nie było problemów to firewalla i antywirusa wyłączyłem całkowicie bo myślałem, że te programy coś blokują ale to nic nie dało. Wersje FPC mam 2.4.0 a synapse 39 (przynajmniej tak była oznaczona na stronie). Ja coś źle zrobiłem czy za stary kompilator na tą wersje synapse lub lipne synapse?

edytowany 1x, ostatnio: babubabu, 2012-03-09 21:01

Pozostało 580 znaków

2012-03-09 22:15
-123
0

Ja coś źle zrobiłem czy za stary kompilator na tą wersje synapse lub lipne synapse?

Coś skopałeś, nawet wiem co.

Server.Accept; - to zwraca socket za pomocą którego komunikujesz się z klientem. Socket servera służy tylko do odbierania połączeń. Do wysyłania/odbierania danych od klientów służy właśnie ten socket który otrzymujesz z accept (jest on już otwarty,po prostu robisz na nim to co chcesz).

Jeszcze taka mała uwaga: Generalnie niewiele robi się tego typu protokołów gdzie każdy pakiet ma jeden bajt, ja bym spróbował nakodzić coś co wysyła między sobą stringi, byłoby bardziej życiowe :) . Ale też trudniejsze, więc jak na pierwszy raz i tak wypadłeś ponadprzeciętnie :P

Pozostało 580 znaków

2012-03-09 22:40
0

Server.Accept; - to zwraca socket za pomocą którego komunikujesz się z klientem. Socket servera służy tylko do odbierania połączeń. Do wysyłania/odbierania danych od klientów służy właśnie ten socket który otrzymujesz z accept (jest on już otwarty,po prostu robisz na nim to co chcesz).

Ok rozumiem. W dokumentacji doczytałem, że accept to jest funkcja i zwraca dane typu TSocket. Wszystko fajnie tylko co mam zrobić z tą wartością? I co to dokładnie jest za wartość? Bo tak jak przeglądam dokumentacje i googluje o synapse to jedyne co zaobserwowałem to wywołanie accept jak procedury bez przypisania wyniku do czegokolwiek. Na tą chwilę jedyne co wymyśliłem to takie cuś:


// program uses itp.
var
  Server : TTCPBlockSocket
  Dane : TTCPBlockSocket

Begin
  // Obsługa socketu Server i ustanowienie połączenia
  Dane := Server.Accept;
  Buff := Dane.RecvByte (2000);
  // Reszta programu
end.

Ewentualnie przed:


Buff := Dane.RecvByte (2000);

Można jeszcze wcisnąć:


Dane := TTCPBlockSocket.Create;

albo jeszcze wcześniej przed accept.

Jednak dzisiaj już późno więc przetestuje to rozwiązanie jutro i podzielę się wynikiem.

Jeszcze taka mała uwaga: Generalnie niewiele robi się tego typu protokołów gdzie każdy pakiet ma jeden bajt, ja bym spróbował nakodzić coś co wysyła między sobą stringi, byłoby bardziej życiowe :) . Ale też trudniejsze, więc jak na pierwszy raz i tak wypadłeś ponadprzeciętnie :P

To co napisałem to tylko próba ogarnięcia i poznania zasady działania synapse, więc wybrałem najprostszą metodę :) Jak zrozumiem o co chodzi to pobawię się stringami bo z tego co pamiętam to w mojej grze będę musiał przesłać około 700 bajtów danych więc robić z tego 700 pakietów jest bez sensu szczególnie, że pakiet może mieć 1kB więc wszystko mogę zmieścić w jednym pakiecie ewentualnie w dwóch, więc jeśli dobrze zrozumiałem to co czytałem o przesyłaniu danych to przesłanie jednego pakietu jest 700 razy szybsze niż przesłanie 700 pakietów :)

edytowany 4x, ostatnio: babubabu, 2012-03-09 23:28

Pozostało 580 znaków

2012-03-09 23:22
-123
0

Bo tak jak przeglądam dokumentacje i googluje o synapse to jedyne co zaobserwowałem to wywołanie accept jak procedury bez przypisania wyniku do czegokolwiek

O to bardzo ciekawe bo to bez sensu jeżeli chcemy coś zrobić z klientem który się do nas podłączył. Pierwszy kod który dałeś jest poprawny, po akceptacji połączenia odbierze on od niego dane. Najlepiej wtedy zamknąć też Socket czekający na połaczenia o ile nie chcesz więcej połączeń.

Jak zrozumiem o co chodzi to pobawię się stringami bo z tego co pamiętam to w mojej grze będę musiał przesłać około 700 bajtów danych więc robić z tego 700 pakietów jest bez sensu szczególnie, że pakiet może mieć 1kB więc wszystko mogę zmieścić w jednym pakiecie ewentualnie w dwóch, więc jeśli dobrze zrozumiałem to co czytałem o przesyłaniu danych to przesłanie jednego pakietu jest 700 razy szybsze niż przesłanie 700 pakietów

Jak się domyślam, to Synapse nie fluszuje tego Od razu, więc robią się grupki tych bajtów, nie chodziło mi o pakiety w rozumieniu czysto TCP.
Czas przesłania pakietu jest generalnie taki sam póki jest on jednoczęściowy (czyli wysyłany na raz), przy czym może on zostać spowolniony jeżeli w danym momencie nie ma jak go wysłać. Generalnie o ile gra nie wymaga tych pakietów superszybko nie musisz się specjalnie martwić o pakiety itd., bo grunt to żeby to wysłać i odebrać.

Pozostało 580 znaków

2012-03-09 23:28
0

Ale jestem z siebie dumny :)


Server.Socket := Server.Accept;

Załatwiło sprawę i wszystko działa :)

Pierwszy kod który dałeś jest poprawny, po akceptacji połączenia odbierze on od niego dane.

I nie jest poprawny :) poczytałem wymyśliłem i działa :)

Przetestuje to teraz na dwóch oddzielnych komputerach. Jak będzie działać to wysyłanie danych z klienta do serwera ogarnięte :) Zostanie tylko wysyłanie z serwera do klienta. A jak to ogarnę to zajmę się stringami :)

@EDIT
Dobra ogarnięte wszystko. Poniżej źródła dwóch programów (serwer,klient). Klient przesyła do serwera to co wpiszemy z klawiatury a serwer to wyświetla.

Serwer:


{$MODE DELPHI}
Program Serwer;
Uses Crt,
     blcksock;
Var
  Server : TTCPBlockSocket;
  Buff   : String;

Begin
  ClrScr;

  Write ('Czekanie na połaczenie...');
  Server := TTCPBlockSocket.Create;
  Server.Bind('192.168.0.2', '1234');
  If Server.LastError <> 0 Then
  Begin
    Write ('Błąd: ');
    Writeln (Server.LastErrorDesc);
    ReadKey;
    Halt (Server.LastError);
  end;
  Server.Listen;
  Server.Socket := Server.Accept;
  Writeln ('Połączono.');
  Writeln;

  Writeln ('Otrzymane dane:');
  Repeat
    Buff := Server.RecvString (10000);
    Writeln (Buff);
  Until buff = '';

Klient:


{$MODE DELPHI}
Program Klient;
Uses Crt,
     blcksock;
Var
  Client : TTCPBlockSocket;
  Buff   : String;

Begin
  ClrScr;

  Write ('Łączenie...');
  Client := TTCPBlockSocket.Create;
  Client.Connect('192.168.0.2', '1234');
  If Client.LastError <> 0 Then
  Begin
    Write ('Błąd: ');
    Writeln (Client.LastErrorDesc);
    ReadKey;
    Halt (Client.LastError);
  end;
  Writeln ('Połączono');
  Writeln;

  Writeln ('Napisz co wysłać (pusta linia zakończy prace programu):');
  Repeat
    Readln (Buff);
    Buff := Buff + CRLF;
    Client.SendString (buff);
  Until buff = ''+CRLF;
end.

Dzięki za pomoc :) Jak bym miał jeszcze jakieś problemy związane z synapse to zapytam tutaj, a jak skończę grę to się pochwalę :)

edytowany 3x, ostatnio: babubabu, 2012-03-10 00:14

Pozostało 580 znaków

2012-03-10 00:16
-123
0

I nie jest poprawny poczytałem wymyśliłem i działa

No właśnie jest, a twój nie...

Ten kod co dałeś to jest piękny przykład że to że działa nie znaczy że jest dobrze. Twój kod powoduje wyciek pamięci na dodatek powoduje on to że port ciągle będzie zbindowany a socket ciągle będzie oczekiwać połączenia.

Weź jakoś tak to napisz jak to ludzie robią:

var
server:TTCPBlockSocket;
server_cl:TSocket;

[...]
server_cl:=server.Accept;
FreeAndNil(server);
[tutaj sobie odbierasz za pomocą server_cl]

Pozostało 580 znaków

Odpowiedz
Liczba odpowiedzi na stronę

1 użytkowników online, w tym zalogowanych: 0, gości: 1, botów: 0