Odbieranie wiadomości - klient

0

Witam. Próbuje zrobić chat i chciałbym, żeby wiadomość do klienta trafiała poprzez pośrednika (Server)
chodzi o to żeby tekst został wyświetalny dopiero gdy server go nadeśle, a nie bezpośrednio poprzez klikniecie buttona.. Mam problem z odebraniem wiadomości od servera dla klienta. Server od klienta wiadomości przyjmuje bez zarzutów. Pomóżcie co zrobić żeby ten klient prawidłowo dostał to wiadomość, bo albo robie coś źle po stronie servera albo klienta...

fragment kodu - SERVER:


        static void ListenClient(object klient)
        {
            Socket myklient = (Socket)klient;
            

            byte[] message = new byte[256];
            int bytesReceive;

            while (true)
            {

                bytesReceive = 0;

                try
                {
                    bytesReceive = myklient.Receive(message);
                }
                catch
                {
                    break;
                }

                if (bytesReceive == 0)
                {
                    Console.WriteLine("Client disconnected");
                    myklient.Close();
                }

                string tekst = Encoding.UTF8.GetString(message, 0, bytesReceive); // przyjmuje
                Console.WriteLine(tekst);
                byte[] SendPacket = Encoding.UTF8.GetBytes(tekst);
                myklient.Send(SendPacket);                                       // a zarazem wysyła do klienta
            }
        }

fragment kodu - Klient:

        private void GetDataServer()
        {
            byte[] message = new byte[256];
            int bytesReceive;

            while (true)
            {

                bytesReceive = 0;

                try
                {
                    bytesReceive = klient.Receive(message);
                }
                catch
                {
                    break;
                }

                string tekst = Encoding.UTF8.GetString(message, 0, bytesReceive); // przyjmuje wiadomosc od servera, nie działa
                rtBox1.Text = tekst;
             }
        }

Tak jak wspomniałem, mam tylko problem z odebraniem wiadomości od servera dla klienta.

0

po pierwsze to w petli while nadpisujesz Text, ale kontroka się nie odmalowuje, wątek GUI jest " jakby zawieszony".
To może być powod dlaczego w rtb nie pojawia się nic.
spróbuj metody rtb.AppendText czy jakoś tak, albo odśwież konrtolkę po zapisaniu. Refresh, albo wywołaj DoEvents();

Aczkolwiek problem moze leżeć gdzie indziej :]

1
while(true) {
string tekst = Encoding.UTF8.GetString(message, 0, bytesReceive); // przyjmuje wiadomosc od servera, nie działa
                rtBox1.Text = tekst;
             }

Czy mi sie wydaje, czy... nawet jeśli coś otrzymasz to natychmiast zniknie, bo nie dopisujesz tylko nadpisujesz.

0

to nadal nie działa, może server w zły sposób wysyła, nie wiem.. Help.

@up to nawet nie raczy pokazać jednej linii tekstu w richtextboxie, no nie wiem jakieś propozycje ?

dodałem + '\n' i nadal nie działa

0

To co pisał MSM, spróbuj dodawać tekst do rtb a nie nadpisywać.
Zamiast Text= cos to Text+= cos.
Aczkolwiek wydało mi się że metoda Receive z socketa blokuje wątek, aż czegoś nie dostanie. Tak więc nie powinno wpisywac spacji.

0

aha ok spróbuje

EDIT: Nie działa, sprawdźcie może kod servera, ale myśle, że jest dobrze.. Eh co tu zrobić ?

1

Swoją drogą nie przewidujesz kończenia programu? Twoja pętla "while true" będzie się wykonywać aż wyskoczy błąd przy pobieraniu danych z serwera. Ciekawy sposób kończenia działania programu, przyznaję.

0

tutaj nie ma co nie działać. Coś musiałeś gdzieś przeoczyc.

CLIENT

        static void Main(string[] args)
        {
            TcpClient client = new TcpClient("79.185.95.222", 6666);
            bool receiving = true;
            byte[] message_bytes = new byte[256];

            client.Client.Send(Encoding.UTF8.GetBytes("Heja!"));
            while (receiving)
            {                
                client.Client.Receive(message_bytes);
                Console.WriteLine(Encoding.UTF8.GetString(message_bytes));
            }
        }

SERVER

static void Main(string[] args)
        {
            TcpListener server_listener = new TcpListener(6666);
            bool listening = true;

            server_listener.Start();
            byte[] message_in_bytes = new byte[256];
            while (listening)
            {
                Socket client = server_listener.AcceptSocket();
                    
                    client.Receive(message_in_bytes);
                    Console.WriteLine(client.AddressFamily.ToString() + ": " + Encoding.UTF8.GetString(message_in_bytes));
                    client.Send(Encoding.UTF8.GetBytes("Ok, przyjąłem"));
            }
        }
1

Podepnę się pod temat w którym sam odpowiadałem kilka minut temu :]

Napisałem sobie kod:

        public void ReadSocketData()
        {
            NetworkStream ns = client.GetStream();

            int readed = 0;
            string buffer = String.Empty;
            int i = 0;

            try
            {
                while (ns.CanRead)
                {
                    byte[] bytes = new byte[MaxPacketSize];
                    readed += i;
                    i = ns.Read(bytes, 0, MaxPacketSize); // -->

                    if (i == -1 || readed >= 64 * 1024) break;

                    if (buffer.Length > 1)
                        if (buffer[buffer.Length - 1] == TerminationString)
                            break;

                    buffer += ASCIIEncoding.ASCII.GetString(bytes, 0, i).Substring(0, i);
                }
            }
            catch (Exception e)
            {
                Console.Write(e.Message); (breakpoint)
            }

            Console.Write(buffer); (breakpoint)

            ns.Close();
        }

I przy trzecim czy czwartym wywołaniu ns.Read() (licznik odczytanych bajtów wynosi 240) jest ZONK. Tzn program dochodzi i odmawia współpracy.
Nie rzuca wyjątku, nie zawiesza się (pracuje w konsoli), NIC nie robi, a podczas debugowania przy naciśnięciu f10 (krok dalej) po prostu nie idzie dalej... nie rozumiem tego :)

Możliwe że nie widzę czegoś oczywistego bo jakoś dzisiaj nie jestem specjalnie do życia ;) Jeśli tak to proszę o uświadomienie mnie.

0

Haha xD Zapomniałem wystartować wątek GetDataServer xD
eh.Start(); i wszystko działa. Głupi mój błąd, ale dzieki za wszystko :)

0

Sory, że doubluje, ale tym sposobem zajrzycie z powrotem do tematu. W jaki sposób mogę serverem mogę wiadomość przysłaną przez jednego klienta wysłać do wszystkich połączonych klientów?

0

No skoro przechowujesz gdzieś podłączonych klientów (jakaś lista czy coś) to możesz po niej iterować, najlepiej z lockiem, i każdemu socketowi wysłać osobno dane.

0
MSM napisał(a)

I przy trzecim czy czwartym wywołaniu ns.Read() (licznik odczytanych bajtów wynosi 240) jest ZONK. Tzn program dochodzi i odmawia współpracy.
Nie rzuca wyjątku, nie zawiesza się (pracuje w konsoli), NIC nie robi, a podczas debugowania przy naciśnięciu f10 (krok dalej) po prostu nie idzie dalej... nie rozumiem tego :)

Read blokuje.
zapewne przeczytał już wszystko, i chce odbierać dalej, ale nic nie ma do odebrania i czeka.
(Miałeś 240 znakow pewnie do odebrania?)
a i jeszcze ns.CanRead nie mowi nam czy jest coś do odebrania. Było chyba coś jak AvaiableData

risen napisał(a)

Sory, że doubluje, ale tym sposobem zajrzycie z powrotem do tematu. W jaki sposób mogę serverem mogę wiadomość przysłaną przez jednego klienta wysłać do wszystkich połączonych klientów?

Nie wiem czy takie coś powinno się robić przez TcpClienta, chociaż nie mówię że się nie da, bo jak najbardziej się da.
Ale jesli to ma być chat to poczytaj o multicastingu, i klasie UdpClient z c#.

Znalazłem takie coś, po polsku w dodatku, może się przyda :)
http://www.codeguru.pl/Articles/13944.aspx

0

ja używam Socketów

Wolałbym zrobić coś takiego jak mówi adsf. Tyle, że w c# nie mozną chyba korzystać z preprocesorów, lub zrobić tablice np. new maxClients[20];

i każda wartość byłaby przypisana na jakiegoś klienta.. Tyle, że w c# się tak nie da.. Chyba.. Sory, ale nie jestem strasznie doświadczony w c#, w każdym razie chciałbym zrobić coś takiego jak "lista klientów".. Ma ktoś pomysł jak zrobić?

0

ze niby tablicy sie nie da zadeklarowac? :O
jeju no podstawy programowania

mozesz zadeklarowac tablice int[] myTab;
oraz mozesz w dowolnym miejscu stworzyc jej instancje myTab = new int[20];
mozesz tez uzyc listy generycznej List<int> myList = new List<int>();
a pozniej dodawac do niej elementy myList.Add(1);
a nastepnie iterowac liste myList.ForEach(x=> ...) lub zwyklym for lub foreach

0

sory, po prostu ja pisałem w języku bardzo podobnym do C, dzieki za podpowiedz z tymi tablicami :)

0

hmmm chyba mam problem.. chciałem zrobić globalną zmienną do zmieniania liczby klientów połączonych.. Cóż, server robie w consoli tyle, że wszystko składa się ze static i nie można do nich używać zmiennych po za ich zasięgem.. To 1 problem. A tera drugi, że nie wiem jak złączyć Socketa z int'em, próbowałem tak:

maxClients += myklient; // maxClients to Int, a myklient to Socket

eh ale wiadome, tak być nie może.. Eh ludziska pomożcie, sam nie moge już wymyśleć jak to zrobić.

Żeby każdego klienta "przylepić" do jednej zmiennej. W późniejszym czasie chcę to zmienną używać w petli, żeby wysłać do wszystkich klientów wiadomość przysłaną od 1 klienta. A ci wszyscy klienci to mają być jako "maxClients".

0

Ja bym Ci radził poczytać samouczki do C#, a potem kilka kodów źródlowych przykładowych aplikacji sieciowych (jest masa).

Nie przylepiasz socketa do inta bo to dwie zupełnie inne klasy C#.
Zrób sobie:

class MojKlient
{
   public Socket MainSocket;
   //inne zmienne jak nick etc
}
List<MojKlient> Klienci = new List<MojKlient>();

A potem jak przyjmujesz klienta to po prostu stwórz nowy obiekt MojKlient, przypisz socketa do zmiennej nowego obiektu i iteruj po liście w razie potrzeby wysłania masowej wiadomości.

0

aha ok, popróbuje

0

No ale co zrobić z tymi static'ami? Nie da się między nimi zmiennymi bawić. Private nie mogę użyć bo zaraz błędy ;/

0

Jakie błędzy, gdzie, przy czym itd. Co chcesz osiągnąć.
Konkrety, najlepiej kod :]

0

Po prostu. Kod zaczyna się od static'a tzw. static void Main(..) i dalej nie idzie zrobić bo reszte też musi być static, jeżeli inaczej to kompilator pokazuje błędy, a tego głównego nie można zamienić na private, sam sprawdź u siebie a zobaczysz o co chodzi..

Jeżeli masz jakąś globalna zmienną to nie można jej użyć w static'u. Tyle i nie idzie pracować..

0

No to jest logiczne przecież.
Ale dalej nie wiem w czym konkretnie masz problem

To co trzeba jest jako static, reszta nie musi.
w static Main mozesz tak samo tworzyć obiekty.

        static class ProgramInterface
        {
            public static List<ServerClient> clients_list = new List<ServerClient>();
        }

        class ServerClient
        {
            private Socket socket=null;

            public ServerClient(Socket socket)
            {
                this.socket = socket;
            }

            public Socket GetSocket()
            {
                return this.socket;
            }
        }

        static void Main(string[] args)
        {
//przykladowo
            ProgramInterface.clients_list.Add(new ServerClient
                (new Socket(new SocketInformation())));
        }

?

0

Ja korzystam z wątków i chciałbym, żeby te wątki były private, a nie static, ale niestety nie mogę tak zrobić ;/ Ta consola zaczyna mnie wkurzać.

A mam prośbę. Mogłbyś mi pokazać przykład, żeby tych klientów wsadzić do Tablicy wymiarowej?

0

ale private to nie jest przeciwieństwo static.
przykładowo protected/internal/public/private to jedna grupa opisujące dostępność pól, metod w klasach.

a modyfikator static służy do tworzenia danych, funkcji, pól dla ktorych nie potrzeba tworzyć instancji danej klasy, aby z nich korzystać.

możesz stworzyć
private static Thread

0

to samo, nie da się globalnych używać, w private static też.

Tak jak wspomniałem wyżej, mógłbyś mi pokazać przykład z wsadzeniem klientów do globalnej tablicy wymiarowej? Sory, ale nie ogarniam za bardzo tego c#, ja się uczę na przykładach, powoli ale wchodzi w tą mózgownicę jakoś.

0

Nie zebym mial zle intencje, ale ty nie ogarniasz generalnie programowania, a rzucasz sie na gleboka wode.

dark_astray podal ci przyklad ze nalezy stworzyc sobie klase do obslugi calej twojej logiki, a w Main stworzyc instancje tej klasy i przekazac do niej sterowanie, np. odpalic jaks metode
(hehe, no moze poszalalem z interpretacja kodu dark_astray'a ale zakladam ze taka byla intencja :D)

zamiast tablicy uzyj listy generycznej System.Collection.Generic.List<T>
zadeklaruj List<MyClient> myList = new List<MyClient>();
teraz mozesz codac sobie obiekt typu MyClient do tej listy uzywajac metody Add: myList.Add(instanceOfClassMyClient);

0

Dokładnie, zreszta było to napisane wcześniej.
Gdy nie wiesz jakiej wielkości tablicę będziesz potrzebował, używaj listy.
Nie ma sensu odkrywać drugi raz Ameryki i budować funkcjonalosc dla Twojej tablicy, jak usuwanie obiektu o indeksie itp. (chyba ze chcesz rozbudować, lub program wymaga takich rzeczy)

a po liście możesz iterować tak jak po tablicy
List<object> lista_obiektow;
lista_obiektow[i]

0

Tablice chce zrobić o wymiarach [20], a każda jej wartość to jeden klient. Tyle, że nie umiem tego dostosować no.. A wy ciągle z tą listą..

Dobra jutro se pogadamy. Schodzę z kompa

0

ServerClient[] tablica_klientow = new ServerClient[20];

po prostu na liście będzie Ci wygodniej;

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