Komunikator w C#
Autor:
Marcin Hałaczkiewicz
Opublikowano:
27 czerwca 2006
Odsłon:
124 216
Dzisiaj pokażemy jak napisać prosty komunikatorek internetowy (coś jak
Gadu-Gadu). Będzie on działał zgodnie z zasadą klient - serwer. Do komunikacji
pomiędzy jednym a drugim użyjemy protokółu TCP/IP. W programie tym wykorzystamy
nowość w .NET 2.0 - kontrolkę BackgroundWorker. Właśnie ona (a dokładniej dwie)
będzie odpowiedzialna za nawiązanie połączenia z drugim komputerem oraz za
odbieranie komunikatów. Będziemy się nią posługiwać, ponieważ ważne jest, aby
komunikacja odbywała się w tle.
Serwer
Standardowo zaczniemy od utworzenia nowego projektu. Nazwijmy go Serwer.
Zmieńmy również nazwę pliku Form1.cs na Serwer.cs. Następnie klikamy w naszą
formę i zerkamy do okna Properties. Ustawiamy pole Name na
frmSerwer, AutoSizeMode zmieniamy na GrowAndShrink - dzięki
temu nie będzie można zmienić rozmiarów formy. Jeszcze tylko zmieniamy wartość
MaximizeBox na false, żeby nie można było zmaksymalizować okna. W
polu Text wpiszmy jeszcze Serwer.
Następnie tworzymy 3 kontrolki RichTextBox i nazywamy je kolejno
txtOdbieranie, txtWysyłanie i txtLog. Dodatkowo dla
txtOdbieranie i txtLog ustawiamy właściwość ReadOnly na true - nie
będziemy tam nic pisać, a jedynie odczytywać. Tworzymy również 2 etykiety. Jedna
ma pokazywać Nr portu, a druga Log. Potrzebujemy jeszcze dwóch
przycisków i kontrolkę TextBox. Buttony nazywamy cmdSluchaj i
cmdWyslij. Tekst w nich to odpowiednio Czekaj na połączenie i
Wyślij. Dla cmdWyslij ustawiamy jeszcze Enabled na false, aby
po starcie programu przycisk był nieaktywny. Textboxa nazywamy txtPort i
wpisujemy do środka (właściwość Text) 8000 - z takiego portu będziemy
domyślnie korzystali. Teraz wszystko odpowiednio układamy. Powinno to wyglądać
mniej więcej tak (górne pole tekstowe to Odbieranie):

Teraz dodajmy do naszego projektu nowy plik: komunikaty.cs. Stworzymy
w nim klasy KomunikatySerwera oraz KomunikatyKlienta, które będą
zawierały stałe tekstowe, za pomocą których serwer i klient będą się
porozumiewać. Oto treść pliku:
namespace komunikaty
{
public class KomunikatySerwera
{
public const string OK = "###__OK";
public const string Cancel = "###__Cancel";
public const string Rozlacz = "###__Rozlacz";
}
public class KomunikatyKlienta
{
public const string Zadaj =
"###__Zadaj";
public const string Rozlacz = "###__Rozlacz";
}
}
Zanim przejdziemy do dalszej pracy przejdźmy do widoku kodu naszej formy i
dodajmy kilka using... , dzięki którym będziemy mogli korzystać z
protokołu sieciowego. U
góry dopiszmy:
using System.Net;
using System.Net.Sockets;
using System.IO;
using komunikaty;
Do klasy frmSerwer dodajmy następującą funkcję:
public void wyswietl(RichTextBox o, string tekst)
{
o.Focus();
o.AppendText(tekst);
o.ScrollToCaret();
txtWysylane.Focus();
}
Będzie ona dodawać tekst tekst do okna tekstowego o oraz zadba
o autoscrool okna. Dodajmy jeszcze pola:
private TcpListener listener = null;
private TcpClient klient = null;
private bool czypolaczono = false;
private BinaryReader r = null;
private BinaryWriter w = null;
Będą one kolejno reprezentowały nasłuchiwanie połączenia, klienta (drugi
komputer), czypolaczono chyba nie trzeba tłumaczyć ;). r i w
posłużą do zapisywania i czytania danych ze strumienia sieciowego.
Teraz stwórzmy kontrolkę BackgroundWorker i nazwijmy ją Polaczenie.
Klikamy w nią 2 razy (będzie widoczna u dołu ekranu), aby dodać obsługę
zdarzenia DoWork. Będzie się ono uaktywniać, gdy uruchomimy kontrolkę za
pomocą polecenia RunWorkerAsync(). Na początek wpiszmy tam:
wyswietl(txtLog, "Czekam na połaczenie\n" );
listener = new TcpListener(int.Parse(txtPort.Text));
listener.Start();
while ( !listener.Pending() )
{
if (this.polaczenie.CancellationPending)
{
if (klient != null) klient.Close();
listener.Stop();
czypolaczono = false;
cmdSluchaj.Text = "Czekaj na
połączenie";
return;
}
}
Pętla przestanie się wykonywać, gdy klient zażąda połączenia lub użytkownik
przerwie operację. Teraz dodajmy następujący kod:
klient = listener.AcceptTcpClient();
wyswietl(txtLog, "Zażądano połączenia\n" );
w = new BinaryWriter(stream);
r = new BinaryReader(stream);
if (r.ReadString() == KomunikatyKlienta.Zadaj)
{
w.Write(KomunikatySerwera.OK);
wyswietl(txtLog, "Połączono\n" );
czypolaczono = true;
cmdWyslij.Enabled = true;
Odbieranie.RunWorkerAsync();
}
else
{
wyswietl(txtLog, "Klient odrzucony\nRozlaczono\n" );
if (klient != null) klient.Close();
listener.Stop();
czypolaczono = false;
}
Tutaj akceptujemy klienta i odczytujemy dane przez niego wysyłane. Jeśli jest
to komunikat klienta Zadaj - akceptujemy połączenie i uruchamiamy
kontrolkę Odbieranie (zaraz ją stworzymy), która również należy do klasy
BackgroundWorker. Jeśli klient nadesłał inny komunikat - odrzucamy go i
zamykamy połączenie.
Przejdźmy do kontrolki Odbieranie. Tworzymy ją i nadajemy odpowiednią
nazwę, a następnie klikamy na niej 2 razy. We wnętrzu funkcji, która nam się
ukaże wpisujemy:
string tekst;
while ((tekst = r.ReadString()) != KomunikatyKlienta.Rozlacz)
{
wyswietl(txtOtrzymywane, "===== Rozmówca =====\n" + tekst + '\n' );
}
wyswietl(txtLog, "Rozlaczono\n" );
czypolaczono = false;
klient.Close();
listener.Stop();
cmdSluchaj.Text = "Czekaj na połączenie";
Odbieranie będzie zajmować się odbieraniem komunikatów od klienta oraz
wyświetlaniem ich w odpowiednim oknie. Zakończy swoją pracę, gdy otrzyma
komunikat Rozłącz. Zmieńmy jeszcze właściwość
WorkerSupportsCancellation na true, aby można było przerwać pracę
kontrolki. To samo zróbmy dla Polaczenie. Stwórzmy teraz obsługę zdarzenia naciśnięcia przycisku
cmdWyslij klikając go dwa razy. Wewnątrz wpiszmy:
string tekst = txtWysylane.Text;
if (tekst == "") { txtWysylane.Focus(); return; }
if (tekst[tekst.Length - 1] == '\n')
tekst = tekst.TrimEnd('\n');
w.Write(tekst);
wyswietl(txtOtrzymywane, "===== Ja =====\n" + tekst + '\n');
txtWysylane.Text = "";
Po naciśnięciu tego klawisza wpisany przez nas tekst zostanie przesłany przez
sieć. Ponadto zostanie z niego usunięty ostatni znak '\n', aby nie było pustych
miejsc gdy będziemy używać klawisza enter zamiast przycisku. Takiej możliwości
jeszcze nie ma, ale zaraz ją dodamy. W tym celu tworzymy obsługę zdarzenia
KeyPress dla pola tekstowego txtWysylane. Wewnątrz funkcji wpisujemy:
if ( cmdWyslij.Enabled && e.KeyChar == (char)13 ) cmdWyslij_Click(sender, e);
Jeśli przycisk do wysyłania jest aktywny i został wciśnięty enter, to
zostanie wywołana funkcja naciśnięcia klawisza cmdWyslij. Następnie
klikamy 2 razy w cmdSluchaj i wewnątrz funkcji obsługi zdarzenia wpisujemy:
if (cmdSluchaj.Text == "Czekaj na połączenie")
{
Polaczenie.RunWorkerAsync();
cmdSluchaj.Text = "Rozłącz";
}
else
{
if (czypolaczono)
{
w.Write(KomunikatySerwera.Rozlacz);
listener.Stop();
if (klient != null) klient.Close();
czypolaczono = false;
}
wyswietl(txtLog, "Rozlaczono\n");
cmdSluchaj.Text = "Czekaj na połączenie";
cmdWyslij.Enabled = false;
Polaczenie.CancelAsync();
Odbieranie.CancelAsync();
}
Jeśli na przycisku jest napisane "Czekaj na połączenie", to funkcja uruchomi
kontrolkę Polaczenie, która rozpocznie nasłuch. Jeśli zaś napis na
buttonie to "Rozłącz" - połączenie zostanie przerwane (o ile jakieś było).
Anulowana zostanie również praca kontrolek Polaczenie i Odbieranie.
Ponadto na przycisku zmieni się napis tak, abyśmy po naciśnięciu "Czekaj na
połączenie" mieli możliwość przerwania operacji i rozłączenia się (napis
"Rozłącz"), na podstawie tego właśnie napisu przycisk odróżnia, którą z operacji
ma wykonać.
Na końcu dodajemy jeszcze zdarzenie FormClosed dla naszej formy i
wpisujemy kod:
if (czypolaczono)
{
w.Write(KomunikatySerwera.Rozlacz);
listener.Stop();
if (klient != null) klient.Close();
czypolaczono = false;
}
Polaczenie.CancelAsync();
Odbieranie.CancelAsync();
Jego zadaniem jest wysłanie klientowi komunikatu, że się rozłączamy, a
następnie zamknięcie połączenia. Kod ten będzie wywoływany przy zamykaniu
programu (formy). No i serwer mamy gotowy zajmijmy się teraz klientem.
Klient
Zaczniemy oczywiście od stworzenia nowego projektu, nadajemy mu nazwę
Klient. Dodajemy nowy plik komunikaty.cs, którego zawartość ma być
taka sama jak w serwerze. Zmieniamy nazwę pliku Form1.cs na Klient.cs.
Formę nazywamy frmKlient, każemy jej wyświetlać (pole Text)
Klient. Pozostałe właściwości ustawiamy tak samo jak w serwerze (również
rozmiar). Następnie
zaznaczamy wszystkie kontrolki wewnątrz formy w serwerze, kopiujemy je i
wklejamy do klienta. Teraz musimy wprowadzić parę zmian. Nazwę przycisku
cmdSluchaj zmieniamy na cmdPolacz i wyświetlamy w środku Połącz.
Tworzymy dodatkową etykietę - Adres IP oraz pole TextBox -
txtIP. Teraz trochę przestawiamy elementy, aby okno programu wyglądało mniej
więcej tak:

Do naszej formy dodajemy te same pola co w serwerze, ale bez listener,
czyli klient, czypolaczono, r, w oraz funkcję
wyswietl. Na górze pliku dodajemy również te same using... co w serwerze.
Kopiujemy jeszcze z serwera kontrolki Polaczenie i Odbieranie.
Klikamy 2 razy na Polaczenie i wewnątrz obsługi zdarzenia DoWork
wpisujemy:
klient = new TcpClient();
wyswietl(txtLog, "Próbuje się połączyć\n");
klient.Connect(IPAddress.Parse(txtIP.Text), int.Parse(txtPort.Text));
wyswietl(txtLog, "Połączenie nawiązane\nŻądam zezwolenia\n");
NetworkStream stream = klient.GetStream();
w = new BinaryWriter(stream);
r = new BinaryReader(stream);
w.Write(KomunikatyKlienta.Zadaj);
if (r.ReadString() == KomunikatySerwera.OK)
{
wyswietl(txtLog,"Połączono\n");
czypolaczono = true;
cmdWyslij.Enabled = true;
Odbieranie.RunWorkerAsync();
}
else
{
wyswietl(txtLog, "Brak odpowiedzi\nRozlaczono\n");
czypolaczono = false;
if (klient != null) klient.Close();
cmdWyslij.Enabled = false;
cmdPolacz.Text = "Połącz";
}
Funkcja ta próbuje się połączyć z serwerem o określonym IP i na określonym
porcie. Jeśli to się uda, wysyła żądanie połączenia i jeśli otrzyma odpowiedź,
potwierdza nawiązanie łączności i uruchamia Odbieranie. Zajmijmy się
teraz odbieraniem. Klikamy 2 razy na odpowiednią kontrolkę i wpisujemy:
string tekst;
while ((tekst = r.ReadString()) != KomunikatySerwera.Rozlacz)
{
wyswietl(txtOtrzymywane, "===== Rozmówca =====\n" + tekst +
'\n');
}
cmdWyslij.Enabled = false;
wyswietl(txtLog, "Rozlaczono\n");
cmdPolacz.Text = "Połącz";
czypolaczono = false;
if (klient != null) klient.Close();
Funkcja ta zajmuje się dokładnie tym samym co jej odpowiednik w serwerze.
Dodajemy teraz obsługę kliknięcia w cmdWyslij oraz zdarzenia KeyPress
dla kontrolki txtWysylane. Będą one dokładnie takie same jak w serwerze,
więc zawartość funkcji możemy skopiować. Pozostał nam jeszcze przycisk
cmpPolacz. Standardowo podwójne kliknięcie, a następnie kod:
if (cmdPolacz.Text == "Połącz")
{
Polaczenie.RunWorkerAsync();
cmdPolacz.Text = "Rozłącz";
}
else
{
if (czypolaczono)
{
w.Write(KomunikatyKlienta.Rozlacz);
klient.Close();
czypolaczono = false;
}
cmdPolacz.Text = "Połącz";
cmdWyslij.Enabled = false;
wyswietl(txtLog, "Rozlaczono\n");
}
Jeśli na przycisku będzie napisane Połącz - zostanie uruchomione
Polaczenie. W przeciwnym wypadku (napis Rozłącz) - połączenie
zostanie zerwane. Zostało już ostatnie zdarzenie - FormClosed dla naszej
formy frmKlient. Tworzymy je i wpisujemy:
if (czypolaczono)
{
w.Write(KomunikatyKlienta.Rozlacz);
klient.Close();
czypolaczono = false;
}
Polaczenie.CancelAsync();
Odbieranie.CancelAsync();
Kod ten dopilnowuje, aby po zamknięciu formy połączenie zostało przerwane. I oto mamy gotowy program. Możemy się oddać jego używaniu. Należy pamiętać,
że po stronie serwera musi być odblokowany odpowiedni port w firewallu Windowsa
(lub innym, jeśli takiego używamy).
Stworzony tutaj program wraz z plikami źródłowymi możemy pobrać stąd.
Komentarze
naprawde dobry artykul i dobre wprowadzenie do BackgroundWorker, ja kiedys probowalem napisac komunikator gg na watkach ale mialem duze problemy z ich synchronizacja
przydalaby sie jakas darmowa wersja opensource komponentu takiego jak GGdotNet.GGLite 2 (http://www.mksoft.pl/GGdotNet2/), moze zna ktos taka?
Zibi,
1 lipca 2006, 22:35
Także szukałem takiego komponentu lecz nie znalazłem nic oprócz powyższego, za to znalazłem opis protokołu gg, bardzo przydatne przy tworzeniu aplikacji symulującej gg. Oto adres http://dev.null.pl/ekg/docs/protocol.html
BadRay,
4 lipca 2006, 20:27
wydaje mi się, że podczas próby kompilacji projektu (Visula C# EE)powinien wystąpić błąd przy użyciu funkcji "wyswetl" w osobnym watku (w metodzie DoWork komponentu BackgroundWorker). Do kontrolek znajdujacych sie na formie nie powinno się odwoływać z innego wątku w sposób jawny. Może coś przeoczyłem, ale chyba autor nie pisze tego wprost.
Pozdrawiam
bigman,
6 lipca 2006, 17:00
w metodzie Polaczenie_DoWork
brakuje linijki
NetworkStream stream = klient.GetStream();
jest tylko w źródłach
fanatari,
10 lipca 2006, 11:22
Fajnie szkoda tylko że komunikator nie działa... :(
maciek,
18 maja 2007, 13:34
Jak zrobić, by serwer obsługiwał połączenia z kilku klientów?
Bo mi za żadne skarby nie chce się to udać :/
rytek,
21 maja 2007, 17:23
a czy ktos probowal pisac komunikator w ktorym mozliwe byloby polaczenie klient-klient? ja utknelam na tym ;/
gosc,
10 czerwca 2007, 00:58
Możecie mi mailem wyslac kody programu?mój mail to 09.ii.aakp2@gmail.com
:/,
14 sierpnia 2007, 14:45
Mi również są potrzebne te kody. krzychoster@gmail.com
krzycho,
14 sierpnia 2007, 16:52
widze ze sezon zaliczen na uczelniach w pelni ....
mivos,
18 października 2007, 13:34
hmm a ja cos nie rozumiem tego programu pisze w c komunikator ala GG ale niechce mi zadzilac laczenie miedzy klientami ma ktos moze taki program ??
adriannek ,
13 listopada 2007, 21:32
Szkoda że nie działa.... zna ktoś morze sposób aby do serwera mogło sie podpiąć kilka klientów ?? , oraz rzeby morzna było urzywać własnej nazwy??
Jak ktoś wie to prosze o e-maila z informacją jak to zrobić... patryk9200@op.pl oraz GG:10108383
patryk9200,
14 listopada 2007, 22:06
Jak napisać komunikator z wieloma klijentami itp. polecam http://cyfbar.republika.pl/kurs5.html
patryk g,
14 listopada 2007, 23:32
Czy ktoś wie jaki skrypt uzyc lub jak napisac aby mozna bylo dodac do wlasnego komunikatora rozmowy glosowe?? Bardzo mi na tym zalezy... Z gory dziekuje moj mail bartek996@wp.pl
Bartek,
17 listopada 2007, 14:27
Potrzebuje napisać komunikator internetowy - czat w c# Znalazlem ciekawy projekt w C++ http://cyfbar.republika.pl/kurs5.html ale z pewnością , aby wykoać to w C# będzie trzeba uzyć BackgroundWorker. czy ktoś dysponuje podobnymi programami ?? Będę wdzięczny za każdą pomoc lub zlece wykonanie projektu. Proszę o kontakt pod gg : 2026806 lub email: proweb@o2.pl Całość ważna do końca tygodnia
Michał,
26 listopada 2007, 19:44
Ten komunikator jest super oczywiscie po drobnych poprawkach...
Sonics,
18 stycznia 2008, 15:40
jak się robi te kontrolki RichTextBox?????
sławek ,
12 lutego 2008, 14:56
Takie pytanko... można taki serwer zrobić w asp.net i odpalić go jako strone www?
ktoś_ekstra,
1 marca 2008, 10:01
jak dodać ten plik komunikator.cs ??
John Doe,
10 marca 2008, 12:55
Byłoby super jak by działało
M.F___,
7 września 2008, 08:52
wszystko pięknie ładnie tylko że w C#2008 EE jest jakiś problem z funkcją wyswitl niby się kompiluje program ale przy próbie połączenia funkcja wyświetl się sypie i zgłasza problem "Nieprawidłowa operacja między wątkami: do formantu "txtLog" uzyskiwany jest dostęp z wątku innego niż wątek, w którym został utworzony." nie wiem skąd nagle tego typu problem
gb83,
10 września 2008, 14:13
Komunikator w pelni sprawny.... nie zapominajcie jednak, ze jest on do komunikacji SIECIOWEJ ;">
Po kilku poprawkach i modyfikacjach nawet fajny programik wychodzi :-)
JA,
15 września 2008, 16:57
zrobilem to co tu pisze ale na wielu kompach to nie dziala todziala jak jest jakas biblioteka ale nie wiem z kad ja wziac :/ prosze o pomoc piszcie na GG 6347525 lub na maila VandziorX@o2.pl z gory dziex
Janekk,
25 września 2008, 14:41
Drogi Jankku,
Sciagnij z internetu .NET FrameWork 2.0, ktorego wymaga c#. Domyslnie Twoj komputer posiada juz wersje 1.2, ale jest stara i nie ma wszystkich bibliotek.
JA,
25 września 2008, 20:28
śmiać mi się chce jak czytam te komentarze, tak jak by same 10cio latki to pisały... (nie twierdze że wszystkie komentarze takie są)
Andrew®,
30 września 2008, 12:52
A ma ktoś pomysła na naprawienie tego kodu? Ja musze zrobić takiego lan czata do jutra do 17.00:)
Damian,
21 października 2008, 00:02
Damian, a co tu naprawiać? :O
Matthias,
29 października 2008, 15:27
Ludzie opamiętajcie się trochę , przecież tu wszystko działa, a mało tego jest jeszcze w miarę dobrze opisane. Nauczcie się może na początek obsługiwać Visual Studio, a później dawać komentarz które powinny coś mądrego wnosić.
Ten co mu dziala :P,
4 listopada 2008, 18:14
Heh, widzicie dużo ludzi myśli że wystarczy VisualStudio zainstalować i wkleić kawałek kodu z neta a będą mieli super wypasiony działający program, i nie będą musieli sie zastanawiać jak on działa.
Komentarze typu
sławek
12 lutego 2008,
14:56
jak się robi te kontrolki RichTextBox?????
to delikatnie mówiąc tragedia
<br />
Ale nie da sie zablokować dostępu do internetu ludziom poprostu leniwym, którzy by najbardziej chyba chcieli żeby im na maila gotowy projekt wysłac i to jeszcze zmieniony według własnych wymagań:/<br />
Byku,
7 grudnia 2008, 17:29
Niby fajny artykulik ale z błędem !
W pliku "Serwer.cs" o tu gdzie podkreślone :
[color=#1e1e1e; font-family: -webkit-monospace; font-size: 11px; line-height: 18px">{<br /> o.Focus();[/color"><br /> o.AppendText(tekst);<br /> o.ScrollToCaret();<br /> txtWysylane.Focus();<br />}
Jeden błąd aplikacja do bani !
Olo,
17 grudnia 2008, 18:43
To troche nie wyszło więc jeszcze raz Błąd jest wlnijce 2 w klasie "frmSerwer
"
Olo jeszcze raz,
17 grudnia 2008, 18:47
dodaj wyjatek do zapory systemu
@,
16 lutego 2009, 13:51
Fakt jest problem z tym wielowatkowym prowadzeniem sprawy, czyli to co zasygnalizowali bigman i gb83. Z tego co sie dotyczalem (choc jeszcze pewien nie jestem, musze pogryzc sprawe), to chodzi o te BackgroundWorkery, ktore dzialaja asynchronicznie. dlatego tez trzeba korzystac z delegatow i statycznej metody Invoke. Bawiac sie troche "na malpe" skonstruowalem nastepujaca metode wyswietl, ktora dziala:
public void wyswietl(RichTextBox o, string tekst)<br /> {<br /> if (InvokeRequired)<br /> {<br /> InvokeGotFocus(o, EventArgs.Empty); //o.Focus();<br /> Invoke(new StringCallback(o.AppendText), tekst); //o.AppendText(tekst);<br /> Invoke(new ScrollCallback(o.ScrollToCaret)); //o.ScrooToCaret<br /> InvokeGotFocus(txtWysylanie, EventArgs.Empty); //txtWysylanie.Focus();<br /> }<br /> }
Ale poki, co jeszcze nie potrafie wytlumaczyc dokladnie co skad sie bierze - zrobilem to troche intuicyjnie w oparciu o milion nieprecyzyjnych artykulow na necie. Jeszcze pogryze problem.
Sokeks,
10 marca 2009, 01:41
To zle wyglada, ale jak skasujecie te <br/>, to macie ta metode. Jakby ktos uczony w pismie (czyli w C#) mogl sie wypowiedziec, to byloby smurfastycznie.
Sokeks,
10 marca 2009, 01:43
No dobra, zgryzlem problem. Wg mnie i mojego kumpla (ktory w przeciwienstwie do mnie, cos tam wie o C#) zaprezentowane tutaj programy moga dzialac i najprawdopodobniej beda dzialac poprawnie po zbuildowaniu do .exe, ale sa tu powazne bledy w sztuce, na co sie bedzie oburzac kompilator (przez tryb debuggingu wyrzuci milion wyjatkow), a w praktyce program moze sie rozjechac przy niesprzyjajacych sytuacjach. Chodzi o fakt dzialania trzech watkow (sam form i 2 BackgroundWorkery).
Sokeks,
12 marca 2009, 01:37
Dlatego tez, potrzebny bedzie:
1. Przerobienie funkcji wyswietl na nastepujaca postac:
delegate void WyswietlInvoker(RichTextBox o, string tekst);public void
wyswietl(RichTextBox o, string tekst){
if(this.InvokeRequired){
this.BeginInvoke(new WyswietlInvoker(wyswietl), new object["> {o, tekst});
return;
}else{
o.Focus();
o.AppendText(tekst);
o.ScrollToCaret();
txtWysylanie.Focus();
}
}
Sokeks,
12 marca 2009, 01:40
2. Stworzenie funkcji do ustawiania kontrolek nastepujacej postaci:
public void delegate SetValueDelegate(Object obj, Object val, Object["> index);
public void SetControlProperty(Control ctrl, String propName, Object val){
System.Reflection.PropertyInfo propInfo = ctrl.getType().GetProperty(propName);
this.BeginInvoke(new SetValueDelegate(propInfo.SetValue), new Object["> {ctrl, val, null});
}
i teraz nalezu wywolywac ta funkcji do ustawiania kontrolek takich jak cmdWyslij, czy cmdSluchaj.
Sokeks,
12 marca 2009, 01:41
Fajnie, dzieki za solucje, ale przydaloby sie umiescic jeszcze pare informacji pomocniczych np:
a) InvokeRequired - sprawdza czy proces wywołujący jest różny od procesu, w którym kontrolka została utworzona. Jeśli tak to zwraca wartość true.
b) BeginInvoke (Delegate) - tworzy się nowy wątek wykonujący daną funkcję przekazana za pomoca delegata.<br /><br /><br />c) BeginInvoke (Delegate, Object[">) - tworzy się nowy wątek wykonujący daną funkcję przekazana za pomoca delegata, ale dodatkowo mozemy przekazac cos za pomoca Object["> np: new object[">{o,tekst}.
<br /><br />dodatkowo polecam jeszcze uzupelnienie lektury<br />https://codeguru.pl/forum-posts-4595-35.aspx<br />msdn.microsoft.com
blacky,
17 marca 2009, 15:05
Jeszcze ciekawostka bo nie wiem czy ktos zauwazyl (strona 2 petla 1):
while ( !listener.Pending() )<br />{<br /> if (this.polaczenie.CancellationPending)<br /> {
.............. <br />jak ta petla dziala w momecie kiedy nasz server juz dziala a jeszcze nikt sie nie polaczyl to aktywnosc procesora wzrasta do 100%.
blacky,
17 marca 2009, 15:25
niekonsekwentnie przygotowany kurs, gdyby nie zrodlo do sciagniecia, nigdy bym sie nie polapal w tych bledach ;)
maras,
4 maja 2009, 08:44
A gdzie jest źródło do ściągnięcia?
lukasz,
9 czerwca 2009, 14:58
nie działa barany, wszystkie te wasze kody są złe
xxx,
9 czerwca 2009, 21:47
wszystko pieknie dziala...
JEDYNA UWAGA KTOREJ NIENAPISALISCIE JEZELI KTOS SAM TO NAPISZE ALBO SKORZYSTA ZE ZRODLA (nie pliki typu .exe) TO PRZY URUCHAMIANIU TRZEBA DAC CTR+F5 (bez debagera a nie samo F5) chodzi o to ze debager wyrzuci pewne wyjatki dotyczace watkow i stad moze "niby niedzialac"
ale mam pare zastrzezen:
1) wogole nieopisana funkcja wyswietl (ze taka jest i trzeba ja dopisac)
2) w serwerze pare bledow
- w tym co opisaliscie brak NetworkStream stream = klient.GetStream();
w funkcji Polaczenie_DoWork
...
wyswietl(txtLog, "Zażądano połączenia\n");
NetworkStream stream = klient.GetStream();//niema na sronce
w = new BinaryWriter(stream);
r = new BinaryReader(stream);
...
- w funkcji cmdSluchaj_Click (w zrodlach) podwojnie napisane:
cmdWyslij.Enabled = false;
ale to szczegol
3)przy uruchomieniu samego klienta bez serwera (lub z ale nieuruchomionym) moim zdaniem powinien sie "rozlanczac" po jakims czasie"
4)przy uruchomieniu najpierw klienta a pozniej serwera niedochodzi do polaczenia a jednak powinno byc jakos to rozwiazane "czasowo z odswierzaniem"
5)jak dla mnie brakuje rowniez wiecej opisow, wytlumaczenia co gdzie jak po co i dlaczego zeby jednak to byl tutorial i mozna bylo sobie ten kodzik jakos przerobic do wlasnych celow
MOZE TO NA TYLE ALE OGOLNIE JEST GIT :)
donixs,
25 czerwca 2009, 12:27
aaa wiedzialem ze o czyms zapomnialem po rozlaczeniu klienta w serwerze dalej "widoczny" jest button wyslij (cmdWyslij_Click.Enabled = true;)a niepowinien co po kliknieciu powoduje blad (w serwerze to dziala ze po rozlaczeniu oba wyslik-klienta i serwera sa "niewidoczne") jesli kogos to niteresuje to w serwerze wystarczy dodac w funkcji Odbieranie_DoWork : po while cmdWyslij.Enabled = false; (tak jak to jest roziwazane u klienta) pewnie stad w zrodlach sie wzielo to podwojenie (co opisalem w pkt.2) )
donixs,
25 czerwca 2009, 12:39
Czy znacie jakiś prosty przykład komunikatora internetowego C# (który działa). Bardzo mi jest potrzebny.
aw22,
26 lipca 2009, 23:26
Nie wiem czy to bedzie mialo dla kogos znaczenie ale zmiana wielkosci litery ma znaczenie <br />while ( !listener.Pending() )<br />{<br /> if (this.polaczenie.CancellationPending)<br /> {<br /> if (klient != null) klient.Close();<br /> listener.Stop();<br /> Chodzi konkretnie o polaczenie w pierwszym BackgroundWorker-erze
Pozdrawiam
bp,
21 sierpnia 2009, 00:30
przeciez ten doskonale dziala... z jednym malym ale -> jezeli masz zewnetrzne ip i postawisz na nim serwer to mozna sie z tym czatem laczyc a jezeli masz ip wew. to zapomnij... dlaczego tak jest to juz nie temat na ten komentarz... (google potega)
donixs,
30 września 2009, 20:23
da ktoś gotowca zrobionego za pomoca tej strony? Żeby inni mogli sobie pozmieniac nazwę i inne bajery? xD
jono,
23 listopada 2009, 14:19
Co to, DONIXS, znaczy "zewnętrzne IP"? Wyjaśnij to, proszę, bo u mnie oba programy dobrze chodzą na jednym komputerze. Nie potrafią, natomiast, skomunikować się, gdy serwer jest na moim, a klient na innym, i w kliencie podaję moje IP. Port jest dobry, bo chodzi w ten sposób inny, podobny, program.
SideC,
7 stycznia 2010, 22:49
Zapomniałem wspomnieć, że kompilator (IDE 2008 Express) nie przyjął:
listener = new TcpListener(int.Parse(txtPort.Text));
więc napisałem:
IPAddress localAddr=IPAddress.Parse("127.0.0.1");
lub
IPAddress localAddr=IPAddress.Parse("tutaj moje IP");
i
listener=new TcpListener(localAddr,int.Parse(textPort.Text));
SideC,
7 stycznia 2010, 23:13
Ma ktoś cały, gotowy projekt? Nic z tego nie rozumiem!?
hmmm,
7 lutego 2010, 09:30
dlaczego podczas nacisniecia przycisku "czekaj na polaczenie" program sie wywala?
otrzymuje komunikat "Nieprawidłowa operacja między wątkami: do formantu "txtLog" uzyskiwany jest dostęp z wątku innego niż wątek, w którym został utworzony."
olekskin1121,
19 lutego 2010, 12:30
olekskin1121 wyjatek pojawia sie dlatego ze nie przekazales Invoke. Zobacz wyzej juz byl poruszany temat.
blacky,
26 lutego 2010, 21:14
Witam wsyztskich.
Nie wiem czy ktoś tu jeszcze zagląda, ale zadam oryginalne pytanie.
Czy jest możliwe napisanie w C# aplikacji typu Server-Client, która działa nir tylko w lokalnej sieci LAN, ale również w sieciach WAN? Aby każdy mnie dobrze zrozumiał nieco przybliżę problem.
Otóż, załóżmy że mam w domu sieć z routerem. Mój kolega z innego miasta również ma taką sieć. Routery to przeciez bramy domyślne każdej z naszych sieci. Czy muszę konstruować wirtualnego LANa (używając np Hamachi) aby się z nim połączyć? Czy jeśt możliwość, żeby klient odpalany u mnie odnalazł serwer odpalany u kolegi z innego miasta?
Z góry dziękuję za wszelkie komentarze ze wskazówkami czy też odpowiedziami.
Pozdrawiam.
pmarek3,
10 września 2010, 12:47
Jeżeli ktoś byłby tak uprzejmy, aby poinformować mnie na maila (pmarek3@wp.pl), że zamieścił komentarz w związku z moim zapytaniem, to już w ogole będzie rewelacyjnie;)
pmarek3,
10 września 2010, 12:54
Nie no.
Pisze cyt: "
Teraz dodajmy do naszego projektu nowy plik: komunikaty.cs. Stworzymy
w nim klasy KomunikatySerwera oraz KomunikatyKlienta, które będą
zawierały stałe tekstowe, za pomocą których serwer i klient
będą się
porozumiewać. Oto treść pliku:"
Ale jaki plik dodajemy ???!!!???
Anonim,
21 marca 2011, 18:07
To można nawet uzyć do stworzenia prostej gry Multiplayer. Jak się dobrze języka naucze to popróbuje.
bingo009,
2 kwietnia 2011, 21:42
Czy komunikator jest tylko do komunikacji LAN?
BeRnI,
28 maja 2011, 18:01
Skoro interesujecie sie kontrolka BackgroundWorker, to moze korzystniej jest wykorzystac takie metody jak: ReportProgress i ProgressChanged. Nie trzeba bawic sie delegatami.
Dzon,
5 listopada 2011, 10:01
Działa to w internecie a nie w lanie ? jak tak to co trzeba zrobić ?
Jarek93pl,
7 grudnia 2011, 15:34