I have a server that handles multiple clients.
I have clients that send and receive data by click event.
I want that whenever a client sends data, the server spreads it out to the other clients.
How can I make my clients listen to the server all the time?
Private Sub Button1_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles Button1.Click
Dim serverStream As NetworkStream = clientSocket.GetStream()
Dim outStream As Byte() = System.Text.Encoding.ASCII.GetBytes(TextBox1.Text + "$")
serverStream.Write(outStream, 0, outStream.Length)
serverStream.Flush()
Dim inStream(10024) As Byte
serverStream.Read(inStream, 0, inStream.Length)
Dim returndata As String = System.Text.Encoding.ASCII.GetString(inStream)
msg("Data from Server : " + returndata)
End Sub
Related
On the Client I want to -
I want to send a screenimage from the client and receive a string with cursor coordinates in.
On the server I want to receive and display the screenimage on Form2
and then send back my cursor coordinates to the client.
I can successfully send text messages from the client and receive them on the server using this code -
Private Sub Button2_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles Button2.Click
senddata("CHAT|" & TextBox3.Text) 'send the data with CHAT| as header
TextBox4.Text &= "You: " & " " & TextBox3.Text.Split("|")(0) & vbNewLine
End Sub
Sub senddata(ByVal message As String)
Dim sw As New StreamWriter(t.GetStream) 'declare a new streamwriter
sw.WriteLine(message) 'write the message
sw.Flush()
End Sub
and receive it on the server with this code -
Imports System.IO
Imports System.Net.Sockets
Public Class ConnectedClient
Private cli As TcpClient 'decleare a tcp client which will be the client that we assign to an instance of this class
Private uniqueid As String 'this will be used for the name property
Public Property name ''This will be the name of the ID containing its Unique ID
Get
Return uniqueid 'when we want to get it, it will return the Unique ID
End Get
Set(ByVal value)
uniqueid = value 'Used for setting the name
End Set
End Property
Sub New(ByVal client As TcpClient)
Dim r As New Random 'create a new random to serve as way to create our unique ID
Dim x As String = String.Empty 'declare a new variable to hold the ID
For i = 0 To 7 'we are goign to have an ID of 7 randomly generated characters
x &= Chr(r.Next(65, 89)) 'create a generate dnumber between 65 and 89 and get the letter that has the same ascii value (A-Z)
' and add it onto the ID string
Next
Me.name = client.Client.RemoteEndPoint.ToString().Remove(client.Client.RemoteEndPoint.ToString().LastIndexOf(":")) & " - " & x 'set the name to the Unique ID
cli = client 'assign the client specified to the TCP client variable to we can operate with it
cli.GetStream.BeginRead(New Byte() {0}, 0, 0, AddressOf read, Nothing) 'start reading using the read subroutine
End Sub
Public Event gotmessage(ByVal message As String, ByVal client As ConnectedClient) 'this is raised when we get a message from the client
Public Event disconnected(ByVal client As ConnectedClient) 'this is raised when we get the client disconnects
Sub read(ByVal ar As IAsyncResult) 'this will process all messages being recieved
Try
Dim sr As New StreamReader(cli.GetStream) 'initialize a new streamreader which will read from the client's stream
Dim msg As String = sr.ReadLine() 'create a new variable which will be used to hold the message being read
RaiseEvent gotmessage(msg, Me) 'tell the server a message has been recieved. Me is passed as an argument which represents
' the current client which it has recieved the message from to perform any client specific
' tasks if needed
cli.GetStream.BeginRead(New Byte() {0}, 0, 0, AddressOf read, Nothing) 'continue reading from the stream
Catch ex As Exception
Try 'if an error occurs in the reading purpose, we will try to read again to see if we still can read
Dim sr As New StreamReader(cli.GetStream) 'initialize a new streamreader which will read from the client's stream
Dim msg As String = sr.ReadLine() 'create a new variable which will be used to hold the message being read
RaiseEvent gotmessage(msg, Me) 'tell the server a message has been recieved. Me is passed as an argument which represents
' the current client which it has recieved the message from to perform any client specific
' tasks if needed
cli.GetStream.BeginRead(New Byte() {0}, 0, 0, AddressOf read, Nothing) 'continue reading from the stream
Catch ' IF WE STILL CANNOT READ
RaiseEvent disconnected(Me) 'WE CAN ASSUME THE CLIENT HAS DISCONNECTED
End Try
End Try
End Sub
Sub senddata(ByVal message As String) 'this is used to deal with sending out messages
Dim sw As New StreamWriter(cli.GetStream) 'declare a new streamwrite to write to the stream between the client and the server
sw.WriteLine(message) 'write the message to the stream
sw.Flush()
End Sub
Sub listen(ByVal port As Integer)
Try
Dim t As New TcpListener(IPAddress.Any, port) 'declare a new tcplistener
t.Start() 'start the listener
Do
Dim client As New ConnectedClient(t.AcceptTcpClient) 'initialize a new connected client
AddHandler client.gotmessage, AddressOf recieved 'add the handler which will raise an event when a message is recieved
AddHandler client.disconnected, AddressOf disconnected 'add the handler which will raise an event when the client disconnects
Loop Until False
Catch
End Try
End Sub
In a totally different application I can successfully send the screen image from the client using this code
Imports System.Net.Sockets
Imports System.Threading
Imports System.Drawing
Imports System.Runtime.Serialization.Formatters.Binary
Public Class Form1
Dim client As New TcpClient
Dim ns As NetworkStream
Dim port As Integer
Dim server As TcpListener
Dim listening As New Thread(AddressOf Listen)
Dim GetImage As New Thread(AddressOf ReceiveCursor)
Private Sub Button1_Click_1(sender As Object, e As EventArgs) Handles btnConnect.Click
port = CInt(txtPort.Text)
Try
If btnConnect.Text = "Connect" Then
client.Connect(txtIP.Text, port)
'MsgBox("Client connected !")
Timer1.Start()
btnConnect.Text = "Disconnect"
Else
btnConnect.Text = "Connect"
Timer1.Stop()
End If
Catch ex As Exception
MsgBox("Failed to connect..." + ex.Message)
End Try
End Sub
Public Function Desktop() As Image
Dim bounds As Rectangle = Nothing
Dim screenshot As System.Drawing.Bitmap = Nothing
Dim graph As Graphics = Nothing
bounds = Screen.PrimaryScreen.Bounds
screenshot = New Bitmap(bounds.Width, bounds.Height, System.Drawing.Imaging.PixelFormat.Format32bppPArgb)
graph = Graphics.FromImage(screenshot)
graph.CopyFromScreen(bounds.X, bounds.Y, 0, 0, bounds.Size, CopyPixelOperation.SourceCopy)
Return screenshot
End Function
Private Sub SendDesktop()
Dim bf As New BinaryFormatter
ns = client.GetStream
bf.Serialize(ns, Desktop())
End Sub
Private Sub BtnShare_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles btnShare.Click
If btnShare.Text.StartsWith("Share") Then
Timer1.Start()
'port = Integer.Parse(Me.txtPort.Text)
'server = New TcpListener(port)
'listening.Start()
btnShare.Text = "Stop Sharing"
Else
Timer1.Stop()
btnShare.Text = "Share Desktop"
End If
End Sub
Private Sub Timer1_Tick(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles Timer1.Tick
SendDesktop()
' SetCursorPosition()
End Sub
Private Sub ReceiveCursor()
Dim bf As New BinaryFormatter
While client.Connected = True
ns = client.GetStream
txtCursorPosition.Text = bf.Deserialize(ns)
End While
End Sub
Private Sub Listen()
While client.Connected = False
server.Start()
client = server.AcceptTcpClient
End While
GetImage.Start()
End Sub
Public Sub StopListening()
GetImage.Abort()
server.Stop()
client = Nothing
If listening.IsAlive Then
listening.Abort()
End If
End Sub
End Class
and receive it on the server using this code -
Imports System.Net.Sockets
Imports System.Threading
Imports System.Drawing
Imports System.Runtime.Serialization.Formatters.Binary
Public Class Form2
Dim port As Integer
Dim client As New TcpClient
Dim ns As NetworkStream
Dim server As TcpListener
Dim listening As New Thread(AddressOf Listen)
Dim GetImage As New Thread(AddressOf ReceiveImage)
Private Sub Form2_Load(sender As Object, e As EventArgs) Handles MyBase.Load
'Start the timer, obtain the port and start listening
Timer1.Start()
port = Integer.Parse(Form1.txtPort.Text)
server = New TcpListener(port)
listening.Start()
End Sub
Private Sub ReceiveImage()
Dim bf As New BinaryFormatter
While client.Connected = True
ns = client.GetStream
PictureBox1.Image = bf.Deserialize(ns)
End While
End Sub
Private Sub Listen()
While client.Connected = False
server.Start()
client = server.AcceptTcpClient
End While
GetImage.Start()
End Sub
Public Sub StopListening()
GetImage.Abort()
server.Stop()
client = Nothing
If listening.IsAlive Then
listening.Abort()
End If
End Sub
End Class
Is there a way of doing both using the same connection and somehow detecting which is text and which is the screenimage?
I succeded creating a UDP client-server connection and sending a large image over it. I split and sent the image into packets of 1500 bytes each .I got at the other end 330025 bytes of 353723 (which I think is pretty good). But as you know UDP packets are not in order so I have to id every packet it's sent (I can't use tcp because I need speed for my project-game). Now I want to ask the 'server' for the missing packets.
This is the server's code:
Imports System
Imports System.IO
Imports System.Net
Imports System.Threading
Imports System.Net.Sockets
Imports System.Text.Encoding
Public Class Form1
Dim ep_client As New IPEndPoint(IPAddress.Parse("127.0.0.1"), 60000)
Dim ep_server As New IPEndPoint(IPAddress.Any, 60000)
Dim publisher As New UdpClient(ep_client)
Private Sub Form1_Load(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles MyBase.Load
Form2.Show()
End Sub
Private Sub Button1_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles Button1.Click
Dim sendbytes() As Byte = ASCII.GetBytes(txt1.Text)
Dim img As Image, img_stream As MemoryStream, buffer As Byte()
Dim packet_size As Integer = 1024, sent_size As Long
Try
img_stream = imgToBytes(txt1.Text)
Debug.Print(img_stream.Length)
ReDim buffer(packet_size)
While Not img_stream.Position = img_stream.Length
sent_size += img_stream.Read(buffer, 0, packet_size)
publisher.Send(buffer, buffer.Length)
End While
Debug.Print(100 * sent_size / img_stream.Length & "%")
Catch ex As Exception
Debug.Print(ex.Message)
End Try
End Sub
Private Sub Button2_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles Button2.Click
''When I press this button it is supposed to 'listen'
Try
'Silence...Nothing here..
publisher.BeginReceive(New AsyncCallback(AddressOf receive), publisher)
Debug.Print("listening")
Catch ex As Exception
Debug.Print(ex.Message)
End Try
End Sub
Sub receive(ByVal ar As IAsyncResult)
''It should take the packets from coming from 'any' ip.
publisher.EndReceive(ar, ep_server)
Debug.Print("received")
publisher.BeginReceive(New AsyncCallback(AddressOf receive), publisher)
End Sub
Function imgToBytes(ByVal file_name As String) As MemoryStream
Dim img As Image = Image.FromFile(file_name)
Dim stream As New MemoryStream
img.Save(stream, Drawing.Imaging.ImageFormat.Jpeg)
stream.Position = 0
Return stream
End Function
End Class
This is the code for the client(which becomes a server...):
Imports System
Imports System.IO
Imports System.Net
Imports System.Threading
Imports System.Net.Sockets
Imports System.Text.Encoding
Public Class Form2
Dim ep_server As IPEndPoint = New IPEndPoint(IPAddress.Any, 60000)
Dim ep_client As New IPEndPoint(IPAddress.Parse("127.0.0.1"), 60000)
Dim client As New UdpClient(ep_client)
Dim stream As New MemoryStream
Private Sub Form2_Load(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles MyBase.Load
Try
'I belive it's listening for packets comming from ep_client ->
'because I initialized the 'client' object with it
'How can I make it listen for ep_server?(from all ip's)
client.BeginReceive(New AsyncCallback(AddressOf receive), client)
Catch ex As Exception
Debug.Print(ex.Message)
End Try
End Sub
Public Sub receive(ByVal ar As IAsyncResult)
Dim buffer As Byte()
Try
'Now I use ep_server ->the proper way
buffer = client.EndReceive(ar, ep_server)
stream.Write(buffer, 0, buffer.Length)
client.BeginReceive(New AsyncCallback(AddressOf receive), client)
Catch ex As Exception
Debug.Print(ex.Message)
End Try
End Sub
Private Sub PictureBox1_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles PictureBox1.Click
Dim img As Image = Image.FromStream(stream)
Debug.Print(stream.Length)
PictureBox1.Image = img ''Weird image because the packets are not arranged
End Sub
Private Sub Button1_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles Button1.Click
Debug.Print("sent")
client.Send(ASCII.GetBytes("a"), 1, ep_client) ''Send something ->not working
End Sub
End Class
No error..nothing. I can send a picture from server to client but not the other way around. And there's another weird thing. I've put the client's code on another machine...It's gives an error when I write the ipv4(of the other machine) in ep_client like this Dim ep_client As New IPEndPoint(IPAddress.Parse("192.168.1.100"), 60000). I get no error. And if I initialize both of the 'udp-clients' on server and client code like this : Dim client as new UdpClient(ep_client) it gives an error :
Only one usage of each socket address (protocol/network address/port)
is normally permitted
But if I write it like this (on the server side) Dim client as new UdpClient("127.0.0.1",60000) it gives no error.What's the difference?
Where is the problem?
Your immediate problem is you can only have one Socket bound to a port number on one machine at any given time - so there must already be something bound to port 60000 to give you the "Only one usage of each socket address..." Exception - perhaps another instance of your program is already running?
Aside, and I am a game developer and understand the need to use UDP, UDP is not a good choice here instead of TCP. UDP is good for small "real-time" data not large one-off data. If using UDP you have to worry about: reliability - the datagram may not get through at all, duplicates - the datagram may be duplicate, congestion control - sending too many datagrams in quick succession without checking previous ones are getting through will just result in them being dropped... Really sending a large file is much better suited to TCP.
Private Sub Button1_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles Button1.Click
Dim card As New GemCard
If card.ReadCard Then
Dim aFileStream As FileStream
aFileStream = New FileStream(Application.StartupPath + "photo.j2k", FileMode.OpenOrCreate, FileAccess.Write)
Dim myBinaryWriter As New BinaryWriter(aFileStream)
myBinaryWriter.Write(card.CivilIDApp.Photo("PHOTO").BinValue)
myBinaryWriter.Close()
Call ImageLoad()
Photo.ImageLocation = Application.StartupPath + "photo.jpg"
End If
Button2.Enabled = True
End Sub
I am trying to send a file through tcp connection in vb.net via byte array.
How do I convert the byte array back to the file and save it using savefiledialog?
The code I use to convert the file to byte array and send it is:
Private Sub btnfSend_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles btnfSend.Click
browseFile.Title = "Browse Files"
browseFile.InitialDirectory = "C:\Users\LF\Desktop"
browseFile.ShowDialog()
End Sub
Private Sub browseFile_FileOk(ByVal sender As System.Object, ByVal e As System.ComponentModel.CancelEventArgs) Handles browseFile.FileOk
If ((lblStatus.Text = "Status: Receiving") Or (lblStatus.Text = "Status: Connected")) Then
Dim strm As System.IO.Stream
strm = browseFile.OpenFile()
Dim fileDir As String
fileDir = browseFile.FileName.ToString()
Dim fInfo As New FileInfo(fileDir)
Dim numBytes As Long = fInfo.Length
Dim fStream As New FileStream(fileDir, FileMode.Open, FileAccess.Read)
Dim br As New BinaryReader(fStream)
Dim data As Byte() = br.ReadBytes(CInt(numBytes))
ChatSocket.SendTo(data, SocketFlags.None, New IPEndPoint(IPAddress.Parse(txtRemoteIP.Text), CInt(Val(txtRemotePort.Text))))
br.Close()
fStream.Close()
End If
End Sub
I have the Manual of Programming protocol, but when I write code vb.net returns error message.
The following is the table structure of bytes array
position 1 2 3 4 5 6 7 8
Name SOH LEN SEQ CMD DATA Post-amble BCC ETX
Lenth/bytes 1 1 1 1 0-200 1 4 1
Value (01h) (20h-FFh) (20h-FFh) (20h-FFh) (20h-FFh) (05h) (30h-3Fh) (03h)
Abbreviations:
“SOH”- (Start Of Heading) start of packed message
“LEN”- total number of bytes from position 2 to position 6, plus fixed offset of 20h.
“SEQ”- serial number of packet. SLAVE puts the same “SEQ” in the reply message. In case when SLAVE
receives a message with the same “SEQ”and “CMD” like the last correctly received message, the device ignores
the message and repeats the last packet sent to the HOST.
“CMD” – code of command
“DATA”- data, according to the command. If there is no data, the length field is zero.
“BCC” – control sum(0000h-FFFFh). Sum of data bytes from position 2 to position 6. The control sum is
transferred in ASCІІ type (12АВ is transferred as 31h 32h 3Аh 3Вh).
“ETX” – (End of TeXt) end of packed message.
Codes sample:
Public Class Form1
Private WithEvents sp As System.IO.Ports.SerialPort
Private Sub Form1_Load(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles MyBase.Load
For Each y As String In System.IO.Ports.SerialPort.GetPortNames
Me.ComboBox1.Items.Add(y)
Next
sp = New IO.Ports.SerialPort("COM4")
sp.StopBits = IO.Ports.StopBits.One
sp.BaudRate = 9600
sp.DataBits = 8
sp.Parity = IO.Ports.Parity.None
sp.Handshake = IO.Ports.Handshake.None
sp.Open()
Dim by As Byte = &H20
' MsgBox(&H20)
End Sub
Private Sub Button1_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles Button1.Click
Try
Dim By(9) As Byte
By(0) = 1
By(1) = &H2 + &H20
By(2) = &H58
By(3) = &H45
By(4) = &H5
Dim S As String = Hex(&H58 Xor &H45)
' MsgBox(S)
By(5) = &H30
By(6) = &H30
By(7) = &H31
By(8) = &H3D
By(9) = &H3
sp.Write(By, 0, By.Length - 1)
' MsgBox(sp.ReadByte)
Catch ex As Exception
MsgBox(ex.Message)
End Try
End Sub
Private Sub sp_DataReceived(ByVal sender As Object, ByVal e As System.IO.Ports.SerialDataReceivedEventArgs) Handles sp.DataReceived
Dim rec As System.IO.Ports.SerialPort = sender
MsgBox(Hex(rec.ReadByte))
End Sub
End Class
Annael you could probably do this, by invoking an updating function and giving a delay of 500ms will make a difference. Now on receiving data you can receive input data
Dim inputData As String = ""// Declare this as a global variable in the program
Private WithEvents sp As System.IO.Ports.SerialPort
Private Sub Form1_Load(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles MyBase.Load
For Each y As String In System.IO.Ports.SerialPort.GetPortNames
Me.ComboBox1.Items.Add(y)//the code you have written to add Serial ports
SerialPort1.PortName = ComboBox1.Text//this will access your com port as your button
Private Sub Button1_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles Button1.Click
Dim by As Byte = &H20
By(0) = 1
By(1) = &H2 + &H20
By(2) = &H58
By(3) = &H45
By(4) = &H5
Dim S As String = Hex(&H58 Xor &H45)
' MsgBox(S)
By(5) = &H30
By(6) = &H30
By(7) = &H31
By(8) = &H3D
By(9) = &H3
SerialPort1.BaudRate = 115200
SerialPort1.Open()
SerialPort1.Write(By)
Private Sub SerialPort1_DataReceived(sender As System.Object, e As System.IO.Ports.SerialDataReceivedEventArgs) Handles SerialPort1.DataReceived
Threading.Thread.Sleep(500) ' 500ms delay induced to receive the email
inputData = SerialPort1.ReadExisting 'or SerialPort1.ReadLine
Me.Invoke(New EventHandler(AddressOf DoUpdate))
Public Sub DoUpdate()
MsgBox(inputData)