pytanie teoretyczne o GG

0

jak to jest ze GG "wie" ze jakis uzytkownik sie wylaczyl?

  1. niby moglo by byc tak, ze jak ktos wylacza program, to wysyla jeszcze ostatnia informacje do serwera - o wylaczeniu sie. jednak tak nie jest, bo przeca można zabic proces GG.
  2. program moze co sekunde wysylac informacje, ze uzytkownik jest dostepny ale jest to takie rozwiazanie "czy ja wiem?"

jak to w koncu jest?

0

Przeciez TCP gwarantuje ci informacje o zerwaniu polaczenia.

0

co kilka minut gg wysyła do serwera odpowedni pakiet do podtrzymania połączenia jesli go nie dostanie serwer <ort>rozłancza </ort>cie i wysla odpowiedni pakiet do ludzi którzy mają ten numer na liście kontaktów

0
spawacz000 napisał(a)

co kilka minut gg wysyła do serwera odpowedni pakiet do podtrzymania połączenia jesli go nie dostanie serwer rozłancza cie i wysla odpowiedni pakiet do ludzi którzy mają ten numer na liście kontaktów

nie jestem co do tego przekonany, a juz na pewno nie co kilka minut, bo sprawdzalem i te pakiety musialyby byc wysylane jakies 10 razy na sekunde.

a chodzi o to, ze zrobilem komunikator oparty na socketach i zostala mi tylko 1 rzecz: reakcja na rozlaczenie sie uzytkownika. do tego konieczny mi jest numer polaczenia osoby, ktora wlasnie zerwala polaczenie. jedyne co znalazlem to nieprzydatny dla mnie remoteaddress, czyli IP osoby zrywajacej palaczenie. prosze o sugestie.

0

Jak zrobiłeś serwer? Wielowątkowo? Na komponentach? Jak robisz przez systemowe gniazda to przecież bardzo łatwo rozpoznać połączenie.. Nie widzę problemu.

0

program dziala na komponentach. wiesz - podaj kod, prosze

0

To ty podaj. Na jakich komponentach? TCPServer/TCPClient? Indy? Własnych?

0

nie wiem, wydawalo mi sie, ze mowie jasno. uzylem komponentow socket server i socket client (gniazda). moj kod zrodlowy nici nie wyjasni. serwer ma podlaczonych kilka klientow, ktore maja przypisane numery polaczen. potrzebuje tylko kawalek kodu, który by okreslal, jaki numer ma przerwane polaczenie, zeby zmienic status uzytkownika o takim numerze polaczenia na niedostepny.

0

Gniazda to mechanizm systemowy. To nie są bezpośrednio żadne komponenty. To tak jak mówienie: zrobiłem obsługę plików. Dlatego Twój kod wyjaśni bardzo dużo.. Za pomocą jakich komponentów zrealizowałeś ten mechanizm i w jaki sposób go obsługujesz?

Dla przykład w serwerze wielowątkowym opartym WinAPI, każdy klient ma swój wątek, w którym jest pętla jego obsługi. Ten, którego pętla została przerwana (gdy jest oparta na czekaniu na odczyt/zapis), rozłączył się. Gdy zrobisz to na funkcjach WSA, odłączenie klienta przerywa czekanie na jakie interakcję.

Skoro robisz to na komponentach - to też jest ich wiele: różnych, a ich dostępność zależy od wersji Delphi. Nie ma tu jasnowidza, by zgadywać, którego użyłeś.

Być może chodzi Ci po prostu, że zrobiłeś to na TClientSocket/TServerSocket (to dopiero są nazwy komponentów)..

0

od razu Ci mowi, ze ten kod zrodlowy to łajno. zamieszczam cały, bo nie wiem, który kawalek by Ciebie interesował.

unit Unit1;

interface

uses
  Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
  Dialogs, StdCtrls, ScktComp, CoolTrayIcon, TextTrayIcon, Menus;

type
        tuser=record

              pass:string;
              status:byte;
              polaczenie:integer;
              kontakty:array of integer;
              end;


  TForm1 = class(TForm)
    ServerSocket1: TServerSocket;
    Button1: TButton;
    Memo1: TMemo;
    Button2: TButton;
    CoolTrayIcon1: TCoolTrayIcon;
    Edit1: TEdit;
    PopupMenu1: TPopupMenu;
    killservuer1: TMenuItem;
    procedure Button1Click(Sender: TObject);
    procedure ServerSocket1ClientRead(Sender: TObject;
      Socket: TCustomWinSocket);
    procedure ServerSocket1ClientDisconnect(Sender: TObject;
      Socket: TCustomWinSocket);
    procedure ServerSocket1Accept(Sender: TObject;
      Socket: TCustomWinSocket);
    procedure FormCreate(Sender: TObject);
    procedure Button2Click(Sender: TObject);
    procedure CoolTrayIcon1Click(Sender: TObject);
    procedure ServerSocket1ClientError(Sender: TObject;
      Socket: TCustomWinSocket; ErrorEvent: TErrorEvent;
      var ErrorCode: Integer);
    procedure killservuer1Click(Sender: TObject);


  private
    { Private declarations }
  public
    { Public declarations }

  end;

var
  Form1: TForm1;
  users: array [1..200] of tuser;
  F: TextFile;
  numer,i,x:integer;
  wiadomosc,autor:string;
 // h: thandle;
implementation



{$R *.dfm}

procedure TForm1.Button1Click(Sender: TObject);
begin
serversocket1.Port:=strtoint(edit1.text);
Serversocket1.Active:= true;
end;

procedure TForm1.ServerSocket1ClientRead(Sender: TObject;
  Socket: TCustomWinSocket);
begin
wiadomosc:=socket.ReceiveText;

if wiadomosc[length(wiadomosc)]='~' then
        begin
          numer:=strtoint(Copy(wiadomosc, Length(wiadomosc)-3,3));
          setlength(wiadomosc,length(wiadomosc)-4);
          users[numer].polaczenie:=ServerSocket1.Socket.ActiveConnections-1;

          if users[numer].pass=wiadomosc then
             begin
                users[numer].status:=1;
                Memo1.Lines.Add('logowanie numeru '+inttostr(numer));
                memo1.Lines.Add('jego adres to ' + Socket.RemoteAddress);
                memo1.Lines.Add('jego nr polaczenia to '+inttostr(users[numer].polaczenie));
                coolTrayIcon1.ShowBalloonHint('wsconnect server','number '+inttostr(numer)+' logged in',bitInfo, 10);
              end
          else
             begin
                ServerSocket1.Socket.Connections[users[numer].polaczenie].SendText('podales nieprawidlowe haslo, zostaniesz odlaczony');
                ServerSocket1.Socket.Connections[users[numer].polaczenie].Close;
                ServerSocket1.Socket.Connections[users[numer].polaczenie].Free;
             end;
        end
else
    begin
      numer:=strtoint(Copy(wiadomosc, Length(wiadomosc)-2,3));
      setlength(wiadomosc,length(wiadomosc)-3);
      ServerSocket1.Socket.Connections[users[numer].polaczenie].SendText(wiadomosc);
      memo1.Lines.Add('dostalem wiadomosc:'+wiadomosc+' dla nru '+inttostr(numer));
    end;

end;

procedure TForm1.ServerSocket1ClientDisconnect(Sender: TObject;
  Socket: TCustomWinSocket);
begin
memo1.Lines.Add('klient sie rozlaczyl');
end;

procedure TForm1.ServerSocket1Accept(Sender: TObject;
  Socket: TCustomWinSocket);
begin
memo1.Lines.Add('Akceptuje połączenie z: ' + Socket.RemoteAddress);
ServerSocket1.Socket.Connections[ServerSocket1.Socket.ActiveConnections -1].SendText('~~~~');

end;

procedure TForm1.FormCreate(Sender: TObject);
begin
 coolTrayIcon1.ShowBalloonHint('wsconnect servuer','by wojtek seredynski',bitInfo, 10);

 x:= GetWindowLong(Application.Handle, GWL_EXSTYLE);
 x:= x or WS_EX_TOOLWINDOW and not WS_EX_APPWINDOW;
 SetWindowLong(Application.Handle,GWL_EXSTYLE,x);
 memo1.Clear;

  AssignFile(F, 'c:/wsconnect.TXT');
  Reset(F); // otwarcie pliku
  try
    while not Eof(F) do
    begin

       Readln(F, numer, users[numer].pass); // wczytanie 2-óch kolumn

    end;
  finally
    CloseFile(F);
    end;

end;

procedure TForm1.Button2Click(Sender: TObject);
begin
memo1.Clear;
end;

procedure TForm1.CoolTrayIcon1Click(Sender: TObject);
begin
form1.CoolTrayIcon1.ShowMainForm;
end;

procedure TForm1.ServerSocket1ClientError(Sender: TObject;
  Socket: TCustomWinSocket; ErrorEvent: TErrorEvent;
  var ErrorCode: Integer);
begin
ErrorCode:=0;
end;

procedure TForm1.killservuer1Click(Sender: TObject);
begin
form1.Close;
end;

end.
0

No to przeciez masz zdarzenie TForm1.ServerSocket1ClientDisconnect, w parametrze jest parametr Socket reprezentujacy polaczenie, w czy problem? [glowa]

0
Wolverine napisał(a)

No to przeciez masz zdarzenie TForm1.ServerSocket1ClientDisconnect, w parametrze jest parametr Socket reprezentujacy polaczenie, w czy problem? [glowa]

:| no mam, ale to zdarzenie tylko wyswietla w memo linie, ze ktostam sie rozlaczyl, a ja chce wiedziec KTO - czyli w praktyce numer polaczenia tego bylego klienta [!!!]

0

Polecam po podłączeniu klienta jakoś połączyć jego socket z jego identyfikatorem. Na przykład pole Socket.Tag w akceptacji połączenia może przechować numer identyfikacyjny użytkownika - czyli indeks z tablicy Users. Przy rozłączeniu z socketu pobierzesz pole Tag i ze swojej tablicy Users[Socket.Tag] odczytasz, co tam potrzebujesz o danym użytkowniku.

0

Tag to 32 bity, czyli mozesz tam przypisac wszystko co chcesz, wystarczy zmallocowac sobie jakas strukture, wtedy nawet lepiej bo na tablicy zadnej nie trzeba operowac.

0
Szczawik napisał(a)

Polecam po podłączeniu klienta jakoś połączyć jego socket z jego identyfikatorem. Na przykład pole Socket.Tag w akceptacji połączenia może przechować numer identyfikacyjny użytkownika - czyli indeks z tablicy Users. Przy rozłączeniu z socketu pobierzesz pole Tag i ze swojej tablicy Users[Socket.Tag] odczytasz, co tam potrzebujesz o danym użytkowniku.

czyli:

type
        tuser=record
              [...]
              nrsocketa: integer;
              end;

pozniej onaccept:

users[x].nrsocketa:=ServerSocket1.Socket.tag;

no i w koncu jak ktos sie rozlaczy:

procedure TForm1.ServerSocket1ClientDisconnect(Sender: TObject;
  Socket: TCustomWinSocket);
begin

//CO TU POWINNO BYC?

end;
0

Raczej polecam coś innego. Pisane z głowy, ale pokazuje ideę.

Przy OnAccept:

Socket.Tag = 0; //0 czyli jeszcze się nie zalogował

Przy OnClientRead:

if users[numer].pass=wiadomosc then
begin
//..
Socket.Tag := numer;

Przy OnClientDisconnect:

if (Socket.Tag <> 0) then //nie 0, czyli zalogowany
begin
//..
numer:=Socket.Tag;
0

odpowiadam na powyzszy tekst szczawika:

czy dobrze rozumiem; mam do klasy tuser dodac zmienna w ktorej bede przechowywal socket.tag? przy pomyslnym zalogowaniu zmieniam ta wartosc z zera na numer w katalogu kontaktow tego uzytkownika.

wg mnie da mi to tylko mozliwosc sprawdzenia, czy uzytkownik jest zalogowany.

a co ma mi dac to? mozesz uscislic, numer ktorego usera jest rowny socket.tagowi ktorego usera? bo jak dla mnie to wyszlo maslo maslane.

if (Socket.Tag <> 0) then //nie 0, czyli zalogowany
begin
//..
numer:=Socket.Tag;
0
serekk napisał(a)

a co ma mi dac to?

w zmiennej numer będziesz miał numer usera, który się rozłącza, czyli efekt, który od samego początku próbujesz osiągnąć ;)

0

jejku, juz sie zastanawialem czy ktokolwiek widzi cel tej mojej litanii.

chodzi mi o to, zeby uscislic ten powyzszy kod, bo nie jest on na moje oko kompletny

0
Szczawik napisał(a)

Polecam po podłączeniu klienta jakoś połączyć jego socket z jego identyfikatorem. Na przykład pole Socket.Tag w akceptacji połączenia może przechować numer identyfikacyjny użytkownika - czyli indeks z tablicy Users. Przy rozłączeniu z socketu pobierzesz pole Tag i ze swojej tablicy Users[Socket.Tag] odczytasz, co tam potrzebujesz o danym użytkowniku.

sprecyzuje moje pytanie: w jaki sposob mam pobrac pole Tag, o którym mowisz?

mysle, ze rownie dobrze moge pobrac nr polaczenia, tylko nie wiem jak? pisze juz dzisiaj n-ty post i nie znam nadal na to odpowiedzi. potrzebna mi jest 1 linijka kodu, ktora mi to powie.

0

Źle rozumujesz. Nie masz do TUser dodawać żadnego pola! Masz napisane przecież, że to w polu Tag klienckiego socketu masz przechowywać numer TUser'a, który jest z socketem powiązany. Jedyne linie kodu, jakie potrzebujesz, masz w moim poście.

To Ty nie widzisz, co wszyscy chcą Ci tutaj podpowiedzieć..

0

no kurcze, ale jak ktos zabije proces klienta, to od niego nic juz przeciez sie nie wyciagnie.

0

dobra, wiem co masz chyba na mysli. jednak nie ma chyba tak po prostu: socket.tag, bo mi wyskakuje unknow identifier

0

Hmm. to zależy jakim Delphi dysponujesz.

Co do pierwszego tekstu..

Połączenia TCP wyobrażaj sobie tak:

    Serwer                                            Klient

[gniazdo nasłuchujące]       <=======        [gniazdo połączeniowe]
                                                    |
[gniazda każdego klienta]    <----------------------+

Zabicie procesu klienta następuje po stronie klienta - likwidacja gniazda połączeniowego. Wtedy TCP (pisał o tym Wolverine) gwarantuje systemowi serwera powiadomnienie, a ten wykonuje powiadomienie procesu serwera o rozłączeniu gniazda danego klienta. Gniazdo klienta obsługiwane przez serwer jest zaalokowany po stronie serwera. Nie jest tak, że zabijając proces klienta, modyfikujesz pamięć serwera. Za to powiadamiasz go, by wykonał rozłączenie.

Zamiast pola Tag (integer) masz Data (pointer), ale pamiętaj, że pointer i integer mają taki sam rozmiar, więc możesz je wzajemnie, bezstratnie rzutować na siebie.

0

o czym ty gadasz ? pytasz o gg a piszesz cos tam innego.
Jak ci mówie że co kilka minut twoje gg wysyła pakiet do podtrzymania połączenia to tak jest a dokładniej $8. Jeśli ktoś sie rozłączył, zminił status czy opis twoje gg dostaje pakiet $F. Na podstawie tych pakietów i wielu innch widzisz to co widzisz w swoim superowym gg. Tak działa gg, więc mi nie mów, że musi wysyłać 10 razy na sekunde żeby twój shit wiedział, że ktoś sie rozłączył.

0

dzieki Szczawik za szczególowe wyjasnienia.

odpowiedz na post spawacza000:
nie denerwuj sie tak od razu. twoj pierwszy post na moj poczatkujacy rozum, sugeruje, że gadu gadu rozpoznaje czy ktos jest online dzieki jakims tam pakietow i jesli nie otrzyma zwrotnego to zmienia status. co masz na mysli mowiac shit?

0

Powiem tylko tak: do wykrycia tego czy połączenie wciąż trwa nie potrzebujesz żadnego pakietu wysłanego przez program. TCP to gwarantuje. Oczywiście, nikt Ci nie zabroni puścić takiego pakietu. Tylko czy to ma sens?

Istnieje coś takiego jak MTU - Maximum Transmission Unit - maksymalny rozmiar datagramu, jaki możesz puścić po sieci. Jeśli wysyłasz mniej, mimo tego cały datagram o rozmiarze MTU jest puszczany w sieć: wysyłasz 1 bajt, 1492 (domyślnie chyba tyle jest ustawione) idą w sieć; wysyłasz 1492 bajty - też 1492 idą w sieć. Wysyłasz więcej - dane są dzielone na kilka datagramów. Czy to nie jest marnotrawstwo przepustowości - wysłać 1 lub kilka pojedynczych bajtów?

0

oczywiście, że taki pakiet nie jest potrzebny ale tak sobie wymyslili swój protokół. Kto jest zbędny niech nie przeciąża i cyk mu disconnecta np amatorom próbującym napisać własnego klienta.

0

wiedzialem Szczawik, ze twoim kodem jest cos nietak. w zmiennej numer nie bedzie numeru osoby, ktora sie rozlaczyla, tylko numer ostatniej zalogowanej osoby!

0

Wiesz czym jest Socket, który dostajesz jako parametr procki obsługi zdarzenia? Jak nie, to nie masz co się zabierać za pisanie klienta, tylko najpierw poczytaj trochę. Jak wiesz, to zastanów się dwa razy, zanim taką głupotę palniesz.

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