On my Xamarin.Android app I'm sending udp broadcast message to find my servers on the local LAN.
My servers then return the MachineName they run on which I display in a ListView on my app in the form of
<MachineName> - <Ip address>
This all works well on the first time, however from the second time on all it reads is empty bytes.
The number of bytes it reads is correct but they are all zero.
Here is the code:
private static void ListenForBroadcastResponses()
{
udp.BeginReceive(OnBroadcastResponse, new object());
}
private static void OnBroadcastResponse(IAsyncResult ar)
{
// Recieve the message
IPEndPoint ip = new IPEndPoint(IPAddress.Any, port);
byte[] bytes = udp.EndReceive(ar, ref ip);
// Decode it
string message = Encoding.ASCII.GetString(bytes);
// If message is the awaited message from client or from the awaited port
if (ip.Port == port) //|| message == BRDCAST_ANSWER)
{
// Raise server found event
var handler = ServerFound;
if (handler != null)
handler(null, new ServerEventArgs
{
Server = new Server(message, ip.Address)
});
}
// Start listening again
ListenForBroadcastResponses();
}
Debug screenshots:
First time full bytes are recieved:
Second time and on bytes are empty:
What is wrong here?
Eventually I figured it out. It seems to be a bug caused by multiple threads trying to listen simultaneously (see this post) to replies so I'll post my solution:
I've added a RecieveTimeout of X seconds to the UdpClient.
Upon timeout, I execute an EndRecieve and Close method calls.
This will trigger the callback passed in BeginRecieve to execute so I've added a check to the callback method if the client is still open
if (udp.Client != null) ...
It fixed things for me, so hopefully it will help others
Related
I have a static method
public class TelnetClient
{
public static string SendAndReceiveData2(string data, string HostIPAddress, int Port)
{
using (Socket socket = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp))
{
socket.Connect(HostIPAddress, Port);
byte[] bytesToSend = Encoding.ASCII.GetBytes(data);
socket.ReceiveTimeout = 3000;
socket.SendTimeout = 3000;
int bytesSent = socket.Send(bytesToSend);
if (bytesSent != bytesToSend.Length)
{
throw new Exception("Invalid send byte number");
}
byte[] bytesReceiveBuffer = new byte[1024];
int bytesRec = socket.Receive(bytesReceiveBuffer); //No need to loop for testing
string returnedData = Encoding.ASCII.GetString(bytesReceiveBuffer, 0, bytesRec);
socket.Close(); // Just out of desperation
socket.Dispose();
return returnedData;
}
}
}
and this is how I am calling it:
for (int i = 0; i < 10; i++)
{
TelnetClient.SendAndReceiveData2("some data different each time", "127.0.0.1", 1234);
}
I am calling this method in a loop. This methods sends some commands to a third party application which returns a response immediately. The issue is that this code works for the first iteration but on the second iteration, it fails at socket.Receive with error:
A connection attempt failed because the connected party did not
properly respond after a period of time, or the established connection
failed because the connected host has failed to respond.
Here is the tricky part, If instead of looping multiple times, I close the exe and start again through command prompt, I don't get the error and also the third party app receives multiple requests as well.
This led me to believe that somehow the socket is not getting disposed properly in the loop. But if I close the process and start again, it has no problem.
I have checked that the socket.LocalEndPoint points to different port each time. Also socket.Available is set to 0 on second iteration.
I am not really sure what is going on, and would appreciate any help.
I notice that you are doing a Socket.Connect, but never doing a Socket.Disconnect.
From the MSDN website Socket.Disconnect will allow reuse of the socket and close the connection.
There is nothing wrong with the Socket and Socket disposal. The error message was bit misleading. The issue was at the server end.
More details....
Invalid data was being sent on the second iteration, when I tried sending exactly same data as the first iteration, it failed as well, because for each requests the server required a unique Guid id. That Guid was being generated outside the loop and hence it was used for all the items in the iteration. Restarting the process was working, because then I would get a new Guid for the first iteration.
I'm writing an application for windows phone and I need to communicate with a server and transmit data. The SERVER is written in C++ and I cannot modify it. The CLIENT is what I have to write. The Server is designed such that the client connect to it and transmit data. The connection remains open for all the transmission. By writing my code in C# I am able to receive data from the server but after the first receive, the data that I read in the buffer are alway the same. So I need a way to flush the input buffer so I can receive the new data (data are sent continuously). I'm using the class defined in here:
http://msdn.microsoft.com/en-us/library/windowsphone/develop/hh202858%28v=vs.105%29.aspx
thanks a lot !!
I used this code for Receiving in the SocketClient.cs :
public string Receive()
{
string response = "Operation Timeout";
// We are receiving over an established socket connection
if (_socket != null)
{
// Create SocketAsyncEventArgs context object
SocketAsyncEventArgs socketEventArg = new SocketAsyncEventArgs();
socketEventArg.RemoteEndPoint = _socket.RemoteEndPoint;
// Setup the buffer to receive the data
socketEventArg.SetBuffer(new Byte[MAX_BUFFER_SIZE], 0, MAX_BUFFER_SIZE);
// Inline event handler for the Completed event.
// Note: This even handler was implemented inline in order to make
// this method self-contained.
socketEventArg.Completed += new EventHandler<SocketAsyncEventArgs>(delegate(object s, SocketAsyncEventArgs e)
{
if (e.SocketError == SocketError.Success)
{
// *********************************************
// THIS part of the code was added to receive
// a vector of 3 double
Double[] OdomD = new Double[3];
for (int i = 0; i < 3; i++)
{
OdomD[i] = BitConverter.ToDouble(e.Buffer, 8 * i);
}
// *********************************************
}
else
{
response = e.SocketError.ToString();
}
_clientDone.Set();
});
// Sets the state of the event to nonsignaled, causing threads to block
_clientDone.Reset();
// Make an asynchronous Receive request over the socket
_socket.ReceiveAsync(socketEventArg);
// Block the UI thread for a maximum of TIMEOUT_MILLISECONDS milliseconds.
// If no response comes back within this time then proceed
_clientDone.WaitOne(TIMEOUT_MILLISECONDS);
}
else
{
response = "Socket is not initialized";
}
return response;
}
The Connect() method is exactly the same reported in the link above. So when the application start, the Connect() method is called as follow:
SocketClient client = new SocketClient();
// Attempt to connect to server for receiving data
Log(String.Format("Connecting to server '{0}' over port {1} (data) ...", txtRemoteHost.Text, 4444), true);
result = client.Connect(txtRemoteHost.Text, 4444);
Log(result, false);
That is done just once at the beginning, then I need receive this array of 3 double that is updated every second. So I use:
Log("Requesting Receive ...", true);
result = client.Receive();
Log(result, false);
The problem is that also if I debug the code and stop the execution inside Receive(), I always read the same value, that is the first value sent by the server. What I'm expecting is that every time I call client.Receive(), I get the new value, but this is not appening.
I had a similar problem by writing the same client in Matlab environment. I solved the problem by using the function flushinput(t) before to read the input buffer. In this way I was able to read always the last data sent by the server. I'm lookin for a function similar to that one ..
The size of the input buffer is fixed equal to the data that I'm expecting to receive, in that case is 24 bytes ( 3* sizeof(double) ) ..
Thanks a lot for you time !!
oleksii is right, you should call client.Receive() in a loop. You can choose to start a thread that covers the receive section of your code. Also note that client.Receive() will keep trying to receive from the buffer, and it will get stuck if there is no data available.
The main question was **how to clear the input buffer? ** or am I wrong?=!
Nevertheless; since you don't have a fixed buffer denoted as seen from you posted code and receive it via the SocketAsyncEventArgs, you could clear it with:
Array.Clear(e.Buffer, 0, e.Buffer.Length);
I had never used UDP before, so I gave it a go. To see what would happen, I had the 'server' send data every half a second, and the client receive data every 3 seconds. So even though the server is sending data much faster than the client can receive, the client still receives it all neatly one by one.
Can anyone explain why/how this happens? Where is the data buffered exactly?
Send
class CSimpleSend
{
CSomeObjServer obj = new CSomeObjServer();
public CSimpleSend()
{
obj.changedVar = varUpdated;
obj.threadedChangeSomeVar();
}
private void varUpdated(int var)
{
string send = var.ToString();
byte[] packetData = System.Text.UTF8Encoding.UTF8.GetBytes(send);
string ip = "127.0.0.1";
int port = 11000;
IPEndPoint ep = new IPEndPoint(IPAddress.Parse(ip), port);
Socket client = new Socket(AddressFamily.InterNetwork, SocketType.Dgram, ProtocolType.Udp);
client.SendTo(packetData, ep);
Console.WriteLine("Sent Message: " + send);
Thread.Sleep(100);
}
}
All CSomeObjServer does is increment an integer by one every half second
Receive
class CSimpleReceive
{
CSomeObjClient obj = new CSomeObjClient();
public Action<string> showMessage;
Int32 port = 11000;
UdpClient udpClient;
public CSimpleReceive()
{
udpClient = new UdpClient(port);
showMessage = Console.WriteLine;
Thread t = new Thread(() => ReceiveMessage());
t.Start();
}
private void ReceiveMessage()
{
while (true)
{
//Thread.Sleep(1000);
IPEndPoint remoteIPEndPoint = new IPEndPoint(IPAddress.Any, port);
byte[] content = udpClient.Receive(ref remoteIPEndPoint);
if (content.Length > 0)
{
string message = Encoding.UTF8.GetString(content);
if (showMessage != null)
showMessage("Recv:" + message);
int var_out = -1;
bool succ = Int32.TryParse(message, out var_out);
if (succ)
{
obj.alterSomeVar(var_out);
Console.WriteLine("Altered var to :" + var_out);
}
}
Thread.Sleep(3000);
}
}
}
CSomeObjClient stores the variable and has one function (alterSomeVar) to update it
Ouput:
Sent Message: 1
Recv:1
Altered var to :1
Sent Message: 2
Sent Message: 3
Sent Message: 4
Sent Message: 5
Recv:2
Altered var to :2
Sent Message: 6
Sent Message: 7
Sent Message: 8
Sent Message: 9
Sent Message: 10
Recv:3
Altered var to :3
The operating system kernel maintains separate send and receive buffers for each UDP and TCP socket. If you google SO_SNDBUF and SO_RCVBUF you'll find lots of information about them.
When you send data, it is copied from your application space into the send buffer. From there it is copied to the network interface card, and then onto the wire. The receive side is the reverse: NIC to receive buffer, where it waits until you read it. Additionally copies and buffering can also occur, depending on the OS.
It is critical to note that the sizes of these buffers can vary radically. Some systems might default to as little as 4 kilobytes, while others give you 2 megabytes. You can find the current size using getsockopt() with SO_SNDBUF or SO_RCVBUF and likewise set it using setsockopt(). But many systems limit the size of the buffer, sometimes to arbitrarily small amounts. This is typically a kernel value like net.core.wmem_max or net.core.rmem_max, but the exact reference will vary by system.
Also note that setsockopt() can fail even if you request an amount less than the supposed limit. So to actually get a desired size, you need to repeatedly call setsockopt() using decreasing amounts until it finally succeeds.
The following page is a Tech Note from my company which touches on this topic a little bit and provides references for some common systems: http://www.dataexpedition.com/support/notes/tn0024.html
It looks to me like the UdpClient-Class provides a buffer for received data. Try using a socket directly. You might also want to set that sockets ReceiveBufferSize to zero, even though I believe it is only used for TCP connections.
I am having some trouble figuring out why I am only receiving one reply from a server application running on my computer(LocalHost). I do not have the source for this server application but it is a java application. Messages that is sent is a xml structure and have to end with a EoT tag.
The communication:
Client connect to sever.
Client sends message to server.
Server sends message recived to client.
Client sends message to server.
Server sends a End of Transmission character.
Client sends message to server.
Server sends a End of Transmission character.
This is how my client connect, send and receive:
public bool ConnectSocket(string server, int port)
{
System.Net.IPHostEntry hostEntry = null;
try
{
// Get host related information.
hostEntry = System.Net.Dns.GetHostEntry(server);
}
catch (System.Exception ex)
{
return false;
}
// Loop through the AddressList to obtain the supported AddressFamily. This is to avoid
// an exception that occurs when the host IP Address is not compatible with the address family
// (typical in the IPv6 case).
foreach (System.Net.IPAddress address in hostEntry.AddressList)
{
System.Net.IPEndPoint ipe = new System.Net.IPEndPoint(address, port);
System.Net.Sockets.Socket tempSocket = new System.Net.Sockets.Socket(ipe.AddressFamily, System.Net.Sockets.SocketType.Stream,
System.Net.Sockets.ProtocolType.Tcp);
tempSocket.Connect(ipe);
if (tempSocket.Connected)
{
m_pSocket = tempSocket;
m_pSocket.NoDelay = true;
return true;
}
else
continue;
}
return false;
}
}
public void Send(string message)
{
message += (char)4;//We add end of transmission character
m_pSocket.Send(m_Encoding.GetBytes(message.ToCharArray()));
}
private void Recive()
{
byte[] tByte = new byte[1024];
m_pSocket.Receive(tByte);
string recivemessage = (m_Encoding.GetString(tByte));
}
Your Receive code looks very wrong; you should never assume that packets arrive in the same constructions that the server sends messages - TCP is just a stream. So: you must catch the return from Receive, to see how many bytes you received. It could be part of one message, an entire message, multiple entire messages, or the last half of one message and the first half of the next. Normally, you need some kind of "framing" decision, which could mean "messages split by LF characters", or could mean "the length of each message is prefixed by network-byte-order integer, 4 bytes". This usually means you need to buffer until you have a full frame, and worry about spare data at the end of the buffer that is part of the next frame. Key bits to add, though:
int bytes = m_pSocket.Receive(tByte);
// now process "bytes" bytes **only** from tByte, nothing that this
// could be part of a message, an entire message, several messages, or
// the end of message "A", the entire of message "B", and the first byte of
// message "C" (which might not be an entire character)
In particular, with text formats, you cannot start decoding until you are sure you have an entire message buffered, because a multi-byte character might be split between two messages.
There may well also be problems in your receive loop, but you don't show that (nothing calls Receive), so we can't comment.
I had recently asked a related question In C# how do I have a socket continue to stay open and accept new data? and somewhat solved it, but now I'm having trouble getting my server to receive data from the same client more than once.
I have written a simple socket server using a windows form in VS that has a button that calls a receive function
public void Receive()
{
try
{
byte[] bytes = new byte[256];
received = s1.Accept().Receive(bytes);
receivedText.Text += System.Text.ASCIIEncoding.ASCII.GetString(bytes);
}
catch (SocketException e)
{
Console.WriteLine("{0} Error code: {1}.", e.Message, e.ErrorCode);
return;
}
}
It works if the first time I send from my client, but if I try sending anything else and click on receive, my server just loops and never picks up the new data. However, if I send from somewhere else, or restart the connection from my client, I'm able to send data.
I would like to have my server able to receive any amount of data from the same client(s) at a time. Please ask if you need more code/details. Not sure what's relevant as I'm pretty new to socket programming.
You must call Accept() only once per client, not every time you want to receive new data. Accept() basically waits for a client to connect to your server socket, s1 (and returns a new socket to send/receive data with this client), so here each time your Receive() function is called your socket waits for another client to connect, that's why it works only once.
Here is an example (the code comes from your previous question) :
s1.Bind(endP);
s1.Listen(10);
Socket s2 = s1.Accept(); // Waits for a client to connect and return a socket, s2, to communicate with him
while (true) {
Receive(s2);
}
...
Receive() function :
public void Receive(Socket s)
{
try
{
byte[] bytes = new byte[256];
received = s.Receive(bytes);
receivedText.Text += System.Text.ASCIIEncoding.ASCII.GetString(bytes);
}
catch (SocketException e)
{
Console.WriteLine("{0} Error code: {1}.", e.Message, e.ErrorCode);
return;
}
}