05. august 2004 - 01:33Der er
48 kommentarer og 1 løsning
Client/Server application
Jeg ønsker at lave en client/server applikation i vb.net, således at en client kan sende en string/fil til serveren, hvorefter klient får besked om det lykkedes. Dette skal ske hvert ms.
Hvis det kan gøres smartere og nemmere på en anden måde er det også ok, bare der sendes over et TCP/IP netværk. Hvis det f.eks. kunne gøres via en browser ville det være vildt fedt.. Men der er vist ingen knap i en browser som kan reagere hurtigt nok til at sende f.eks. 3 gang inde for et sekund, men lad høre.
Det er ret nemt at lave noget client/server i VB.NET.
Du kan starte med dette simple eksempel:
client:
Imports System Imports System.IO Imports System.Net.Sockets Imports System.Threading
Class Client Public Shared Sub Main(ByVal args As String()) Dim client As TcpClient = New TcpClient ("localhost", 1234) Dim wrt As StreamWriter = New StreamWriter (client.GetStream) Dim rdr As StreamReader = New StreamReader (client.GetStream) Dim outmsg As String Dim inmsg As String While True outmsg = "Dette er en streng eller en fil" wrt.WriteLine(outmsg) wrt.Flush inmsg = rdr.ReadLine Console.WriteLine(inmsg) Thread.Sleep(500) End While wrt.Close rdr.Close client.Close End Sub End Class
server:
Imports System Imports System.IO Imports System.Net Imports System.Net.Sockets
Class Server Public Shared Sub Main(ByVal args As String()) Dim server As TcpListener = New TcpListener (IPAddress.Any, 1234) server.Start Dim client As TcpClient = server.AcceptTcpClient Dim rdr As StreamReader = New StreamReader (client.GetStream) Dim wrt As StreamWriter = New StreamWriter (client.GetStream) Dim outmsg As String Dim inmsg As String inmsg = rdr.ReadLine While Not (inmsg Is Nothing) Console.WriteLine(inmsg) outmsg = "OK" wrt.WriteLine(outmsg) wrt.Flush inmsg = rdr.ReadLine End While rdr.Close wrt.Close client.Close server.Stop End Sub End Class
Imports System Imports System.IO Imports System.Net.Sockets Imports System.Threading
Class Client Public Shared Sub Main(ByVal args As String()) ' connect til localhost port 1234 Dim client As TcpClient = New TcpClient ("localhost", 1234) ' hent writer og reader til at skrive og læse med Dim wrt As StreamWriter = New StreamWriter (client.GetStream) Dim rdr As StreamReader = New StreamReader (client.GetStream) Dim outmsg As String Dim inmsg As String ' uendelig løkke med: ' skriv til server ' læse fra server ' udskriv det læste til skærmen While True outmsg = "Dette er en streng eller en fil" wrt.WriteLine(outmsg) wrt.Flush inmsg = rdr.ReadLine Console.WriteLine(inmsg) Thread.Sleep(500) End While ' luk alting wrt.Close rdr.Close client.Close End Sub End Class
Imports System Imports System.IO Imports System.Net Imports System.Net.Sockets
Class Server Public Shared Sub Main(ByVal args As String()) ' lyt på port 1234 Dim server As TcpListener = New TcpListener (IPAddress.Any, 1234) server.Start ' vent på connection Dim client As TcpClient = server.AcceptTcpClient ' hent writer og reader til at skrive og læse med Dim rdr As StreamReader = New StreamReader (client.GetStream) Dim wrt As StreamWriter = New StreamWriter (client.GetStream) Dim outmsg As String Dim inmsg As String ' så længe der kommer data ind: ' læs data fra client ' udskriv data til skærmen ' skriv svar tilbage til client inmsg = rdr.ReadLine While Not (inmsg Is Nothing) Console.WriteLine(inmsg) outmsg = "OK" wrt.WriteLine(outmsg) wrt.Flush inmsg = rdr.ReadLine End While ' luk alting rdr.Close wrt.Close client.Close server.Stop End Sub End Class
Ok, mit problem er nok at der ikke kom noget på skærmen og at den kom med en fejl hvis det ene program blev startet noget før end det andet. Dvs. det ene program kan ikke køre uden det anden uden at kommer med en fejl medl. Det kan nok klares med en try... Men jeg forstår bare ikke hvorfor der ikke kommer noget på skærmen... åhh.. det er nok fordi at jeg ikke programmere i console -mode men i grafisk... Anyway 1000 tak... alle pointene er dig velfortjent.
Jeg er opmærksom på at dette er et spørgsmål udenfor og du siger bare hvis du skal have points, men er det - på en nem måde - muligt at få serveren til at lave andet mens den venter på at få et svar og når den så få et svar så hopper den til en given funktion? Som jeg ser det - ser det ud som om at man skal lade client kalde proceduren hvert x ms (ikke fordi jeg ved hvordan det nemmest gøres). Eller er der en nemmere løsning?
Den her version af server venter på client connecter men så modtager den både beskeder fra client og laver noget andet:
Imports System Imports System.IO Imports System.Net Imports System.Net.Sockets Imports System.Threading
Public Class T Private client As TcpClient Public Sub New(cli As TcpClient) client = cli End Sub Public Sub Run() Dim rdr As StreamReader = New StreamReader (client.GetStream) Dim wrt As StreamWriter = New StreamWriter (client.GetStream) Dim outmsg As String Dim inmsg As String inmsg = rdr.ReadLine While Not (inmsg Is Nothing) Console.WriteLine(inmsg) outmsg = "OK" wrt.WriteLine(outmsg) wrt.Flush inmsg = rdr.ReadLine End While rdr.Close wrt.Close End Sub End Class
Class Server Public Shared Sub Main(ByVal args As String()) Dim server As TcpListener = New TcpListener (IPAddress.Any, 1234) server.Start Dim client As TcpClient = server.AcceptTcpClient Dim clienthandler As T = New T(client) Call (New Thread (New ThreadStart (AddressOf clienthandler.Run))).Start While True Console.WriteLine("I am doing something") Thread.Sleep(250) End While client.Close server.Stop End Sub End Class
Den her version af server lader venten på connect ske i tråden så den kan gå igang med noget andet med det samme uden at vente på client:
Imports System Imports System.IO Imports System.Net Imports System.Net.Sockets Imports System.Threading
Public Class T Private server As TcpListener Public Sub New(srv As TcpListener) server = srv End Sub Public Sub Run() Dim client As TcpClient = server.AcceptTcpClient Dim rdr As StreamReader = New StreamReader (client.GetStream) Dim wrt As StreamWriter = New StreamWriter (client.GetStream) Dim outmsg As String Dim inmsg As String inmsg = rdr.ReadLine While Not (inmsg Is Nothing) Console.WriteLine(inmsg) outmsg = "OK" wrt.WriteLine(outmsg) wrt.Flush inmsg = rdr.ReadLine End While rdr.Close wrt.Close client.Close End Sub End Class
Class Server Public Shared Sub Main(ByVal args As String()) Dim server As TcpListener = New TcpListener (IPAddress.Any, 1234) server.Start Dim clienthandler As T = New T(server) Call (New Thread (New ThreadStart (AddressOf clienthandler.Run))).Start While True Console.WriteLine("I am doing something") Thread.Sleep(250) End While server.Stop End Sub End Class
Det ser rigtig godt ud, men hvad sker der i linierne: Dim clienthandler As T = New T(server) Call (New Thread(New ThreadStart(AddressOf clienthandler.Run))).Start()
Nogle andre sprog insisterer på at man skal angive kommando linie argumenterne til Main selvom man ikke har planer om at bruge dem. Det er bare en vane.
' lav et client handler objekt som skal bruges til at køre tråd med Dim clienthandler As T = New T(server) ' start en ny tråd med clienthandler objektet og Run metoden Call (New Thread(New ThreadStart(AddressOf clienthandler.Run))).Start()
Public Class T Public Sub Run() Console.WriteLine("T Run") End Sub End Class
Module Main Public Sub Run() Console.WriteLine("Run") End Sub Sub Main() Dim thr As T = new T Call (New Thread(New ThreadStart(AddressOf thr.Run))).Start Call (New Thread(AddressOf thr.Run)).Start Call (New Thread(New ThreadStart(AddressOf Run))).Start Call (New Thread(AddressOf Run)).Start End Sub End Module
Har du en bog du kan anbefale i forbindelse med obj-programmeret i vb.net?
(åh og et sidste lille ? Når jeg i Tråden (T) og vil tilføje noget til en listbox i classen "server" kan jeg ikke skrive Form1.listbox1.item.add("hej"), hvorfor ikk'?)
Jeg har faktisk ikke en VB.NET bog selv. En mulighed var Professional VB.NET / Wrox. Jeg har den tilsvarende C# bog og den er god. Anmeldelserne på Amazon er dog lidt blandede.
Jeg formoder at du enten skal kalde en metode i den klasse der har Form1 eller at du skal have en reference til Form1 sendt med over i T.
Hej Arne Jeg formoder at dine tråde i 2. og 3. sidste eksempel aldrig bliver lukket. Betyder det ikke at de aldrig forsvinder fra memory og dermed fylder efter man har lukke applicationen (pga. while true...)? eller ?
Bør man lave en Form1_Closing(...) Handles MyBase.Closing eller er jeg helt på afspor?
Jeg har lavet nedenstående og hver gang jeg lukker applikationen forbliver processen i windows jobliste, og applicationen kan ikke startes igen før end jeg har afbrudt den fra windows jobliste.
Public Sub lyt() ListBox1.Items.Add("logon") ' Add the data to the list While True Dim server As TcpListener = New TcpListener(IPAddress.Any, 1234) server.Start() ' Start listen for client request Dim inmsg As String Dim client As TcpClient = server.AcceptTcpClient ' Wait for a client to connect ' ... connected Dim rdr As StreamReader = New StreamReader(client.GetStream) ' Prepare for data inmsg = rdr.ReadLine ' Get first steam of data While Not (inmsg Is Nothing) ListBox1.Items.Add(inmsg) ' Add the data to the list inmsg = rdr.ReadLine End While rdr.Close() ' close data stream client.Close() ' close client connection server.Stop() ' stop listen End While End Sub
Private Sub Button1_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles Button1.Click Call New Thread(AddressOf lyt).Start() ' Start the thread End Sub
Jeg forstår det ikke, hele min app. fryser ved: Dim client As TcpClient = server.AcceptTcpClient() selv om er i tråden. Var det ikke netop det tråden skulle løse?
Mit prg. ser således ud nu:
Class lyt Private server As TcpListener Public Event TreadDone(ByVal minmsg As String)
Public Sub New(ByVal srv As TcpListener) server = srv End Sub Public Sub GetData() While True Dim client As TcpClient = server.AcceptTcpClient() ' ... connected Dim rdr As StreamReader = New StreamReader(client.GetStream) Dim inmsg As String inmsg = rdr.ReadLine While Not (inmsg Is Nothing) RaiseEvent TreadDone(inmsg) inmsg = rdr.ReadLine End While rdr.Close() client.Close() End While server.Stop() End Sub End Class
Private Sub Form1_Load(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles MyBase.Load Dim server As TcpListener = New TcpListener(IPAddress.Any, 1234) server.Start() ClientData = New lyt(server)
Call (New Thread(New ThreadStart(AddressOf ClientData.GetData))).Start() End Sub
Private Sub AddItem(ByVal minmsg As String) Handles ClientData.TreadDone If Not (minmsg Is Nothing) Then ListBox1.Items.Add(minmsg) ' Add the data to the list End If End Sub
Namespace DefaultNamespace Public Class MainClass Public Shared Sub Main Dim mf As New MainForm Dim server As TcpListener = New TcpListener(IPAddress.Any, 1234) server.Start() Dim t As Listen = New Listen(server, mf) Call (New Thread(New ThreadStart(AddressOf t.WaitForConnectAndAccept))).Start() mf.ShowDialog() End Sub End Class Public Class Listen Private server As TcpListener Private mainform As MainForm Public Sub New(srv As TcpListener, mf As MainForm) server = srv mainform = mf End Sub Public Sub WaitForConnectAndAccept() MessageBox.Show("started") While True Dim client As TcpClient = server.AcceptTcpClient Dim rdr As StreamReader = New StreamReader(client.GetStream) Dim line As String = rdr.ReadLine mainform.SetLabel2(line) rdr.Close client.Close End While server.Stop() End Sub End Class Public Class MainForm Inherits System.Windows.Forms.Form Private label1 As Label Private button1 As Button Private button2 As Button Private label2 As Label Private button3 As Button Public Sub SetLabel2(txt As String) label2.Text = txt End Sub Public Sub New() MyBase.New Me.InitializeComponent End Sub Private Sub InitializeComponent() SuspendLayout
ClientSize = New Size(300, 300) Name = "MainForm" Text = "MainForm"
label1 = New Label label1.Location = New Point(50, 50) label1.Size = new Size(200, 25) label1.Name = "label1" label1.TabIndex = 0 label1.Text = "Du har ikke trykket endnu" Controls.Add(label1)
button1 = New Button button1.Location = New Point(50, 100) button1.Size = new Size(200, 25) button1.Name = "button1" button1.TabIndex = 1 button1.Text = "A" AddHandler button1.Click, AddressOf ClickA Controls.Add(button1)
button2 = New Button button2.Location = New Point(50, 150) button2.Size = new Size(200, 25) button2.Name = "button2" button2.TabIndex = 2 button2.Text = "B" AddHandler button2.Click, AddressOf ClickB Controls.Add(button2)
label2 = New Label label2.Location = New Point(50, 200) label2.Size = new Size(200, 25) label2.Name = "label2" label2.TabIndex = 3 label2.Text = "" Controls.Add(label2)
button3 = New Button button3.Location = New Point(50, 250) button3.Size = new Size(200, 25) button3.Name = "button3" button3.TabIndex = 4 button3.Text = "Exit" AddHandler button3.Click, AddressOf ClickExit Controls.Add(button3)
ResumeLayout(false) End Sub Private Sub ClickA(o As Object, e As EventArgs) label1.Text = "Du har trykket A" End Sub Private Sub ClickB(o As Object, e As EventArgs) label1.Text = "Du har trykket B" End Sub Private Sub ClickExit(o As Object, e As EventArgs) Application.Exit Environment.Exit(0) End Sub End Class End Namespace
Jeg tror jeg har fundet ud af hvad problemet var. Det har noget en binding at gøre. F.eks. fungere følgende heller ikke pga.:
DataGrid1.SetDataBinding(DS, "AllData")
Men udmaskes den fungere det, men så får jeg bare ikke mit resultat på skærmen.. øv.
Imports System Imports System.IO Imports System.Net Imports System.Net.Sockets Imports System.Threading Imports System.Data Public Class Form1 Inherits System.Windows.Forms.Form #Region " Windows Form Designer generated code "
Public Sub New() MyBase.New()
'This call is required by the Windows Form Designer. InitializeComponent()
'Add any initialization after the InitializeComponent() call
End Sub
'Form overrides dispose to clean up the component list. Protected Overloads Overrides Sub Dispose(ByVal disposing As Boolean) If disposing Then If Not (components Is Nothing) Then components.Dispose() End If End If MyBase.Dispose(disposing) End Sub
'Required by the Windows Form Designer Private components As System.ComponentModel.IContainer
'NOTE: The following procedure is required by the Windows Form Designer 'It can be modified using the Windows Form Designer. 'Do not modify it using the code editor. Friend WithEvents Button1 As System.Windows.Forms.Button Friend WithEvents ListBox1 As System.Windows.Forms.ListBox Friend WithEvents Button2 As System.Windows.Forms.Button Friend WithEvents DataGrid1 As System.Windows.Forms.DataGrid Friend WithEvents Label1 As System.Windows.Forms.Label
Private Sub Button2_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles Button2.Click If Button2.BackColor.ToString = Color.Blue.ToString Then Button2.BackColor = Color.Red Else Button2.BackColor = Color.Blue End If End Sub Function CreateDataSet(ByVal TheDS As DataSet, ByVal TheDT As DataTable, ByVal TableName As String) Dim ds As DataSet = TheDS Dim dt As DataTable = TheDT Dim DC0 As New DataColumn("tal1") ' Create colums to the table Dim DC1 As New DataColumn("tal2") Dim DC2 As New DataColumn("tal3") Dim DC3 As New DataColumn("Kommentar") DC3.ColumnName = "Kommentar" dt.Columns.Add(DC0) ' Add the columns to the table dt.Columns.Add(DC1) dt.Columns.Add(DC2) dt.Columns.Add(DC3) ds.Tables.Add(dt) ' Add the table to the dataset Return ds End Function Public Class Listen Private server As TcpListener Private mainform As ListBox Private TheDataTable As DataTable Private MyDR As DataRow Public Sub New(ByVal srv As TcpListener, ByVal DT As DataTable, ByVal mf As ListBox) server = srv mainform = mf TheDataTable = DT End Sub Public Sub WaitForConnectAndAccept() While True Dim client As TcpClient = server.AcceptTcpClient Dim rdr As StreamReader = New StreamReader(client.GetStream) Dim line As String = rdr.ReadLine mainform.Items.Add(line) ' Add the data to the list
rdr.Close() client.Close() End While server.Stop() End Sub End Class
Private Sub Form1_Load(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles MyBase.Load Dim DS As DataSet = New DataSet("DSet") ' Make a dataset Dim DT As DataTable = New DataTable("AllData") ' Make a table DS = CreateDataSet(DS, DT, "AllData") ' -------- Udmaskes linien herunder virker det, men ikke med så fryser tråden ---- DataGrid1.SetDataBinding(DS, "AllData") '
Dim server As TcpListener = New TcpListener(IPAddress.Any, 1234) server.Start() Dim t As Listen = New Listen(server, DT, ListBox1) Call (New Thread(New ThreadStart(AddressOf t.WaitForConnectAndAccept))).Start()
End Sub Private Sub Form1_Closing(ByVal sender As Object, ByVal e As System.ComponentModel.CancelEventArgs) Handles MyBase.Closing Application.Exit() Environment.Exit(0) End Sub
Jeg er dig meget taknemlig og vil gerne give dig nogle flere point, hvis du kan hjælpe mig med dette problem.. Hvis du vil, hvad vil da være et passende antal points?
Det lader til at problemet opstår fordi at der oprettes noget nyt i tråden - i dette tilfælde en ny row - som så tilføjes DataGrid'en. Hvilket sker i linien:
Nix, det er først når row'en tilføjes tabellen at problemet opstår. TheDataTable.Rows.Add(MyDR) Men det er jo i og for sig også det bindingen sker. Jeg skal sikkert over i noget invoke/delegate for at undgå tilknytningen, men det kender jeg desværre ikke så meget til. Læste et sted at det måske kunne løses med invoke.
Jeg kan ikke forklare/forstå hvorfor den fryser når den tilføjer noget til en binding, og har - ind til videre - derfor valgt at fjerne det fra tråden og kun vente på data i tråden. Når tråden modtager data lukker den TCPClienten og stopper TCPListeren, hvorefter den starter en event som derved løser det som skal ske - altså tilføjer data i datagrid'en. Jeg opnår det ventede men forklare ikke problemet. Løsningen må vente... Jeg vil dog gerne give dig nogle point for tiden du har brugt...Jeg ved ikke hvor meget tid du har brugt og hvis jeg spørg dig vil du sikkert bare være for beskeden. At spørge dig om hvad du vil syntes ville være et passende antal point vil sikkert ende med samme resultat. Jeg har derfor lagt 30 point i http://www.eksperten.dk/spm/528479 og takker mange gange for din support.
Der må være et eller andet winforms threading issue.
Men jeg har ingen ide om hvordan det hænger sammen.
Synes godt om
Ny brugerNybegynder
Din løsning...
Tilladte BB-code-tags: [b]fed[/b] [i]kursiv[/i] [u]understreget[/u] Web- og emailadresser omdannes automatisk til links. Der sættes "nofollow" på alle links.