Here's the strangest problem I've ever seen. Consider this code I use to receive consecutive UDP datagrams (the sequence always ends with a datagram containing Base64-encoded message FEND):
var received = new List<string>(10);
while (received.LastOrDefault() != "FEND")
{
byte[] buffer = new byte[65535]; // 65535 is the maximum size of a UDP datagram
client.Receive(buffer);
string strBuffer = Convert.ToBase64String(buffer);
strBuffer = strBuffer.TrimEnd('A'); // The buffer ends with zeros that are translated to "A"
received.Add(strBuffer);
Console.WriteLine();
}
received = received.Take(received.Count - 1).ToList();
client is a Socket field initialized with this code:
client = new Socket(AddressFamily.InterNetwork, SocketType.Dgram, ProtocolType.Udp);
client.Bind(new IPEndPoint(IPAddress.Any, port));
port is specified by the client code (I'm writing a class library).
Here's the issue itself: the received list always contains only one item. I have added a Console.WriteLine() call into the end of while cycle and put there a breakpoint. When it hits, strBuffer contains a string of type hoYfopfHUTDJf8erK... (it's the expected value, and it is different in different iterations), and received contains a List<string> which has its Count property equal to 1 in all iterations! Its only item is the strBuffer value from the iteration I'm watching.
It seems like the Add call replaces the item in received instead of adding a new one. Is it an underlying bug or a stupid error?
UPDATE: in an online C# compiler my code works fine.
Are you really getting BASE64 text in UDP datagrams? Maybe you need Encoding.GetString() instead?
I think you could try something like this:
var received = new List<string>(10);
byte[] buffer = new byte[65535]; // 65535 is the maximum size of a UDP datagram
while (true)
{
var bytesReceived = client.Receive(buffer);
if (bytesReceived == 0)
break;
string strBuffer = System.Text.Encoding.UTF8.GetString(buffer, 0, bytesReceived);
if (strBuffer == "FEND")
break;
received.Add(strBuffer);
Console.WriteLine();
}
Related
This is a follow up to my previous question. But it appears that for a reason I don't understand, the os is interpreting a received string differently than a message box is. This is apparent as when using message box.show function, it shows the correct string that was received. But the if then statement, the code for if the string equals what it does equal does not execute, and also the same string comes across as only system.byte it does not show in the console.
Here is the code:
SL_Click(object sender, EventArgs e)
{
try
{
TcpClient tcpclnt = new TcpClient();
tcpclnt.Connect(RecieveIP.Text, 8001); // receive the IP to listen from and port number for server.
MessageBox.Show("Connected");
Stream stm = tcpclnt.GetStream();
MessageBox.Show("Listening for information......");
byte[] bb = new byte[100];
int k = stm.Read(bb, 0, 100);
for (int i = 0; i < k; i++)
Console.Write(Convert.ToString(bb));
string atk = Encoding.ASCII.GetString(bb);
MessageBox.Show("Received Command " + atk);
if (atk == "g")
{
MessageBox.Show("working");
Search.RunWorkerAsync();
}
}
}
I'm leaving out the actual background worker code is it works ok in other implementations.
I am wondering why this may be? Thanks.
i don't know why you don't have it in a "while" loop or something but never mind that...
please try this:
byte[] bb = new byte[100];
int k = stm.Read(bb, 0, 100);
string data = Encoding.UTF8.GetString(bb.AsSpan(0, k ));
Console.WriteLine($"Data Received: {data}");//test
//if you want your check
//this will not work if your incoming data contains white space or other bytes that were converted.
if (data == "g" ||data.Contains("g"))//the .Contains can solve that prob, but a mix of letters containing "g" will trigger it
{
MessageBox.Show("working");
Search.RunWorkerAsync();
}
if your still having trouble please debug your incoming bytes and sent one.
make sure your not sending other bytes other the the "g" that you have send, if you use a different conversion method it might add additional bytes.
Consider checking your sent and received bytes!
I am very new in Socket Programming.
I am using the following code to receive incoming data from a pathology machine.
byte[] buffer = new byte[2048];
IPAddress ipAddress = IPAddress.Parse(SERVER_IP);
IPEndPoint localEndpoint = new IPEndPoint(ipAddress, PORT_NO);
Socket sock = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
try
{
sock.Connect(localEndpoint);
}
catch (Exception ex)
{
throw ex;
}
int recv = 0;
string Printed = string.Empty;
StringBuilder sb = new StringBuilder();
while ((recv = sock.Receive(buffer)) > 0)
{
if (sock.Receive(buffer).ToString().Length > 1) // I used this line because it's receiving some garbage value all the time.
{
sb.Append(Encoding.UTF8.GetString(buffer));
}
else
{
if (sb.Length > 50 && Printed == string.Empty)
{
Console.WriteLine(sb);
Printed = "Y";
}
}
}
Issues I am facing
My program is not receiving complete data. Maybe because of this line if (sock.Receive(buffer).ToString().Length > 1). But I used this line because it's always receiving something.
My program goes to endless loop. I am looking for the program which should stop for sometime after receiving the data and start listening again for new incoming data.
There's a few things here;
you need to store the read count, and use only that many bytes, i.e. var bytes = sock.Receive(buffer); (and use bytes for both the EOF test, and for how many bytes to process)
we can't use ToString().Length > 1 here, because it is an integer and every integer, as a string, has a non-zero length; instead, simply: if (bytes > 0) (minutiae: there is a scenario where an open socket can return zero without meaning EOF, but... it doesn't apply here)
even for a text protocol, you can't necessarily simply use Encoding.UTF8.GetString(buffer, 0, bytes), because UTF8 is a multi-byte encoding, meaning: you might have partial characters; additionally, you don't yet know whether that is one message, half a message, or 14 and a bit messages; you need to read about the protocol's "framing" - which might simply mean "buffer bytes until you see a newline ('\n') character, decode those buffered bytes via the encoding, process that message, and repeat"
I have a Socket code which is communicating through TCP/IP.The machine to which i am communicating has buffer data in its buffer.At present i am trying to get the buffer data using this code.
byte data = new byte[1024];
int recv = sock.Receive(data);
stringData = Encoding.ASCII.GetString(data, 0, recv);
But this code retrieves only 11 lines of data whereas more data is there in the machines buffer.Is this because i have used int recv = sock.Receive(data); and data is 1024 ?
If yes ,How to get the total buffer size and retrieve it into string.
If you think you are missing some data, then you need to check recv and almost certainly: loop. Fortunately, ASCII is always single byte - in most other encodings you would also have to worry about receiving partial characters.
A common approach is basically:
int recv;
while((recv = sock.Receive(data)) > 0)
{
// process recv-many bytes
// ... stringData = Encoding.ASCII.GetString(data, 0, recv);
}
Keep in mind that there is no guarantee that stringData will be any particular entire unit of work; what you send is not always what you receive, and that could be a single character, 14 lines, or the second half of one word and the first half of another. You generally need to maintain your own back-buffer of received data until you have a complete logical frame to process.
Note, however, Receive always tries to return something (at least one byte), unless the inbound stream has closed - and will block to do so. If this is a problem, you may need to check the available buffer (sock.Available) to decide whether to do synchronous versus asynchronous receive (i.e. read synchronously while data is available, otherwise request an asynchronous read).
Try something along these lines:
StringBuilder sbContent=new StringBuilder();
byte data = new byte[1024];
int numBytes;
while ((numBytes = sock.Receive(data))>0)
{
sbContent.Append(Encoding.UTF8.GetString(data));
}
// use sbContent.ToString()
Socket tcpSocket = new Socket(ipe.AddressFamily, SocketType.Stream, ProtocolType.Tcp);
Console.WriteLine(" ReceiveBufferSize {0}", tcpSocket.ReceiveBufferSize);
For actual data you can put below condition:-
int receiveBytes;
while((receiveBytes = tcpSocket.Receive.Data(receiveBytes)) > 0)
{
}
I am writing a telnet server using the async Begin/End methods. The issue that I am having is determining what within my buffer is actual data and what is not. Network coding is a bit new to me, but I've tried to research this and have not been able to find a answer.
public bool Start(IGame game)
{
// Get our server address information.
IPHostEntry serverHost = Dns.GetHostEntry(Dns.GetHostName());
IPEndPoint serverEndPoint = new IPEndPoint(IPAddress.Any, this.Port);
// Instance the server socket, bind it to a port and begin listening for connections.
this._ServerSocket = new Socket(serverEndPoint.Address.AddressFamily, SocketType.Stream, ProtocolType.Tcp);
this._ServerSocket.Bind(serverEndPoint);
this._ServerSocket.Listen(this.MaxQueuedConnections);
this._ServerSocket.BeginAccept(new AsyncCallback(Connect), this._ServerSocket);
return true;
}
private void Connect(IAsyncResult result)
{
var player = new BasePlayer();
try
{
player.Game = this.Game;
player.Connection = this._ServerSocket.EndAccept(result);
lock (this.Connections)
{
this.Connections.Add(player);
}
// Pass all of the data handling for the player to itself.
player.Connection.BeginReceive(player.Buffer, 0, player.BufferSize, SocketFlags.None, new AsyncCallback(player.ReceiveData), player);
// Fetch the next incoming connection.
this._ServerSocket.BeginAccept(new AsyncCallback(Connect), this._ServerSocket);
}
catch (Exception)
{
}
}
and then the player.ReceiveData..
public void ReceiveData(IAsyncResult result)
{
int bytesRead = this.Connection.EndReceive(result);
if (bytesRead > 0)
{
// TODO: Parse data received by the user.
//Queue the next receive data.
this.Connection.BeginReceive(this.Buffer, 0, this.BufferSize, SocketFlags.None, new AsyncCallback(ReceiveData), this);
var str = System.Text.Encoding.Default.GetString(Buffer);
}
else
{
this.Disconnect(result);
}
}
So when I call BeginReceive, I need to provide a buffer of a predetermined size. In doing that, I end up with unused bytes in my buffer array. They all have the value of 0, so I am assuming that I can loop through the array and build a new one starting at index 0 and working until I hit a value of 0.
I imagine there is a better way to do this? Can someone please point me in the right direction as to how I should determine what the data is within my buffer or perhaps a way that I can do this without having to use a predetermined buffer size.
So when call BeginReceive, I need to provide a buffer of a predetermined size. In doing that, I end up with unused bytes in my buffer array. They all have the value of 0, so I am assuming that I can loop through the array and build a new one starting at index 0 and working until I hit a value of 0.
No, that's not what you should do. Instead, in your callback (ReceiveData) you're already calling EndReceive - and the result of that is the number of bytes you read. That's how much of the buffer you should use.
However, you should copy the data you've read out of the buffer before you call BeginReceive again, otherwise you may end up with the next bit of data overwriting the just-read data before you get to use it.
So something like:
string text = Encoding.ASCII.GetString(Buffer, 0, bytesRead);
Connection.BeginReceive(this.Buffer, 0, this.BufferSize, SocketFlags.None,
new AsyncCallback(ReceiveData), this);
I would not suggest that you use Encoding.Default to convert the bytes to text - instead, you should decide which encoding you're using, and stick to that. If you use an encoding which isn't always one-byte-per-character, you'll end up in a slightly trickier situation, as then you might end up receiving a buffer with part of a character. At that point you need to keep a Decoder which can maintain state about partial characters read.
I can use SetBuffer with SocketAsyncEventArgs just fine.
If I try to use BufferList (after doing SetBuffer(null, 0, 0)) I always and immediately get SocketError InvalidArgument (10022) when I do SendAsync on the socket.
There are NO examples or documentation on how to use BufferList and what I am doing makes sense (to me anyway).
Can someone point out an example program or code snippet?
I'm tearing my hair out over this and don't have much left ...
Here is basically what I am doing (e is SocketAsyncEventArgs and lSocket is the same socket I use for SetBuffer which works)
// null the buffer since we will use a buffer list
e.SetBuffer(null, 0, 0);
// create a bufferlist
e.BufferList = new List<ArraySegment<byte>>();
// create the bufferlist with the network header and the response bytes
e.BufferList.Add(new ArraySegment<byte>(lTxBytes)); // add the 4 character total length
e.BufferList.Add(new ArraySegment<byte>(Encoding.ASCII.GetBytes(lTx.Identity))); // echo back the incoming sequence number
e.BufferList.Add(new ArraySegment<byte>(Encoding.ASCII.GetBytes(lResponse)));
// *** the SendAsync always completes IMMEDIATELY (returns false) gets SocketError InvalidArgument (10022)
if (lSocket.SendAsync(e) == false)
{
// data was already sent back to the client.
AppSupport.WriteLog(LogLevel.Flow, "ProcessReceive had SendAsync complete synchronously (bytes transferred {0}).", e.BytesTransferred);
ProcessSend(e);
}
The reason you are getting an exception is that under the hood the SocketAsyncEventArgs only uses the buffers present in the list at the time of setting the BufferList property.
Basically you are trying to send en empty buffer with the code :
e.BufferList = new List<ArraySegment<byte>>();
e.BufferList.Add(new ArraySegment<byte>(lTxBytes));
e.BufferList.Add(new ArraySegment<byte>(Encoding.ASCII.GetBytes(lTx.Identity)));
e.BufferList.Add(new ArraySegment<byte>(Encoding.ASCII.GetBytes(lResponse)));
Instead try to do :
var list = new List<ArraySegment<byte>>();
list.Add(new ArraySegment<byte>(lTxBytes));
list.Add(new ArraySegment<byte>(Encoding.ASCII.GetBytes(lTx.Identity)));
list.Add(new ArraySegment<byte>(Encoding.ASCII.GetBytes(lResponse)));
e.BufferList = list;
This behavior is not well documented at all and can only be understood by looking at the BufferList setter code in detail. Behind the scenes the SocketAsyncEventArgs has a WSABuffer array field(for interop with native code) where it copies and pins the byte arrays references when you set the BufferList. Since it is this WSABuffer[] that is sent to native code, that explains why your code throws an exception.