I'm realizing a .NET chat application but i still have that error:
I can send only a message per connection.
For example. With the code below, i can send only one message that can be received correctly by the other peer, but if i send another message message, on the same connection,it won't be received by the remote PC.
Here is the code:
Dim client_TCP As New TcpClient
Private Sub send_obj(ByVal obj As Object)
Dim bf As New BinaryFormatter
Dim tosend As Packet
tosend.data = obj
bf.Serialize(client_TCP.GetStream(), tosend)
client_TCP.GetStream.Flush()
End Sub
Private Sub connect_to_port()
Try
client_TCP = New TcpClient(client_data.getIP(), client_data.getPort())
Catch ex As Exception
MsgBox(ex.Message)
End Try
End Sub
Private Sub disconnect_from_port()
client_TCP.Close()
End Sub
And here is the listener:
Private Sub Timer_Tick(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles timer.Tick
If client_TCP_listener.Pending = True Then
....
End If
End Sub
So, to send a message I always need to do this (example):
Dim b As Byte
b = 1
disconnect_from_port()
connect_to_port()
client_TCP.GetStream().WriteByte(b)
client_TCP.GetStream().Flush()
I tried to put\remove the flush from both the code. Nothing happened.
Have you got any ideas?!
How do you know that it is not received? Did you try emulating remote host with your own code?
TCP is a stream protocol that means that you can send two bytes doing two separate calls to client_TCP.GetStream().WriteByte(b) and the remote party can receive those 2 bytes using one Receive call. You should not make any assumptions on the I/O API call patterns (number of writes and number of receives) but analyze the data you're sending receiving via stream connection.
So to send messages using stream protocol you have to introduce the notion of the application protocol. For instance [2bytes-size][size-bytes of message] - which means that if we want to send "hello" message we at first will send 2 bytes containing the size of the "hello" string and then the string itself.
make sure that receiving end is also using .net BinaryFormatter for deserlizing the object.
Related
I'm trying to build a simple Windows Forms app in VB.net (.net Framework 2.0 in order to support Windows XP) which allows multiple client PCs to send short text strings as UDP messages to a listening "server".
The "server" part must listen asynchronously and display the received text from each client as it arrives.
My code can't use the newer ReceiveAsync() function because it must support XP and thus must be built on .net Framework 2.0, which doesn't support these Async functions, so I'm using the BeginReceive() function and passing a callback.
It works perfectly for the first incoming UDP message, but the problem is that no additional messages are received. Even if I send the same message twice, nothing is output after receiving the first incoming message. It's as if the listener ignores anything after the first message, or as if it's hung in an incorrect state. Is there some sort of "reset" procedure that must be performed on the UDP listener after each incoming message in order that it will listen for further incoming data? (Note: no exceptions are raised)
Here's my listener code:
Private Sub btnListen_Click(sender As Object, e As EventArgs) Handles btnListen.Click
Dim state As New UdpState
listener = New UdpClient(CInt(txtListenPort.Text)) ' Create UDP client on specified port (all interfaces)
'Async receive data:
Dim ip As System.Net.IPAddress = System.Net.Dns.GetHostEntry("localhost").AddressList(0)
state.udpClient = listener
state.ipEndPoint = New Net.IPEndPoint(ip, CInt(txtListenPort.Text))
Dim callback As AsyncCallback
callback = AddressOf rx
listener.BeginReceive(callback, state)
lblListenStatus.Text = "Listening..."
End Sub
Shared Sub rx(result As IAsyncResult)
Dim r As UdpState = result.AsyncState
Dim endpt As System.Net.IPEndPoint = r.ipEndPoint
Dim client As UdpClient = r.udpClient
Dim bytes() As Byte
bytes = client.EndReceive(result, endpt)
Dim s As String = System.Text.Encoding.ASCII.GetString(bytes)
Debug.Print("Received string = " & s)
End Sub
Private Class UdpState
Public ipEndPoint As System.Net.IPEndPoint
Public udpClient As System.Net.Sockets.UdpClient
End Class
And here's the code I'm using to send data to this socket endpoint:
Private Sub btnSend_Click(sender As Object, e As EventArgs) Handles btnSend.Click
Dim send As New UdpClient
Dim s As String = txtSendMessage.Text
Dim b_len As Integer = System.Text.Encoding.ASCII.GetByteCount(s)
Dim b() As Byte
ReDim b(b_len)
b = System.Text.Encoding.ASCII.GetBytes(s) 'Convert text to bytes.
send.Send(b, b_len, txtSendIP.Text, CInt(txtSendPort.Text)) 'Blocking SEND.
send.Close()
End Sub
Note that I'm testing sending from localhost to itself - not even sending over the network.
Thanks for any insight.
I've written a Windows-based TCP server program based on some VB code I found on the internet several years ago (I can't find the link now, but it was called "multi-client server program" or something like that).
The server communicates with a couple of Enterprise iPhone client apps that I have also developed. I've successfully incorporated this code into two separate server programs that work just fine on both the development server and the production server. I'm working on a third iOS client application and a corresponding server program, which works fine on the development machine, but will not work on the production server -- the same machine that hosts the other two server programs with no problem.
It was working for a while, but as I have added more functionality to the server class, it seems to have stopped processing the incoming data, but only on the production machine.
The code that performs the connection functions is contained in a separate public class which is supposed to communicate with the Windows form that processes the incoming data. Using msgbox's for debugging tools, I have been able to confirm that the Client Connection class is connecting and is receiving the data, but it for some reason will not communicate that data with the Windows form.
My only thought is that it must be a threading issue, but I am not sure, and I have no idea how to find out.
To recap, just to be clear:
The code works fine on the development server, but not on the production server.
The client connection class is identical in every way with the other two working server programs.
That the client is communicating with the client connection class has been confirmed. The incoming data can be captured inside the connection class and displayed in msgbox's, so the data is getting through.
The Windows class that processes the incoming data is not receiving the data from the public client connection class.
EDIT: I should have included this in the original post: The development server is Win 7; the production sever is Windows Server 2012.
Because of the complexity of this code, I am not sure what snippets would be applicable for this, but I'll do my best to include what makes most sense to me here.
This is the entirety of the client connection class with the exception of the method that sends outgoing data. Again, this was copied from a website several years ago, and the comments are those of the original developer:
Imports System.IO
Imports System.Net.Sockets
Imports System.Data.SqlClient
Public Class ConnectedClient
Private cli As TcpClient 'declare 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
Dim strErrorLogPath As String
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 going 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 the client disconnects
Sub read(ByVal ar As IAsyncResult) 'this will process all messages being received
'bn-note: This is the entry point of the data being received from the client.
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
If msg = "" Then
RaiseEvent disconnected(Me) 'WE CAN ASSUME THE CLIENT HAS DISCONNECTED
Exit Try
'msg = "Null Message"
End If
WriteToRawIncomingDataLog(msg)
RaiseEvent gotmessage(msg, Me) 'tell the server a message has been received. Me is passed as an argument which represents
' the current client which it has received 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
'End Ifz
'Catch ex As System.NullReferenceException
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
WriteToRawIncomingDataLog(msg)
RaiseEvent gotmessage(msg, Me) 'tell the server a message has been received. Me is passed as an argument which represents
' the current client which it has received 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
'End If
'Catch ex2 As System.NullReferenceException
' Stop
Catch ' IF WE STILL CANNOT READ
RaiseEvent disconnected(Me) 'WE CAN ASSUME THE CLIENT HAS DISCONNECTED
End Try
End Try
End Sub
Here is the Windows form code that processes the incoming data:
Private Sub formMain_Load(sender As Object, e As System.EventArgs) Handles Me.Load
Try
Dim listener As New System.Threading.Thread(AddressOf listen) 'initialize a new thread for the listener so our GUI doesn't lag
listener.IsBackground = True
listener.Start(CInt(IncomingPortString)) 'start the listener, with the port specified as a parameter (textbox1 is our port textbox)
Catch ex As Exception
txtSystemMessages_AddText(String.Format("Error in formMain_Load sub: {0}{1}", ex.Message.ToString, vbNewLine))
End Try
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 received 'add the handler which will raise an event when a message is received
AddHandler client.disconnected, AddressOf disconnected 'add the handler which will raise an event when the client disconnects
Loop Until False
Catch ex As Exception
txtSystemMessages_AddText(String.Format("Error in Listen sub: {1}{2}", ex.Message.ToString, vbNewLine))
End Try
End Sub
Sub received(ByVal msg As String, ByVal client As ConnectedClient)
Try
If Not clients.ContainsKey(client) Then
clients.Add(client, client.name.ToString) 'add the client to our hashtable
End If
Catch ex As ArgumentException
End Try
(The sub that processes the incoming data string "msg".)
End Sub
I'm at a complete loss to know what could be causing this issue, and a threading issue is all that I can think of. Could a different machine have different threading schemes? Any help would be greatly appreciated.
i am trying to establish connection between calamp lmu (gps tracking device) and my server.
i am using following code to send and receive data.
i am using timer1 to receive data from device
Private Sub Timer1_Tick(sender As Object, e As EventArgs) Handles Timer1.Tick
Try
Dim receiveBytes As [Byte]() = receivingUdpClient.Receive(remoteEP)
Dim returnData As String = BitConverter.ToString(receiveBytes)
txtLog.Text &= returnData.ToString & vbCrLf
Dim rep As New IPEndPoint(remoteEP.Address, C_DEVICE_LISTNING_PORT)
sktSocket = New Socket(AddressFamily.InterNetwork, SocketType.Dgram, ProtocolType.Udp)
sktSocket.Connect(remoteEP.Address, 20510)
sktSocket.SendTimeout = 100
'Dim udc As New UdpClient
'udc.Send(sendBytes, sendBytes.Length, rep)
'receivingUdpClient.Client.Send(sendBytes)
Catch ex As Exception
End Try
End Sub
following two variables are class level:
Dim remoteEP As New IPEndPoint(IPAddress.Any, 0)
Dim sktSocket As Socket
i am using following code to send data to device:
Private Sub butSend_Click(sender As Object, e As EventArgs) Handles butSend.Click
Dim sendBytes() As Byte = Encoding.ASCII.GetBytes(txtCommand.Text)
sktSocket.Send(sendBytes)
End Sub
my code to receive data works fine. when device sends data timer1 displays it in a textbox. But when i send data to the ip address returned by receivingUdpClient.Receive, it does not reach to the device. however wireshark shows that data has been sent.
any help will be appriciated.
i solved my problem myself. actually nothing was wrong in the code. actually i was connecting the device using forwarded port. it was hindering inward traffic from device to my system. Assigning static ip direct to my system solved the problem.
So I'm trying to make a very simple system to send messages from a client to a server (and later on from server to client as well, but baby steps first). I'm not sure exactly how to use UDPClient to send and receive messages (especially to receive them), mostly because I don't have anything triggering the ReceiveMessage() function and I'm not sure what would.
Source Code is at this link, go to File>Download. It is already built if you want to just run the exe.
So my question is basically: How can I easily use UDPClient, how can I get this system to work and what are some tips for executing this kind of connection? Anything I should watch out for (threading, issues with code,etc)?
Source.
You need first need to set up two UdpClients. One client for listening and the other for sending data. (You'll also need to pick a free/unused port number and know the IP address of your target - the machine you want to send data to.)
To set up the receiver,
Instantiate your UdpClient variable with the port number you chose earlier,
Create a new thread to avoid blocking while receiving data,
Loop over the client's receive method for as long as you want to receive data (the loop's execution should be within the new thread),
When you receive one lot of data (called a "packet") you may need to convert the byte array to something more meaningful,
Create a way to exit the loop when you want to finish receiving data.
To set up the sender,
Instantiate your UdpClient variable with the port number you chose earlier (you may want to enable the ability to send broadcast packets. This allows you to send data to all listeners on your LAN),
When you need to transmit data, convert the data to a byte array and then call Send().
I'd suggest that you have a quick skim read through this.
Here's some code to get you started off...
'''''''''''''''''''''''Set up variables''''''''''''''''''''
Private Const port As Integer = 9653 'Port number to send/recieve data on
Private Const broadcastAddress As String = "255.255.255.255" 'Sends data to all LOCAL listening clients, to send data over WAN you'll need to enter a public (external) IP address of the other client
Private receivingClient As UdpClient 'Client for handling incoming data
Private sendingClient As UdpClient 'Client for sending data
Private receivingThread As Thread 'Create a separate thread to listen for incoming data, helps to prevent the form from freezing up
Private closing As Boolean = False 'Used to close clients if form is closing
''''''''''''''''''''Initialize listening & sending subs'''''''''''''''''
Private Sub Form1_Load(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles Me.Load
InitializeSender() 'Initializes startup of sender client
InitializeReceiver() 'Starts listening for incoming data
End Sub
''''''''''''''''''''Setup sender client'''''''''''''''''
Private Sub InitializeSender()
sendingClient = New UdpClient(broadcastAddress, port)
sendingClient.EnableBroadcast = True
End Sub
'''''''''''''''''''''Setup receiving client'''''''''''''
Private Sub InitializeReceiver()
receivingClient = New UdpClient(port)
Dim start As ThreadStart = New ThreadStart(AddressOf Receiver)
receivingThread = New Thread(start)
receivingThread.IsBackground = True
receivingThread.Start()
End Sub
'''''''''''''''''''Send data if send button is clicked'''''''''''''''''''
Private Sub sendBut_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles sendBut.Click
Dim toSend As String = tbSend.Text 'tbSend is a textbox, replace it with whatever you want to send as a string
Dim data() As Byte = Encoding.ASCII.GetBytes(toSend)'Convert string to bytes
sendingClient.Send(data, data.Length) 'Send bytes
End Sub
'''''''''''''''''''''Start receiving loop'''''''''''''''''''''''
Private Sub Receiver()
Dim endPoint As IPEndPoint = New IPEndPoint(IPAddress.Any, port) 'Listen for incoming data from any IP address on the specified port (I personally select 9653)
While (True) 'Setup an infinite loop
Dim data() As Byte 'Buffer for storing incoming bytes
data = receivingClient.Receive(endPoint) 'Receive incoming bytes
Dim message As String = Encoding.ASCII.GetString(data) 'Convert bytes back to string
If closing = True Then 'Exit sub if form is closing
Exit Sub
End If
End While
End Sub
'''''''''''''''''''Close clients if form closes''''''''''''''''''
Private Sub Form1_FormClosing(sender As Object, e As FormClosingEventArgs) Handles Me.FormClosing
closing = True 'Tells receiving loop to close
receivingClient.Close()
sendingClient.Close()
End Sub
Here are a few other exmples: Here, here, here and here.
Imports System.Threading
Shared client As UdpClient
Shared receivePoint As IPEndPoint
client = New UdpClient(2828) 'Port
receivePoint = New IPEndPoint(New IPAddress(0), 0)
Dim readThread As Thread = New Thread(New ThreadStart(AddressOf WaitForPackets))
readThread.Start()
Public Shared Sub WaitForPackets()
While True
Dim data As Byte() = client.Receive(receivePoint)
Console.WriteLine("=" + System.Text.Encoding.ASCII.GetString(data))
End While
End Sub
I'm writing an app that sends messages over a network to another PC that processes the message and sends back a reply (e.g. a boolean or some other data). My network communication subs (based on WCF) just give me the ability to send a message to the other PC and process any received messages.
The issue is that any response received is processed by my designated network message event handler sub, but I have no way of feeding it back to the sub that called for the original message to be sent.
To quickly illustrate, the situation is something like this:
Private Function NetSendMessage(ByVal message As String) As Boolean
'Send network message to PC with device connected
'....
'returns true if message sent
End Function
Private Sub NetMessageReceived(ByVal sender As Object, ByVal e As MessageEventArgs) Handles NetComm.OnReceiveMessage
'Handles incoming messages
'....
End Sub
Private Function MoveForward() As Boolean
Return (MoveLeftWheel() And MoveRightWheel())
End Function
Private Function MoveLeftWheel() As Boolean
If NetSendMessage("MoveLeftWheel") = False Then Return False
'Network message went through, now we need to know if the command was executed, which the remote PC will tell us
Return ______ *(here is the trouble-- how do I get the boolean response from the other side as to whether this worked or not?)*
End Function
Private Function MoveRightWheel() As Boolean
If NetSendMessage("MoveRightWheel") = False Then Return False
Return ______
End Function
The solutions I've thought of so far are more complex than this probably needs to be.
One idea I had was to add an ID number to identify each message (which the other side would include in its response), and then I'd have an ArrayList for a "message queue." The NetMessageReceived sub would add any new message to this ArrayList, and any function that wants a reply would monitor the queue to see if its response arrived. It'd be something like this:
Private NetMessageQueue as New ArrayList
Private LatestMessageID as Integer
Private Sub NetMessageReceived(ByVal sender As Object, ByVal e As MessageEventArgs) Handles NetComm.OnReceiveMessage
'Handles incoming messages
NetMessageQueue.Add(e.Message.ToString)
End Sub
Private Function MoveLeftWheel() As Boolean
'Send network message to robot PC
Private MyMessageID as Integer = LatestMessageID + 1
NetSendMessage(MyMessageID & "|" & "MoveLeftWheel")
Do
For Each msg As String in NetMessageQueue
If msg.Split("|")(0) = MyMessageID.ToString Then
'This is the response message we're waiting for
Return Boolean.Parse(msg.Split("|")(1))
End If
Next
Loop
End Function
This seems like a very cumbersome / unnecessarily taxing way to do this. I was thinking along the lines of maybe add a NetSendReceive function that, say, MoveRightWheel could call; NetSendReceive would call NetSendMessage, monitor the message queue for its response (perhaps via a delegate/IAsyncResult), and then return the response message (to MoveRightWheel, which would be waiting for it).
There's probably a better way to do this- any ideas?
What if you wrap all of this in a class? Then the idea would be that you'd only have one "NetComm" object in each instance. Say you call the class MessagingUtility. And whenever you want to send a new message you'll have to call
Dim myMessage As New MessagingUtility()
myMessage.NetSendMessage("Hello World")
Or something like that.
This will prevent any possibility of you losing track of the context of a message when a lot of other messages are being sent around the same time. Because after all, every property of a given message you'll ever want will be contained neatly in the myMessage object.