Přenos dat, protokol a dokončení

3. díl - Přenos dat, protokol a dokončení

Tomáš Jecha, MVP, MCSD       26.04.2007       C#, VB.NET, Threading, I/O operace, .NET       13703 zobrazení

Je tu poslední díl tohoto seriálu, kde si konečně ukážeme jak přes TCP protokol komunikovat a jak ho adekvátně použít pro potřeby naší aplikace.

Nepovinné rozšíření

Pokud máte chuť se vrhnout rovnou na komunikaci, můžete tuto kapitolu přeskočit...

Dříve než začneme, dovolím si nabídnout malé rozšíření. Aby naše aplikace uměla něco víc, než jen kreslit bílé čáry, přidáme si funkce na změnu tloušťky a barvy štětce. První rozšíříme menu stejně, jako na vidíte na obrázku:

Po přidání nových položek do menu

Já jsem použil jedno standardní tlačítko na zvolení barvy a jeden ComboBox pro tloušťku štětce - fantazii se však meze nekladou a výběr můžete realizovat jak chcete.

Pokud se budete držet mého konvenčního řešení, vložte si na formulář ColorDialog1 a do tlačítka Zvolit barvu štetce vložte následující kód:

     Private Sub ToolStripMenuItemBarvaStetce_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles ToolStripMenuItemBarvaStetce.Click 
         ' nastavíme dialogu aktuální barvu 
         ColorDialog1.Color = drawColor 
         ' zobrazíme dialog 
         If ColorDialog1.ShowDialog() = Windows.Forms.DialogResult.OK Then 
             ' nová barva kreslení 
             drawColor = ColorDialog1.Color 
         End If 
     End Sub   

Tím máme hotový výběr barvy. Pro zvolení tloušťky použijeme ComboBox pojmenovaný ToolStripComboSirkaStetce. Dáme na výběr z několika přednastavených hodnot, které do něj vložíme v proceduře Form1_Load:

  
         ' přidáme do výběru tloušťky štětce hodnoty 
         For i As Integer = 1 To 10 
             ToolStripComboSirkaStetce.Items.Add(i.ToString + "px") 
         Next 
         ToolStripComboSirkaStetce.SelectedIndex = drawWidth - 1 ' aktuálně vybraná šírka štětce bude defaultní výběr 

Přepisování vložených položek zamezíme nastavením vlastnosti ToolStripComboSirkaStetce.DropDownStyle na DropDownList. Aby se při změně výběru změnila i proměnná drawWidth, přidáme do události SelectedIndexChanged kód:

  
     Private Sub ToolStripComboSirkaStetce_SelectedIndexChanged(ByVal sender As Object, ByVal e As System.EventArgs) Handles ToolStripComboSirkaStetce.SelectedIndexChanged 
         ' byla vybrána nová šířka štetce 
         drawWidth = ToolStripComboSirkaStetce.SelectedIndex + 1 
     End Sub 

To by mělo být vše - barevná kreslící tabule je na světě :)

Tabule s použitím barev

Synchronizace

Asynchronní přijímání

Pokud použijeme asynchronního přijímání, je to pro nás velmi výhodné. V opačném případě bychom museli totiž pořád kontrolovat, zda přišla nějaká data a na to by padla velká část procesorového výkonu. Celou situaci znázorňuje obrázek:

Použití asynchroního čtení

K tomuto účelu budeme mít proceduru CtiData. Její volání vypadá takto:

 networkStream.BeginRead(Buffer, 0, BUFFER_SIZE, AddressOf CtiData, Nothing) ' začínáme asynchronně číst 

Čekat na data potřebujeme od vzniku spojení, vložíme jej tedy do procedur KlientSePripojuje a Pripojit za příkaz, kde přiřazujeme do NetworkStreamu:

             ... 
             networkStream = tcp.GetStream()	' stream pro přenos dat 
             networkStream.BeginRead(Buffer, 0, BUFFER_SIZE, AddressOf CtiData, Nothing) ' začínáme asynchronně číst 
             ... 
 

Asi jste si všimli, že používáme proměnné Buffer pro uložení příchozích dat a BUFFER_SIZE jako definici velikosti bufferu. Jejich deklarace provedeme takto:

     Const BUFFER_SIZE As Integer = 512 ' velikost bufferu 
     Dim Buffer(BUFFER_SIZE) As Byte ' buffer pro příchozí data 

Nastal čas popsat si funkci procedury CtiData, která vypadá následovně:

  
     Sub CtiData(ByVal at As System.IAsyncResult) 
         Try 
             Dim prijato As Integer = networkStream.EndRead(at) ' dokončíme čtení dat a zjistíme kolik dat přišlo 
             If prijato < 1 Then Throw New Exception() ' spojení bylo ukončeno (přichází 0B dat) 
  
             ' >> ZDE BUDE KOD NA ZPRACOVANI PRICHOZICH DAT << 
  
             tcp.GetStream.BeginRead(Buffer, 0, BUFFER_SIZE, AddressOf CtiData, Nothing)          ' přečetli jsme všechny příchozí data, proto budeme čekat až přijdou další 
         Catch e As ObjectDisposedException 
             ' proběhlo zrušení spojení 
         Catch e As Exception 
             MsgBox(e.Message) 
             ' nastala chyba, spojení je ukončeno 
             StripInfo.Text = "Spojení bylo ukončeno" ' informace pro uživatele 
             MsgBox("Spojení ukončeno!", MsgBoxStyle.Information) 
             OdemkniPolozky() ' nakonec odemkneme znovu položky v menu na připojení a vytvoření spojení 
         End Try 
     End Sub 

Příkazem EndRead potvrdíme přijetí dat. Návratová hodnota je počet přijatých bytů. Pokud spojení skončilo, bude rovna nule.

Když se data zpracují, znovu se zavolá BeginRead a vytvoří se tak smyčka, která se provede vždy, když přijdou data.

Tím jsme zvládli přijímání dat. Až do teď byla komunikace dosti obecná, avšak od příští kapitoly se zaměříme přímo na implementaci vlastního protokolu pro kreslící tabuli.

Vše připraveno

Konečně se dostáváme k hlavnímu problému našeho scénáře. Z minulých dílů máme k dispozici uživatelské rozhraní a připravený komunikační kanál NetworkStream odvozený z TCP spojení. Data umíme přijímat, ale protože nejpřijde nic víc, než hromada bytů, musíme data umět nějak interpretovat. K tomu v jakém formátu je posílat a následně jak je dekódovat na druhé straně navrhneme jednoduchý protokol.

Jak navrhnout protokol?

Pro naše účely nám postačí jednoduchý textový prokol. Příkazy budeme oddělovat středníkem a parametry mezerou. Takže například příkaz s dvěma argumenty může vypadat takto:

 příkaz parametr parametr; 
 

Více příkazů pak takhle:

 příkaz parametr1 parametr2;jiný_příkaz parametr;ještě_jiný_příkaz_bez_parametru; 
 

Aby jsme mohli příkazy textově odesílat, napíšeme si proceduru PosliPrikaz:

     Sub PosliPrikaz(ByVal prikaz As String) 
         ' zjistíme, zda jsme připojeni 
         Dim Connected As Boolean = False 
         If Not tcp Is Nothing Then 
             If Not tcp.Client Is Nothing Then 
                 Connected = tcp.Connected 
             End If 
         End If 
         If Connected = False Then Exit Sub ' pokud nejsme ještě připojeni, tak se nic neposíla 
         Try 
             Dim bfr(prikaz.Length - 1) As Byte ' pole presne pro prikaz 
             bfr = System.Text.Encoding.ASCII.GetBytes(prikaz) ' převedeme příkaz na pole bytů 
             networkStream.Write(bfr, 0, bfr.Length) ' odeslat prikaz 
         Catch e As ObjectDisposedException 
             ' proběhlo zrušení spojení 
         Catch ex As Exception 
             StripInfo.Text = "Spojení bylo ukončeno" ' informace pro uživatele 
             tcp.Close() ' chyba - uzavřít spojení 
             MsgBox("Spojení ukončeno!", MsgBoxStyle.Information) 
             OdemkniPolozky() ' nakonec odemkneme znovu položky v menu na připojení a vytvoření spojení 
         End Try 
     End Sub 
  

Když už známe, jak budou příkazy strukturované, můžeme vyplnit prázdné místo v proceduře CtiData.

POZOR: Data přes TCP/IP mohou dorazit po částech nebo naopak více najednou spojených za sebe! Z toho důvodu budeme příchozí byty konvertovat na řetězec a přidávat do proměnné text_buffer. Deklaraci přidáme k ostatním bufferům:

     Const BUFFER_SIZE As Integer = 512 ' velikost bufferu 
     Dim Buffer(BUFFER_SIZE) As Byte	 ' buffer pro příchozí data 
     Dim text_buffer As String ' buffer ze kterého budeme data rovnou číst a odmazávat 

A do CtiData vepíšeme parser na příkazy, který bude odsekávat kompletní příkazy zakončené středníkem a posílat je do funkce ProvedPrikaz(prikaz):

 

             text_buffer += System.Text.Encoding.ASCII.GetString(Buffer, 0, prijato)    ' přidání přijatých dat 
  
             Do While text_buffer.Contains(";") ' dokud máme příkazy, které můžeme parsovat 
                 Dim poziceStredniku As Integer = text_buffer.IndexOf(";") ' najdeme ukončovací znak 
                 Dim prikaz As String = text_buffer.Substring(0, poziceStredniku) ' přečteme příkaz až ke středníku 
                 text_buffer = text_buffer.Substring(poziceStredniku + 1) ' a prikaz odřízneme 
                 ProvedPrikaz(prikaz) ' pošleme příkaz ke zpracování 
             Loop 

Parser máme už hotový, odesílání připravené, už nám jen stačí napsat funkci ProvedPrikaz(prikaz), co bude vyhodnocovat příkazy. Nejdříve si je ale nadefinujeme.

Příkazy protokolu

Nakonec nám budou stačit pouze dva příkazy:

  • smazat; - smaže tabuli
  • cara x1 y1 x2 y2 sirka r g b; - nakreslí čáru

Abychom mohli vykreslovat příkaz čára, napíšeme si novou funkci:

  
     Sub KresliCaru(ByVal x1 As Integer, ByVal y1 As Integer, ByVal x2 As Integer, ByVal y2 As Integer, ByVal drawWidth As Integer, ByVal color As Color) 
         Threading.Monitor.Enter(Me)    ' uzamkneme vlákno 
         grp.FillEllipse(New Pen(color).Brush, New RectangleF(x1 - drawWidth / 2, y1 - drawWidth / 2, drawWidth, drawWidth))    ' vykreslíme prvnotní bod (zakulacení začátku čáry) 
         grp.DrawLine(New Pen(color, drawWidth), x1, y1, x2, y2)    ' vykreslíme čáru 
         grp.FillEllipse(New Pen(color).Brush, New RectangleF(x2 - drawWidth / 2, y2 - drawWidth / 2, drawWidth, drawWidth))    ' vykreslíme zakončovací bod (zakulacení konce čáry) 
         PicTabule.Invalidate() ' nechame překreslit PicTabule 
         Threading.Monitor.Exit(Me) ' odemkneme vlákno 
     End Sub 

Všimněte si, že jsem použil příkazy Threading.Monitor.Enter(Me) a Threading.Monitor.Exit(Me). Ty slouží k uzamčení objektu pro určité vlákno. Pokud použiji Enter na určitý objekt, jiné vlákno to nemůže udělat dokud nepoužiji Exit V tomto případě to bude zabraňovat kolizím v zápisu na objekt grp.

Způsob synchronizace

První, co člověka (resp. programátora) v naší situaci napadne, je posílat vše, co jsme nakreslili tomu druhému a nechat ať to vykreslí i u sebe. Bohužel to tak snadné není.

Představte si situaci, kdy oba najednou nakreslí čáru. Vykreslí ji tedy u sebe a odešlou po síti. A když jim oběma přijde nazpět čára toho druhého, nakreslí se přes jejich původní. Asi takhle:

Chyba při společném kreslení

Naštěští to jde celkem snadným způsobem vyřešit. Všechna data půjdou nejdřív na server a teprve ten je bude posílat zpět společně se svými k vykreslení. Funkci serveru lze pak znázornit takto:

Funkce serveru

Tím pádem bude klient místo vykreslování u sebe vše jen posílat serveru a ten všechnu příchozí komunikaci přesměruje zpět na klienta. Díky tomu bude stejné vykreslovací pořadí i u serveru i u klienta.

Dokončení

Zde je konečně kód, který zpracuje samotný příkaz od parseru:

  
     Sub ProvedPrikaz(ByVal prikaz As String) 
         Try 
             Dim casti As String() = Split(prikaz, " ") ' rozdělíme příkaz podle mezer 
             Select Case casti(0) ' zjistíme druh příkazu 
                 Case "smazat" ' smažeme tabuli 
                     Threading.Monitor.Enter(Me)    ' uzamkneme vlákno 
                     grp.Clear(Color.Black) 
                     PicTabule.Invalidate() 
                     Threading.Monitor.Exit(Me)    ' odemkneme 
                     If Status = StatusPripojeni.Server Then PosliPrikaz(casti(0) + ";") ' server přeposíla zpět klientovi 
                 Case "cara"    ' nakreslí čáru 
                     KresliCaru(Val(casti(1)), Val(casti(2)), Val(casti(3)), Val(casti(4)), _ 
                     Val(casti(5)), _ 
                     Color.FromArgb(Val(casti(6)), Val(casti(7)), Val(casti(8)))) 
                     If Status = StatusPripojeni.Server Then    ' server přeposíla zpět klientovi 
                         PosliPrikaz(casti(0) + " " + casti(1) + " " + casti(2) + " " + casti(3) + " " + casti(4) + " " + casti(5) + " " + casti(6) + " " + casti(7) + " " + casti(8) + ";") 
                     End If 
                 Case Else ' neznámý příkaz, ukončení připojení 
                     Throw New Exception 
             End Select 
         Catch e As Exception  ' chyba při zpracování přikazu, ukončení spojení 
             StripInfo.Text = "Spojení bylo ukončeno" ' informace pro uživatele 
             tcp.Close()    ' uzavřeme spojení' 
             MsgBox("Chybná syntaxe příkazů!", MsgBoxStyle.Information) 
             OdemkniPolozky() ' nakonec odemkneme znovu položky v menu na připojení a vytvoření spojení 
         End Try 
     End Sub 

A teď posílání nakreslených čar. Jako první si vložte funkci, která zjistí jestli jsem klient a tedy jestli nemám vykreslovat, dokud mi to nepřijde od serveru:

  
     Function JsemPripojenyKlient() As Boolean 
         ' zjistíme, zda jsme připojeni 
         Dim Connected As Boolean = False 
         If Not tcp Is Nothing Then 
             If Not tcp.Client Is Nothing Then 
                 Connected = tcp.Connected 
             End If 
         End If 
         Return Connected And (Status = StatusPripojeni.Klient) 
     End Function 

Následuje upravená procedura pro tlačítko mazání tabule:

  
     Private Sub ToolStripMenuItem_SmazatTabuli_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles ToolStripMenuItem_SmazatTabuli.Click 
         If JsemPripojenyKlient() = False Then 
             Threading.Monitor.Enter(Me)    ' uzamkneme vlákno 
             grp.Clear(Color.Black) ' smažeme tabuli 
             PicTabule.Invalidate() ' a překreslíme ji 
             Threading.Monitor.Exit(Me)    ' odemkneme 
         End If 
         PosliPrikaz("smazat;") ' smažeme i u druheho 
     End Sub 
  

A nakonec to nejlepší, upravené procedury pro kreslení čar. Přidal jsem příkaz na odesílání dat a podmínku, která zabrání vykreslování v případě že je aplikace připojena jako klient.

  
     Private Sub PicTabule_MouseDown(ByVal sender As Object, ByVal e As System.Windows.Forms.MouseEventArgs) Handles PicTabule.MouseDown 
         If e.Button = Windows.Forms.MouseButtons.Left Then 
             PosledniBod = e.Location ' počátek kreslení je nyní nastaven jako pozice myši 
             If JsemPripojenyKlient() = False Then 
                 Threading.Monitor.Enter(Me)    ' uzamkneme vlákno 
                 grp.FillEllipse(New Pen(drawColor).Brush, New RectangleF(e.X - drawWidth / 2, e.Y - drawWidth / 2, drawWidth, drawWidth)) ' vykreslíme první bod (zakulacení počátku čáry) 
                 PicTabule.Invalidate() ' necháme překreslit PicTabule 
                 Threading.Monitor.Exit(Me)    ' odemkneme 
             End If 
             Kresleni = True    ' aktivujeme kreslící mód 
             PosliPrikaz("cara " + e.X.ToString + " " + e.Y.ToString + " " + e.X.ToString + " " + e.Y.ToString + " " + drawWidth.ToString + " " + drawColor.R.ToString + " " + drawColor.G.ToString + " " + drawColor.B.ToString + ";") 
         End If 
     End Sub 
  
     Private Sub PicTabule_MouseMove(ByVal sender As Object, ByVal e As System.Windows.Forms.MouseEventArgs) Handles PicTabule.MouseMove 
         If e.Button = Windows.Forms.MouseButtons.Left And Kresleni = True Then 
             If JsemPripojenyKlient() = False Then 
                 Threading.Monitor.Enter(Me)    ' uzamkneme vlákno 
                 grp.DrawLine(New Pen(drawColor, drawWidth), PosledniBod, e.Location) ' vykreslíme čáru z posledního bodu, kde byla myš 
                 grp.FillEllipse(New Pen(drawColor).Brush, New RectangleF(e.X - drawWidth / 2, e.Y - drawWidth / 2, drawWidth, drawWidth)) ' vykreslíme zakončovací bod (zakulacení konce čáry) 
                 PicTabule.Invalidate() ' nechame překreslit PicTabule 
                 Threading.Monitor.Exit(Me)    ' odemkneme 
             End If 
             ' odeslat údaje serveru 
             PosliPrikaz("cara " + PosledniBod.X.ToString + " " + PosledniBod.Y.ToString + " " + e.X.ToString + " " + e.Y.ToString + " " + drawWidth.ToString + " " + drawColor.R.ToString + " " + drawColor.G.ToString + " " + drawColor.B.ToString + ";") 
             PosledniBod = e.Location ' poslední bod, ze kterého se kreslilo je nyní opět aktuální pozice myši 
         End If 
     End Sub 

Finální podoba

Pokud jste to vydrželi až do teď, tak děkuji za pozornost a trpělivost. Doufám, že vám článek něco přinesl. V případě jakýchkoliv dotazů se na mě obraťte v diskuzi.

Výsledný kód je ke stažení zde:

 

hodnocení článku

5 bodů / 5 hlasů       Hodnotit mohou jen registrované uživatelé.

 

Všechny díly tohoto seriálu

3. Přenos dat, protokol a dokončení 26.04.2007
2. Základy TCP spojení, implementace funkcí Připojit a Založit server 26.04.2007
1. Úvod, uživatelské prostředí 26.04.2007

 

 

 

Nový příspěvek

 

Nefunguje

Udělal jsem vše podle návodu a když mi to nefungovalo, tak jsem vytvořil novou aplikaci ,nový form1 naskládal tam vše co tam mělo být a do zdrojového kódu jsem zkopíroval výsledné zdroojové kódy, které byly zdde pod článkem. Aplikace ale nefungovala, přestože jsem na druhý počítač nainstaloval dvě poslední verze .net frameworku. Už jsem v koncích...přesto , co mám napsat jako adresu serveru? Děkuji za každou radu a odpověď.

nahlásit spamnahlásit spam 0 odpovědětodpovědět

Přechod na jiný formulář - prosím pomoc

Dobrý den,

děkuji za tento velmi užitečný přiklad, hlavně co se týká TCP spojení,

použil jsem to u hry na které pracuju.

Potřeboval bych poradit jak udělat když potřebuju přejít na další formulář,

nejlépe aby spojení zůstalo zachováno

(myšleno tak že ten formulář kde je nejprve spojení navázáno potřebuji zavřít a aby se pokračovalo na dalším nově otevřeném formuláři, když jsem ten původní jen skryl a volal procedury na tom původním tak mi to nefungovalo i když jsem je změnil na public)

Pro profíky určitě jednoduchá věc, děkuji předem za pomoc

nahlásit spamnahlásit spam 0 odpovědětodpovědět

Jak zpracovat mnoho rychlých dat

Ahoj.

Řeším situaci, kdy mám zařízení k PC připojené přes LAN a toto zařízení posílá souvislý tok dat. (mnohokrát za vteřinu mi pošle sadu 500 bajtů a vše běží i týden v kuse)

Já potřebuju naprosto všechna data zachytit, zpracovat, rozdělit do menších bloků a uložit na disk.

Mám tedy otázku na metodu CtiData (viz výše). Co se stane s daty, která přijdou v době, kdy zpracovávám ta minulá data? Uloží se do nějakého bufferu a až znovu zalovám BeginRead tak se mi načtou, nebo o ně přijdu? Pokud se ztratí, doporučíte mi něco jiného?

Možná by se tu dal použít pojem Streamování (jako na youtube). Ale nevim, co s tim. Jen mě to teď napadlo.

networkStream.EndRead(at)
             ' >> ZDE BUDE KOD NA ZPRACOVANI PRICHOZICH DAT << 
tcp.GetStream.BeginRead(Buffer, 0, BUFFER_SIZE, AddressOf CtiData, Nothing)
nahlásit spamnahlásit spam 0 odpovědětodpovědět

Diskuse: Přenos dat, protokol a dokončení

Prosim tě jak to mám udělat, když chci aby to bylo pro tři uživatle, nebo i více npříklad pět?

nahlásit spamnahlásit spam 1 / 1 odpovědětodpovědět

huzvzas

nahlásit spamnahlásit spam 0 odpovědětodpovědět

Diskuse: Přenos dat, protokol a dokončení

Jak tohleto napsat v c#:

tcp.GetStream.BeginRead(Buffer, 0, BUFFER_SIZE, AddressOf CtiData, Nothing)

tcp.GetStream.BeginRead() - neexistuje

Díky předem za odpověď.

nahlásit spamnahlásit spam 1 / 1 odpovědětodpovědět

Chtel jsem se zaptat jak celou tuhle funkci zapsat v C#:

Sub CtiData(ByVal at As System.IAsyncResult) 
         Try 
             Dim prijato As Integer = networkStream.EndRead(at) ' dokončíme čtení dat a zjistíme kolik dat přišlo 
             If prijato < 1 Then Throw New Exception() ' spojení bylo ukončeno (přichází 0B dat) 
  
             ' >> ZDE BUDE KOD NA ZPRACOVANI PRICHOZICH DAT << 
  
             tcp.GetStream.BeginRead(Buffer, 0, BUFFER_SIZE, AddressOf CtiData, Nothing)          ' přečetli jsme všechny příchozí data, proto budeme čekat až přijdou další 
         Catch e As ObjectDisposedException 
             ' proběhlo zrušení spojení 
         Catch e As Exception 
             MsgBox(e.Message) 
             ' nastala chyba, spojení je ukončeno 
             StripInfo.Text = "Spojení bylo ukončeno" ' informace pro uživatele 
             MsgBox("Spojení ukončeno!", MsgBoxStyle.Information) 
             OdemkniPolozky() ' nakonec odemkneme znovu položky v menu na připojení a vytvoření spojení 
         End Try 
     End Sub 

nahlásit spamnahlásit spam 1 / 1 odpovědětodpovědět
public void CtiData(System.IAsyncResult at)
{
	try {
		int prijato = networkStream.EndRead(at);
		// dokončíme čtení dat a zjistíme kolik dat přišlo 
		if (prijato < 1)
			throw new Exception();
		// spojení bylo ukončeno (přichází 0B dat) 

		// >> ZDE BUDE KOD NA ZPRACOVANI PRICHOZICH DAT << 

		tcp.GetStream.BeginRead(Buffer, 0, BUFFER_SIZE, CtiData, null);
		// přečetli jsme všechny příchozí data, proto budeme čekat až přijdou další 
	} catch (ObjectDisposedException e) {
	// proběhlo zrušení spojení 
	} catch (Exception e) {
		Interaction.MsgBox(e.Message);
		// nastala chyba, spojení je ukončeno 
		StripInfo.Text = "Spojení bylo ukončeno";
		// informace pro uživatele 
		Interaction.MsgBox("Spojení ukončeno!", MsgBoxStyle.Information);
		OdemkniPolozky();
		// nakonec odemkneme znovu položky v menu na připojení a vytvoření spojení 
	}
}

nahlásit spamnahlásit spam 0 odpovědětodpovědět

Diskuse: Přenos dat, protokol a dokončení

Takže něco jako

dim path as string = "C:\test.jpg"

Dim stream As Byte() = System.IO.File.ReadAllBytes(path)

nahlásit spamnahlásit spam 1 / 1 odpovědětodpovědět

Diskuse: Přenos dat, protokol a dokončení

Dobrý den.

Nejdříve chci říci, že jsem moc rád, že někdo osvětlil jak vlastně funguje TCP client / server do detailu. Mám svoji aplikaci, je to vlasně chat, a text převádím takto

System.Text.Encoding.ASCII.GetBytes(messagetoserver)

Co ale nevím, jak poslat soubor. Napadlo mne, přečíst obsah a poslat to jako string...více méně to funguje, ale u obrázků a exe souborů atd. to nerozpozná některé znaky ani když použiji kódování

Dim coding As System.Text.Encoding = System.Text.Encoding.GetEncoding("windows-1250")

které umožní přečíst ,,čřžÁÝŽ" atd.

Opravdu bych byl moc vděčný, kdyby mi někdo poradil, jak poslat soubor. Nejsem zádný expert, spíše nadšenec, a asi tak 30 aplikací jsem již udělal (většinou databáze, čtení ze souboru, ale i hru chcete byt milionářem).

Moc děkuju za případné odpovědi.

nahlásit spamnahlásit spam 0 odpovědětodpovědět

skuste to poslat jako pole bytů

nahlásit spamnahlásit spam 0 odpovědětodpovědět

Diskuse: Přenos dat, protokol a dokončení

Mohol by tu niekto prosim Vas zverejnit ten "kod pro pripojeni vice uzivatelu ?" Dost by to pomohlo. THX

nahlásit spamnahlásit spam 1 / 1 odpovědětodpovědět

Diskuse: Přenos dat, protokol a dokončení

Ahoj, a jde tento program rozchodit i u pc s neveřejnou ip? Zkoušel jsem to a nepřipojí se a nepřipojí :-(

nahlásit spamnahlásit spam 1 / 1 odpovědětodpovědět

To je otázka TCP/IP protokolu. Vždy musíte mít PC ke kterému se připojujete dostupný. Pokud to tak není, tak to nikdy nebude fungovat (což je běžné u připojovatelů k internetu - schovají vás za takzvaný NAT). To nijak neoblbnete.

Řešením je používat server, či cokoliv jiného, co vám zpřístupní druhý bod nějakou fintou. Například program Hamachi nebo v lepším případě otevřít port přímo na zařízení zajišťující NAT.

nahlásit spamnahlásit spam 0 odpovědětodpovědět

Diskuse: Přenos dat, protokol a dokončení

Jakým kódem udělat aby se poslala backgroundcolor toho druhého (mám colordialog2 a příkaz pro změneu barvy a tAKTO to má být:)

PC1 si změní barvu > data o barvě se pošlou druhému > druhý data zpracuje a nastaví backcolor (příkaz bude vypadat takto:

"pozadi black;")

nahlásit spamnahlásit spam 1 / 1 odpovědětodpovědět

Připojil jsem tabuli na terninál v xp (localhost) a nakreslil jsem obrázek. Hezké že:

 10 128 255 128;cara 74 429 75 429 10 128 255 128;cara 75 429 76 429 10 128 2555                                                                              
128;cara 76 429 77 429 10 128 255 128;cara 77 429 78 429 10 128 255 128;cara 780 1                                                                            
429 79 429 10 128 255 128;cara 79 429 80 429 10 128 255 128;cara 80 429 81 429 15 25                                                                            
0 128 255 128;cara 81 429 82 429 10 128 255 128;cara 82 429 83 429 10 128 255 128;ca                                                                            
8;cara 83 429 84 429 10 128 255 128;cara 84 429 85 429 10 128 255 128;cara 85 4247 1                                                                            
9 87 429 10 128 255 128;cara 87 429 88 429 10 128 255 128;cara 88 429 91 429 10 94 1                                                                          
128 255 128;cara 91 429 92 429 10 128 255 128;cara 92 429 94 429 10 128 255 128;                                                                              
2
cara 94 429 95 429 10 128 255 128;cara 95 429 96 429 10 128 255 128;cara 96 4299                                                                              
97 429 10 128 255 128;cara 97 429 99 429 10 128 255 128;cara 99 429 100 429 10 100                                                                            
1
28 255 128;cara 100 429 101 429 10 128 255 128;cara 101 429 103 429 10 128 255 128                                                                            
;
28;cara 103 429 106 429 10 128 255 128;cara 106 429 108 429 10 128 255 128;caracar                                                                            
108 429 109 429 10 128 255 128;cara 109 429 112 429 10 128 255 128;cara 112 42999 37                                                                          
ara 120 429 123 429 10 128 255 128;cara 123 429 124 429 10 128 255 128;cara 124 26                                                                            
429 126 429 10 128 255 128;cara 126 429 127 429 10 128 255 128;cara 127 429 12884 26                                                                          
429 10 128 255 128;cara 128 429 130 429 10 128 255 128;cara 130 429 131 429 10 1387 10                                                                        
 
3
28;cara 135 429 137 429 10 128 255 128;cara 137 429 140 429 10 128 255 128;carac                                                                            
3
140 429 142 429 10 128 255 128;cara 142 429 145 430 10 128 255 128;cara 145 430859                                                                            
146 430 10 128 255 128;cara 146 430 147 430 10 128 255 128;cara 147 430 148 43085 39                                                                          
10 128 255 128;cara 148 430 149 430 10 128 255 128;cara 149 430 150 430 10 128 2 2 255                                                                          
55 128;cara 150 430 153 430 10 128 255 128;cara 153 430 156 430 10 128 255 128;c 1 192                                                                          
434 10 128 255 128;cara 181 434 188 435 10 128 255 128;cara 188 435 200 435 10 12 10                                                                          
1
28 255 128;cara 200 435 207 436 10 128 255 128;cara 207 436 214 436 10 128 255 1 128                                                                        
8
5
28;cara 214 436 221 436 10 128 255 128;cara 221 436 223 436 10 128 255 128;cara2;car                                                                      
255
223 436 230 436 10 128 255 128;cara 230 436 237 437 10 128 255 128;cara 237 4374276 40                                                                    
   
ara 254 438 255 438 10 128 255 128;cara 255 438 256 438 10 128 255 128;cara 2565 2                                                                        
74 
438 259 438 10 128 255 128;cara 259 438 262 438 10 128 255 128;cara 262 438 265cara8                                                                      
255
438 10 128 255 128;cara 265 438 267 438 10 128 255 128;cara 267 438 268 438 10 167 810                                                                    
     
2
299 440 10 128 255 128;cara 299 440 306 440 10 128 255 128;cara 306 440 318 440555 2                                                                        
5
10 128 255 128;cara 318 440 321 440 10 128 255 128;cara 321 440 331 440 10 128 2raara5                                                                      
255
55 128;cara 331 440 334 440 10 128 255 128;cara 334 440 340 440 10 128 255 128;c04 392                                                                    
     
459 438 10 128 255 128;cara 459 438 466 438 10 128 255 128;cara 466 438 478 4388                                                                              
10 128 255 128;cara 478 438 485 438 10 128 255 128;cara 485 438 491 438 10 128 234                                                                              
55 128;cara 491 438 503 438 10 128 255 128;cara 503 438 515 438 10 128 255 128;c 2                                                                            
0
ara 515 438 522 438 10 128 255 128;cara 522 438 528 438 10 128 255 128;cara 5281;c                                                                            
438 535 438 10 128 255 128;cara 535 438 542 438 10 128 255 128;cara 542 438 549 12 4                                                                          
438 10 128 255 128;cara 549 438 555 438 10 128 255 128;cara 555 438 562 438 10 173 555                                                                          
2
28;cara 575 438 582 438 10 128 255 128;cara 582 438 594 438 10 128 255 128;cara3                                                                              
594 438 605 438 10 128 255 128;cara 605 438 612 438 10 128 255 128;cara 612 4385 2                                                                            
619 438 10 128 255 128;cara 619 438 622 438 10 128 255 128;cara 622 438 628 4385ara1                                                                          
10 128 255 128;cara 628 438 631 438 10 128 255 128;cara 631 438 633 438 10 128 2ca 555                                                                          
55 128;cara 633 438 636 438 10 128 255 128;cara 636 438 639 437 10 128 255 128;c455592                                                                          
436 643 435 10 128 255 128;cara 643 435 644 435 10 128 255 128;cara 644 435 645a84                                                                            
435 10 128 255 128;cara 645 435 646 435 10 128 255 128;cara 646 435 646 436 10 19110                                                                            
28 255 128;cara 646 436 646 438 10 128 255 128;cara 646 438 644 445 10 128 255 18128                                                                            
28;cara 644 445 640 457 10 128 255 128;cara 640 457 636 469 10 128 255 128;cara4;car                                                                          
636 469 632 486 10 128 255 128;cara 632 486 624 498 10 128 255 128;cara 624 498 689 23                                                                        
615 516 10 128 255 128;cara 615 516 602 529 10 128 255 128;cara 602 529 598 5419                                                                              
10 128 255 128;cara 598 541 591 545 10 128 255 128;cara 591 545 588 548 10 128 2 2                                                                            
1
55 128;cara 588 548 587 548 10 128 255 128;cara 587 548 586 549 10 128 255 128;c;c                                                                            
 
ara 586 549 586 548 10 128 255 128;cara 586 548 592 542 10 128 255 128;cara 5922 4                                                                            
542 616 521 10 128 255 128;cara 616 521 643 503 10 128 255 128;cara 643 503 6706 655                                                                          
486 10 128 255 128;cara 670 486 683 473 10 128 255 128;cara 683 473 686 470 10 1 10car                                                                          
28;cara 687 467 686 467 10 128 255 128;cara 686 467 685 467 10 128 255 128;cara2                                                                            
1
685 467 684 467 10 128 255 128;cara 684 467 682 467 10 128 255 128;cara 682 4675a6                                                                            
675 468 10 128 255 128;cara 675 468 668 470 10 128 255 128;cara 668 470 652 471;ca26                                                                          
10 128 255 128;cara 652 471 631 472 10 128 255 128;cara 631 472 610 474 10 128 27 4355                                                                          
55 128;cara 610 474 575 476 10 128 255 128;cara 575 476 554 476 10 128 255 128;c255992                                                                          
474 10 128 255 128;cara 531 474 533 472 10 128 255 128;cara 533 472 537 464 10 12510                                                                            
28 255 128;cara 537 464 541 457 10 128 255 128;cara 541 457 542 450 10 128 255 1 428                                                                            
28;cara 542 450 543 447 10 128 255 128;cara 543 447 544 446 10 128 255 128;cara 34ar                                                                          
544 446 545 445 10 128 255 128;cara 545 445 545 444 10 128 255 128;cara 545 444 255 29                                                                        
544 444 10 128 255 128;cara 544 444 541 444 10 128 255 128;cara 541 444 527 4456                                                                              
10 128 255 128;cara 527 445 495 455 10 128 255 128;cara 495 455 443 477 10 128 2 1                                                                            
0
55 128;cara 443 477 391 498 10 128 255 128;cara 391 498 332 520 10 128 255 128;c12                                                                            
 
ara 332 520 280 541 10 128 255 128;cara 280 541 243 554 10 128 255 128;cara 2430 2                                                                            
554 223 563 10 128 255 128;cara 223 563 221 564 10 128 255 128;cara 221 564 2229 10r                                                                          
563 10 128 255 128;cara 222 563 224 562 10 128 255 128;cara 224 562 239 558 10 1128;15                                                                          
28;cara 296 551 331 549 10 128 255 128;cara 331 549 365 547 10 128 255 128;carar                                                                            
1
365 547 393 545 10 128 255 128;cara 393 545 405 544 10 128 255 128;cara 405 544a31                                                                            
408 543 10 128 255 128;cara 408 543 409 542 10 128 255 128;cara 409 542 408 542 4431                                                                          
10 128 255 128;cara 408 542 407 542 10 128 255 128;cara 407 542 402 542 10 128 225525538 220 139 4 128 0 128;cara 220 139 220 140 4 128 0 128;cara 22           
55 128;cara 402 542 390 542 10 128 255 128;cara 390 542 370 542 10 128 255 128;cra7192128 0 128;cara 220 141 220 142 4 128 0 128;cara 220 142 220 14            
545 10 128 255 128;cara 150 545 138 546 10 128 255 128;cara 138 546 139 546 10 1 410 1                                                                          
28 255 128;cara 139 546 141 545 10 128 255 128;cara 141 545 148 544 10 128 255 13828 15                                                                         
28;cara 148 544 155 542 10 128 255 128;cara 155 542 171 541 10 128 255 128;cara556ar4 12                                                                      
171 541 188 540 10 128 255 128;cara 188 540 210 535 10 128 255 128;cara 210 535475 232ara 2                                                                   
227 531 10 128 255 128;cara 227 531 243 529 10 128 255 128;cara 243 529 246 5291                                                                              
10 128 255 128;cara 246 529 247 528 10 128 255 128;cara 247 528 247 527 10 128 212c                                                                             
55 128;cara 247 527 247 526 10 128 255 128;cara 247 526 246 526 10 128 255 128;c 422                                                                            
ara 246 526 245 525 10 128 255 128;cara 245 525 244 524 10 128 255 128;cara 24410r 0                                                                          
524 242 523 10 128 255 128;cara 242 523 239 522 10 128 255 128;cara 239 522 23628;271                                                                         
521 10 128 255 128;cara 236 521 226 520 10 128 255 128;cara 226 520 205 519 10 1 285 2 1                                                                        
28 255 128;cara 205 519 184 517 10 128 255 128;cara 184 517 162 516 10 128 255 1                                                                              
5
28;cara 162 516 146 514 10 128 255 128;cara 146 514 143 514 10 128 255 128;caraa                                                                            
1
143 514 142 513 10 128 255 128;cara 142 513 142 512 10 128 255 128;cara 142 512 48                                                                            
142 511 10 128 255 128;cara 142 511 143 511 10 128 255 128;cara 143 511 145 508 2551                                                                          
10 128 255 128;cara 145 508 146 505 10 128 255 128;cara 146 505 149 503 10 128 2cara55                                                                          
55 128;cara 149 503 153 490 10 128 255 128;cara 153 490 157 483 10 128 255 128;c478192                                                                          
471 10 128 255 128;cara 163 471 162 471 10 128 255 128;cara 162 471 156 472 10 12 14                                                                            
28 255 128;cara 156 472 145 473 10 128 255 128;cara 145 473 133 475 10 128 255 12558                                                                            
28;cara 133 475 116 476 10 128 255 128;cara 116 476 95 478 10 128 255 128;cara 970ar                                                                            
5 478 67 479 10 128 255 128;cara 67 479 33 479 10 128 255 128;cara 33 479 6 4792 126                                                                          
10 128 255 128;cara 6 479 -28 479 10 128 255 128;cara -28 479 -56 479 10 128 255                                                                              
1
 128;cara -56 479 -67 479 10 128 255 128;cara -67 479 -74 479 10 128 255 128;car                                                                              
8
a -74 479 -75 479 10 128 255 128;cara -75 479 -74 479 10 128 255 128;cara -74 47                                                                              
2
9 -73 478 10 128 255 128;cara -73 478 -71 477 10 128 255 128;cara -71 477 -68 47                                                                            
2
c
6 10 128 255 128;cara -68 476 -61 473 10 128 255 128;cara -61 473 -50 471 10 128                                                                            
455
 255 128;cara -50 471 -38 470 10 128 255 128;cara -38 470 -21 469 10 128 255 128                                                                            
   
1
59 10 128 255 128;cara 11 459 11 458 10 128 255 128;cara 11 458 14 457 10 128 25                                                                              
 
5 128;cara 14 457 16 456 10 128 255 128;cara 16 456 23 455 10 128 255 128;cara 2                                                                              
1
3 455 30 454 10 128 255 128;cara 30 454 37 453 10 128 255 128;cara 37 453 44 452                                                                            
1
 
 10 128 255 128;cara 44 452 51 451 10 128 255 128;cara 51 451 58 451 10 128 255c                                                                          
1
 
128;cara 58 451 59 451 10 128 255 128;cara 59 451 60 451 10 128 255 128;cara 609 5                                                                        
 
 
1
128 255 128;cara 51 450 71 450 10 128 255 128;cara 71 450 88 450 10 128 255 128;;c                                                                          
1
2
cara 88 450 95 451 10 128 255 128;cara 95 451 102 452 10 128 255 128;cara 102 45 5                                                                          
5
1
2 105 453 10 128 255 128;cara 105 453 106 453 10 128 255 128;cara 106 453 105 4555                                                                          
a
6
3 10 128 255 128;cara 105 453 104 453 10 128 255 128;cara 104 453 103 453 10 128ar                                                                        
 
 
 
19 
6 453 10 128 255 128;cara 186 453 189 453 10 128 255 128;cara 189 453 190 453 10                                                                            
 25
 128 255 128;cara 190 453 189 453 10 128 255 128;cara 189 453 188 453 10 128 255                                                                            
;ca
 128;cara 188 453 187 453 10 128 255 128;cara 187 453 186 453 10 128 255 128;car                                                                          
 
   
3
 128 255 128;cara 141 457 167 458 10 128 255 128;cara 167 458 194 458 10 128 255                                                                            
2
5
 128;cara 194 458 228 458 10 128 255 128;cara 228 458 262 458 10 128 255 128;car                                                                            
 
2
a 262 458 290 458 10 128 255 128;cara 290 458 306 458 10 128 255 128;cara 306 45                                                                            
2
 
8 313 458 10 128 255 128;cara 313 458 316 458 10 128 255 128;cara 316 458 316 45                                                                          
2
 
7
7 10 128 255 128;cara 316 457 316 456 10 128 255 128;cara 316 456 315 455 10 128                                                                        
 
 
   
1
 128 255 128;cara 457 457 457 456 10 128 255 128;cara 457 456 458 455 10 128 255                                                                              
c
 128;cara 458 455 459 454 10 128 255 128;cara 459 454 460 453 10 128 255 128;car                                                                            
21 
a 460 453 460 452 10 128 255 128;cara 460 452 460 451 10 128 255 128;cara 460 45                                                                          
8
7 447 468 446 10 128 255 128;cara 468 446 469 446 10 128 255 128;cara 469 446 47
2 446 10 128 255 128;cara 472 446 482 446 10 128 255 128;cara 482 446 489 446 10
 128 255 128;cara 489 446 501 446 10 128 255 128;cara 501 446 507 446 10 128 255
 128;cara 507 446 514 446 10 128 255 128;cara 514 446 517 446 10 128 255 128;car
a 517 446 520 446 10 128 255 128;cara 520 446 521 446 10 128 255 128;cara 521 44
6 522 446 10 128 255 128;cara 522 446 522 445 10 128 255 128;cara 522 445 523 44
4 10 128 255 128;cara 523 444 524 444 10 128 255 128;cara 524 444 525 443 10 128
 255 128;cara 525 443 528 443 10 128 255 128;cara 528 443 531 443 10 128 255 128
;cara 531 443 534 443 10 128 255 128;cara 534 443 536 443 10 128 255 128;cara 53
6 443 543 444 10 128 255 128;cara 543 444 549 444 10 128 255 128;cara 549 444 55
6 445 10 128 255 128;cara 556 445 559 446 10 128 255 128;cara 559 446 570 446 10
 128 255 128;cara 570 446 572 446 10 128 255 128;cara 572 446 575 446 10 128 255
 128;cara 575 446 576 446 10 128 255 128;cara 576 446 578 446 10 128 255 128;car
a 578 446 581 446 10 128 255 128;cara 581 446 582 446 10 128 255 128;cara 582 44
6 583 446 10 128 255 128;cara 583 446 584 446 10 128 255 128;cara 584 446 585 44
6 10 128 255 128;cara 585 446 586 446 10 128 255 128;cara 586 446 587 446 10 128
 255 128;cara 587 446 588 446 10 128 255 128;cara 588 446 589 446 10 128 255 128
;cara 589 446 590 446 10 128 255 128;cara 590 446 591 446 10 128 255 128;cara 59
1 446 591 447 10 128 255 128;cara 591 447 592 448 10 128 255 128;cara 592 448 59
3 448 10 128 255 128;cara 593 448 594 448 10 128 255 128;cara 594 448 595 448 10
 128 255 128;cara 595 448 596 449 10 128 255 128;cara 596 449 596 450 10 128 255
 128;cara 596 450 597 450 10 128 255 128;cara 597 450 600 453 10 128 255 128;car
a 600 453 602 454 10 128 255 128;cara 602 454 603 454 10 128 255 128;cara 603 45
4 604 455 10 128 255 128;cara 604 455 604 456 10 128 255 128;

k terminálu se připojíte tak že:

V xp dáte start>všechny programy>příslušnství>komunikace>HyperTerminal

do okénka popis připojení toto:

název - jak chcete

OK

potom připojit pomocí = tpc/ip

port = 3556

hostitel = hostitel, pro test na jednom pc localhost

než dáte OK spusťte tabuli a založit spojení

ok

aby jste mohli příkazy dávat tak takhle:

zavolat>odpojit

zavolat>čekat na volání

v tabuli

připojit se> prostě hostitel (test na localhost)

nahlásit spamnahlásit spam 3 / 3 odpovědětodpovědět

Diskuse: Přenos dat, protokol a dokončení

Tento úžasný článek mě inspiroval k naprogramování chatu mezi dvěma počítači (vlastně jde o úplně totéž, akorát chci převedené byty vypsat do textboxu). Téměř všechno funguje tak jak má, ale do textboxu2(to je ten, kde se vypisují zprávy od druhého uživatele) se nic nevypíše. Dal jsem textbox2 do watch a tam se u něj píše: error:cannot obtain value. Ćást kódu, kde by se to mělo vypsat, vypadá takto:

   Dim prijato As Integer = networkstream.EndRead(at)
            If prijato < 1 Then Throw New Exception
            textbuffer = textbuffer & System.Text.Encoding.ASCII.GetString(buffer, 0, prijato)

            REM Threading.Monitor.Enter(Me)
            tcp.GetStream.BeginRead(buffer, 0, buffersize, AddressOf spravadat, Nothing)
            REM Threading.Monitor.Exit(Me)
            zaloznitext2 = CStr(textbuffer) ' tento příkaz ještě funguje
            TextBox2.Text = TextBox2.Text & vbCrLf & zaloznitext2 ' TENTO příkaz  nefunguje

Neví někdo kde bych mohl udělat chybu? Používám VB.NET 2005 express edition. Moc díky za odpovědi

nahlásit spamnahlásit spam 1 / 1 odpovědětodpovědět

Diskuse: Přenos dat, protokol a dokončení

Mohl bych poprosit o konkretni priklad kodu pro pripojeni vice uzivatelu ? :x

nahlásit spamnahlásit spam 2 / 2 odpovědětodpovědět

to by mě taky zajímalo

nahlásit spamnahlásit spam 2 / 2 odpovědětodpovědět

Diskuse: Přenos dat, protokol a dokončení

Ahoj. Mě by taky zajímalo, jakým způsobem to napsat, abych měl dejme tomu jednu server aplikaci, která by jen obhospodařovala libovolný počet klientů. Trochu tuším, že to bude o tvoření vláken pro jednotlivé klienty, ale s VB.NET zatím bohužel moc zkušeností nemám a v předchozím VB6 tohle bylo pomocí Winsock víceméně nerealizovatelné. Díky, Milan.

nahlásit spamnahlásit spam 1 / 1 odpovědětodpovědět

Tak už nic...Už jsem si pomohl sám.

Kažopádně doufam, že budete mít teď po uzávěrce soutěže trochu víc času na další a další články.

nahlásit spamnahlásit spam -1 / 1 odpovědětodpovědět

To je super, to si šikovný a mohl by si to sem napsat? Možná by mi to ulehčilo práci, kterou ty si už zvládl ;o) díky mnohokrát

nahlásit spamnahlásit spam 1 / 1 odpovědětodpovědět
                       
Nadpis:
Antispam: Komu se občas házejí perly?
Příspěvek bude publikován pod identitou   anonym.

Nyní zakládáte pod článkem nové diskusní vlákno.
Pokud chcete reagovat na jiný příspěvek, klikněte na tlačítko "Odpovědět" u některého diskusního příspěvku.

Nyní odpovídáte na příspěvek pod článkem. Nebo chcete raději založit nové vlákno?

 

  • Administrátoři si vyhrazují právo komentáře upravovat či mazat bez udání důvodu.
    Mazány budou zejména komentáře obsahující vulgarity nebo porušující pravidla publikování.
  • Pokud nejste zaregistrováni, Vaše IP adresa bude zveřejněna. Pokud s tímto nesouhlasíte, příspěvek neodesílejte.

přihlásit pomocí externího účtu

přihlásit pomocí jména a hesla

Uživatel:
Heslo:

zapomenuté heslo

 

založit nový uživatelský účet

zaregistrujte se

 
zavřít

Nahlásit spam

Opravdu chcete tento příspěvek nahlásit pro porušování pravidel fóra?

Nahlásit Zrušit

Chyba

zavřít

feedback