I use 2 ways to receive data with a socket connected to an IP address.
Synchronous receive.
Asynchronous receive.
Using synchronous receive, I get all response from the server in less than 1 second. But by using asynchronous receive, it takes over 30 seconds to receive all the responses.
Here is the code:
class StateObject
{
// Client socket.
public Socket workSocket = null;
// Size of receive buffer.
public const int BufferSize = 256;
// Receive buffer.
public byte[] buffer = new byte[BufferSize];
// Received data string.
public StringBuilder sb = new StringBuilder();
}
private static void Receive(Socket client)
{
try
{
// Create the state object.
StateObject state = new StateObject();
state.workSocket = client;
// Begin receiving the data from the remote device.
client.BeginReceive(state.buffer, 0, StateObject.BufferSize, 0,
new AsyncCallback(ReceiveCallback), state);
}
catch (Exception e)
{
Console.WriteLine(e.ToString());
}
}
private static void ReceiveCallback(IAsyncResult ar)
{
try
{
// Retrieve the state object and the client socket
// from the asynchronous state object.
StateObject state = (StateObject)ar.AsyncState;
Socket client = state.workSocket;
// Read data from the remote device.
int bytesRead = client.EndReceive(ar);
if (bytesRead > 0)
{
// There might be more data, so store the data received so far.
state.sb.Append(Encoding.ASCII.GetString(state.buffer, 0, bytesRead));
// Get the rest of the data.
client.ReceiveTimeout = 500;
client.BeginReceive(state.buffer, 0, StateObject.BufferSize, 0,
new AsyncCallback(ReceiveCallback), state);
}
else
{
// All the data has arrived; put it in response.
if (state.sb.Length > 1)
{
response = state.sb.ToString();
}
// Signal that all bytes have been received.
receiveDone.Set();
}
}
catch (Exception e)
{
MessageBox.Show(e.ToString());
}
}
You should check for your value after you append the current string to your buffer, in order to process the message and remove the client.ReceiveTimeout = 500; which i think is taking time:
if (bytesRead > 0)
{
state.sb.Append(Encoding.ASCII.GetString(state.buffer, 0, bytesRead));
response = state.sb.ToString();
if (response.IndexOf("<EOF>") != -1)
{
state.sb.Clear();
receiveDone.Set();
}
else
{
client.BeginReceive(state.buffer, 0, StateObject.BufferSize, 0,
new AsyncCallback(ReceiveCallback), state);
}
}
This will only work for one message with , for real-time multiple messages, I think you should try different approach.
Related
I am trying to receive data asynchronously and store it into StringBuilder and when StringBuilder length will be above 1000 process this data. Every time I call my Update_Interface function some data is lost. I set buffer size to 256. How can I solve this? Its caused because my function need some time to process my data and then Client is not receiving data?
public void Receive(Socket client)
{
try
{
// Create the state object.
StateObject state = new StateObject();
state.workSocket = client;
// Begin receiving the data from the remote device.
client.BeginReceive(state.buffer, 0, StateObject.BufferSize, 0,
new AsyncCallback(ReceiveCallback), state);
}
catch (Exception e)
{
MessageBox.Show(e.ToString());
}
}
public void ReceiveCallback(IAsyncResult ar)
{
try
{
// Retrieve the state object and the client socket
// from the asynchronous state object.
StateObject state = (StateObject)ar.AsyncState;
Socket client = state.workSocket;
// Read data from the remote device.
int bytesRead = client.EndReceive(ar);
if (bytesRead > 0)
{
// There might be more data, so store the data received so far.
state.sb.Append(Encoding.ASCII.GetString(state.buffer, 0, bytesRead));
if (state.sb.Length > 1000)
{
Update_Interface(state.sb.ToString());
state.sb.Clear();
}
client.BeginReceive(state.buffer, 0, StateObject.BufferSize, 0,
new AsyncCallback(ReceiveCallback), state);
}
else
{
receiveDone.Set();
}
}
catch (Exception e)
{
MessageBox.Show(e.ToString());
}
}
I'm creating a Server Socket in C# for my Unity Application. I have created Asynchronous Server Socket from below link
Asynchronous Server Socket
Using which I can successfully able to connect with client and receive data from client. But after few data received the socket is not receiving data even though the client is sending the data (I'm testing client and server in same machine).
Also there was no exception thrown in try catch either. So I'm not able to identify the root cause.
Please find my code below
public class NetworkStateObject
{
// Client socket.
public Socket workSocket = null;
// Size of receive buffer.
public const int BufferSize = 1024;
// Receive buffer.
public byte[] buffer = new byte[BufferSize];
// Received data string.
public List<byte> receivedBytes = new List<byte>();
}
private readonly ManualResetEvent allDone = new ManualResetEvent(false);
private readonly ManualResetEvent receiveDone = new ManualResetEvent(false);
private readonly string receiveDelimitter = "<EOF>";
socketThread = new Thread(new ThreadStart(StartSocketServer));
socketThread.Priority = System.Threading.ThreadPriority.BelowNormal;
socketThread.IsBackground = true;
socketThread.Start();
protected void Receive(Socket socket)
{
ReceiveData(socket);
receiveDone.WaitOne();
}
private void ReceiveData(Socket socket)
{
try
{
// Create the state object.
NetworkStateObject state = new NetworkStateObject();
state.workSocket = socket;
// Begin receiving the data from the remote device.
socket.BeginReceive(state.buffer, 0, NetworkStateObject.BufferSize, 0, new AsyncCallback(ReceiveCallback), state);
}
catch (Exception e)
{
Debug.Log(e.ToString());
}
}
private void ReceiveCallback(IAsyncResult ar)
{
try
{
// Retrieve the state object and the client socket
// from the asynchronous state object.
NetworkStateObject state = (NetworkStateObject)ar.AsyncState;
Socket socket = state.workSocket;
// Read data from the remote device.
int bytesRead = socket.EndReceive(ar);
if (bytesRead > 0)
{
// There might be more data, so store the data received so far.
//state.sb.Append(Encoding.ASCII.GetString(state.buffer, 0, bytesRead));
var bytesArray = state.buffer;
if (bytesRead < NetworkStateObject.BufferSize)
{
Array.Resize(ref bytesArray, bytesRead);
}
var bytesList = new List<byte>(bytesArray);
state.receivedBytes.AddRange(bytesList);
var receivedBytes = state.receivedBytes;
var bytesCount = receivedBytes.Count;
if (receivedBytes.Count > 1)
{
var receivedString = Encoding.ASCII.GetString(receivedBytes.ToArray(), 0, bytesCount);
if (receivedString.IndexOf(receiveDelimitter, StringComparison.CurrentCulture) > -1)
{
var message = receivedString.Replace(receiveDelimitter, String.Empty);
message = Regex.Unescape(message);
socketBaseDelegate.ReceivedMessage(message);
state.receivedBytes.Clear();
receiveDone.Set();
}
else
{
// Get the rest of the data.
socket.BeginReceive(state.buffer, 0, NetworkStateObject.BufferSize, 0, new AsyncCallback(ReceiveCallback), state);
}
}
}
else
{
receiveDone.Set();
}
}
catch (Exception e)
{
Debug.Log(e.ToString());
}
}
public void ReceivedMessage(string data)
{
socketInputParser.Parse(data);
asynchronousSocketListener.ReceiveMessage();
}
In the above code the ReceiveCallback is not triggered after some time.
Even though client sends data.
else
{
// Get the rest of the data.
socket.BeginReceive(state.buffer, 0, NetworkStateObject.BufferSize, 0, new AsyncCallback(ReceiveCallback), state);
}
This part shouldn't be conditional. You should always begin receiving again once the receive callback is complete. Unless of course the connection is terminated.
I have some weird problem with two c# server sockets.
I have 2 servers. One is asynchronous and second is synchronous. I have also client in android which sends picture to this servers.
Synchronous Server:
Socket listener = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
public void Start()
{
byte[] bytes = new Byte[1024000];
String content = String.Empty;
IPAddress ipAddress = IPAddress.Parse("192.168.1.2");
IPEndPoint localEndPoint = new IPEndPoint(ipAddress, 53100);
try
{
listener.Bind(localEndPoint);
listener.Listen(10);
while (true)
{
//// Program is suspended while waiting for an incoming connection.
Socket handler = listener.Accept();
data = null;
// An incoming connection needs to be processed.
while (true)
{
bytes = new byte[1024000];
int bytesRec = handler.Receive(bytes);
strBuilder.Append(Encoding.ASCII.GetString(bytes, 0, bytesRec));
if (strBuilder.Length > 1)
{
content = strBuilder.ToString();
byte[] xdata = Convert.FromBase64String(content);
using (var mStream = new MemoryStream(xdata, 0, xdata.Length))
{
pictureBox1.Image = Image.FromStream(mStream, true);
}
}
}
byte[] msg = Encoding.ASCII.GetBytes(data);
handler.Send(msg);
handler.Shutdown(SocketShutdown.Both);
handler.Close();
}
}
catch (Exception ex)
{
MessageBox.Show(ex.Message);
}
}
private void Form1_Load(object sender, EventArgs e)
{
thr = new Thread(new ThreadStart(Start));
thr.Start();
}
Asynchronous Server:
public void StartListening()
{
listener.Bind(new IPEndPoint(IPAddress.Parse("192.168.1.2"), 53100));
listener.Listen(1);
allDone.Reset();
listener.BeginAccept(new AsyncCallback(AcceptCallback), listener);
}
public void AcceptCallback(IAsyncResult ar)
{
Socket listener = (Socket)ar.AsyncState;
Socket handler = listener.EndAccept(ar);
StateObject stateObj = new StateObject();
stateObj.clientSocket = handler;
handler.BeginReceive(stateObj.buffer, 0, StateObject.buffSize, 0,
new AsyncCallback(ReadCallback), stateObj);
listener.BeginAccept(new AsyncCallback(AcceptCallback), listener);
}
public void ReadCallback(IAsyncResult ar)
{
String content = String.Empty;
StateObject stateObj = (StateObject)ar.AsyncState;
Socket handler = stateObj.clientSocket;
SocketError errorCode;
int bytesRead = handler.EndReceive(ar, out errorCode);
if (errorCode != SocketError.Success)
{
bytesRead = 0;
}
if (bytesRead > 0)
{
stateObj.strBuilder.Append(Encoding.ASCII.GetString(stateObj.buffer, 0, bytesRead));
handler.BeginReceive(stateObj.buffer, 0, stateObj.buffer.Length, SocketFlags.None, new AsyncCallback(ReadCallback), stateObj);
}
else
{
if (stateObj.strBuilder.Length > 1)
{
content = stateObj.strBuilder.ToString();
Debug.WriteLine(content);
byte[] data = Convert.FromBase64String(content);
using (var mStream = new MemoryStream(data, 0, data.Length))
{
pictureBox1.Image = Image.FromStream(mStream, true);
}
recImage = (Bitmap)pictureBox1.Image;
imgImage = new Image<Bgr, Byte>(recImage);
imageBox1.Image = imgImage;
while (imageBox1.Image != null)
{
SURFDetectionAndGUIUpdate(this, new EventArgs());
}
string xname = name.ToString();
Send(handler, xname);
}
}
}
private void Send(Socket handler, String data)
{
byte[] byteData = Encoding.ASCII.GetBytes(data);
handler.BeginSend(byteData, 0, byteData.Length, 0,
new AsyncCallback(SendCallback), handler);
}
private void SendCallback(IAsyncResult ar)
{
try
{
Socket handler = (Socket)ar.AsyncState;
int bytesSent = handler.EndSend(ar);
handler.Shutdown(SocketShutdown.Both);
handler.Close();
}
catch (Exception ex)
{
MessageBox.Show(ex.Message);
}
}
The problem is that when I send picture from client to synchronous server everything works and server receives it, but if I send picture from the same client to asynchronous server it doesn't receive it.
Currently your synchronous server attempts to create a bitmap from the data of the first Receive, and the asynchronous server waits until the client disconnects before trying to create a bitmap from the data.
TCP streams data, which means that you can read data as it arrives, in the order it was sent, but sending 1000 bytes doesn't mean you'll receive 1000 bytes at once. You could even receive data from two different message in a single Receive operation. The more data you send, and the more times you send data, the bigger the chance that this effect will occur.
In the comments you mention that the client is going to send multiple images, so before you continue you should decide how you want to determine when the first image is received and when data for the second image starts:
You could choose to let the client disconnect after sending each image, as the asynchronous server currently expects
You could choose to first send the number of bytes of an image, before sending the image data itself. Make sure the size itself is encoded at a fixed length. This prevents you from having to reconnect all the time, and also allows you to predetermine the size of the receive buffers
Or you could delimit the data using a byte outside the base64 range, but this requires scanning through the received data
Here is my code . I am successfully sending data but not receiving any data . here is my code below . I am actually sending 23 bytes over the socket and its executing the event but its not receiving the data server is sending back . I want to have persistent bi directional connection to send and receive data
using System;
using System.Net;
using System.Net.Sockets;
using System.Threading;
using System.Text;
using System.Collections.Generic;
// State object for receiving data from remote device.
public class StateObject
{
// Client socket.
public Socket workSocket = null;
// Size of receive buffer.
public const int BufferSize = 256;
// Receive buffer.
public byte[] buffer = new byte[BufferSize];
// Received data string.
public StringBuilder sb = new StringBuilder();
}
public class AsynchronousClient
{
// The port number for the remote device.
private const int port = 18001;
// ManualResetEvent instances signal completion.
private static ManualResetEvent connectDone =
new ManualResetEvent(false);
private static ManualResetEvent sendDone =
new ManualResetEvent(false);
private static ManualResetEvent receiveDone =
new ManualResetEvent(false);
// The response from the remote device.
private static String response = String.Empty;
private static void StartClient()
{
// Connect to a remote device.
try
{
IPEndPoint remoteEP = new IPEndPoint(IPAddress.Parse("192.168.1.140"), port);
// Create a TCP/IP socket.
Socket client = new Socket(AddressFamily.InterNetwork,SocketType.Stream, ProtocolType.Tcp);
// Connect to the remote endpoint.
client.BeginConnect(remoteEP, new AsyncCallback(ConnectCallback), client);
connectDone.WaitOne();
// Send test data to the remote device.
Send(client, "This is a test<EOF>");
sendDone.WaitOne();
// Receive the response from the remote device.
Receive(client);
receiveDone.WaitOne();
// Write the response to the console.
Console.WriteLine("Response received : {0}", response);
// Release the socket.
client.Shutdown(SocketShutdown.Both);
client.Close();
}
catch (Exception e)
{
Console.WriteLine(e.ToString());
}
}
private static void ConnectCallback(IAsyncResult ar)
{
try
{
// Retrieve the socket from the state object.
Socket client = (Socket)ar.AsyncState;
// Complete the connection.
client.EndConnect(ar);
Console.WriteLine("Socket connected to {0}",
client.RemoteEndPoint.ToString());
// Signal that the connection has been made.
connectDone.Set();
}
catch (Exception e)
{
Console.WriteLine(e.ToString());
}
}
private static void Receive(Socket client)
{
try
{
// Create the state object.
StateObject state = new StateObject();
state.workSocket = client;
// Begin receiving the data from the remote device.
client.BeginReceive(state.buffer, 0, StateObject.BufferSize, 0,
new AsyncCallback(ReceiveCallback), state);
}
catch (Exception e)
{
Console.WriteLine(e.ToString());
}
}
private static void ReceiveCallback(IAsyncResult ar)
{
try
{
StateObject state = (StateObject)ar.AsyncState;
Socket client = state.workSocket;
// Read data from the remote device.
int bytesRead = client.EndReceive(ar);
if (bytesRead > 0)
{
// There might be more data, so store the data received so far.
state.sb.Append(Encoding.ASCII.GetString(state.buffer, 0, bytesRead));
// Get the rest of the data.
client.BeginReceive(state.buffer, 0, StateObject.BufferSize, 0,
new AsyncCallback(ReceiveCallback), state);
}
else
{
// All the data has arrived; put it in response.
if (state.sb.Length > 1)
{
response = state.sb.ToString();
}
// Signal that all bytes have been received.
receiveDone.Set();
}
}
catch (Exception e)
{
Console.WriteLine(e.ToString());
}
}
private static void Send(Socket client, String data)
{
// F2 00 DATA FF
List<byte> byteTemp = new List<byte>();
byteTemp.Add(0XF2);
byteTemp.Add(0X00);
byte[] TcpData = Encoding.ASCII.GetBytes("0040005001100180");
foreach (byte eachdata in TcpData)
{
byteTemp.Add(eachdata);
}
byteTemp.Add(0XFF);
byte[] byteData = byteTemp.ToArray();
client.BeginSend(byteData, 0, byteData.Length, 0,
new AsyncCallback(SendCallback), client);
}
private static void SendCallback(IAsyncResult ar)
{
try
{
// Retrieve the socket from the state object.
Socket client = (Socket)ar.AsyncState;
// Complete sending the data to the remote device.
int bytesSent = client.EndSend(ar);
Console.WriteLine("Sent {0} bytes to server.", bytesSent);
// Signal that all bytes have been sent.
sendDone.Set();
}
catch (Exception e)
{
Console.WriteLine(e.ToString());
}
}
public static int Main(String[] args)
{
StartClient();
return 0;
}
}
private static void ReceiveCallback(IAsyncResult ar)
{
try
{
Console.WriteLine("Receieve Call Back Invoked");
StateObject state = (StateObject)ar.AsyncState;
Socket client = state.workSocket;
// Read data from the remote device.
int bytesRead = client.EndReceive(ar);
Console.WriteLine("Receieve End Receieve");
if (bytesRead > 0)
{
// There might be more data, so store the data received so far.
state.sb.Append(Encoding.ASCII.GetString(state.buffer, 0, bytesRead));
Console.WriteLine("Read : " + bytesRead.ToString());
// Get the rest of the data.
client.BeginReceive(state.buffer, 0, StateObject.BufferSize, 0,
new AsyncCallback(ReceiveCallback), state);
Console.WriteLine("Begin Receieve completed");
}
else
{
// All the data has arrived; put it in response.
if (state.sb.Length > 1)
{
response = state.sb.ToString();
}
Console.WriteLine("Received data from client");
// Signal that all bytes have been received.
receiveDone.Set();
}
Console.WriteLine("completed receive callback");
}
catch (Exception e)
{
Console.WriteLine(e.ToString());
}
}
the data has been received, but not utilized as "else" in the above method is not getting executed.
I'm trying to make a basic chat system for multiple people.
It sends messages and all, but except the first message sent from each client, each message's first byte is missing (whether the client didn't send it, or the server did not receive it).
Here is my client's Send and SendCallback:
private static void Send(Socket client, string data)
{
byte[] byteData = Encoding.ASCII.GetBytes(data);
client.BeginSend(byteData, 0, byteData.Length, SocketFlags.None, new AsyncCallback(SendCallback), client);
}
private static void SendCallback(IAsyncResult ar)
{
try
{
Socket client = (Socket) ar.AsyncState;
int bytesSent = client.EndSend(ar);
sendDone.Set();
}
catch (Exception e)
{
Console.WriteLine(e);
}
}
And here's my server's Accepter and ReceiveCallback:
private static void AcceptCallback(IAsyncResult ar)
{
allDone.Set();
Socket listenerSocket = (Socket) ar.AsyncState;
Socket handlerSocket = listenerSocket.EndAccept(ar);
if (!clientList.Contains(handlerSocket))
{
clientList.Add(handlerSocket);
}
// Creating the state object
StateObject state = new StateObject();
state.workSocket = handlerSocket;
handlerSocket.BeginReceive(state.buffer, 0, StateObject.BUFFER_SIZE, 0,
new AsyncCallback(ReceiveCallback), state);
}
private static void ReceiveCallback(IAsyncResult ar)
{
StateObject state = (StateObject) ar.AsyncState;
Socket handlerSocket = state.workSocket;
// Read data from the client socket.
try
{
int read = handlerSocket.EndReceive(ar);
if (read > 0)
{
state.sb.Append(Encoding.ASCII.GetString(state.buffer, 0, read));
handlerSocket.BeginReceive(state.buffer, 0, StateObject.BUFFER_SIZE, 0, new AsyncCallback(ReceiveCallback),
state);
}
if (state.sb.Length > 0)
{
string content = state.sb.ToString();
foreach (Socket clientSocket in clientList)
{
Send(clientSocket, content);
}
Console.WriteLine(content);
state.sb = new StringBuilder();
}
else
handlerSocket.Close();
}
catch (Exception e)
{
Console.WriteLine(e);
}
}
I'll give an example of the problem:
client sends "hi",
server sees "hi" - everything is fine.
then:
client sends "hi"
server sees "i" - first character is missing.
What am I missing? What did I do wrong?