Async socket - Duplex communication with permanent sockets in c# - c#

I'm trying to do asynchronous socket communication, and want the server to keep a list of all connected sockets, so he can broadcast messages to them.
First I took the examples from msdn Asynchronous Socket Server and altered them a little so they don't close the sockets. (just removed the .shutdown and .Close commands)
But doing so, seems to cause the client to hang in the "receiving part".
Here are the changes I made to the msdn examples:
Client:
only changed ReceiveCallback() so it stays in an endless receiving loop:
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.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();
Console.WriteLine(state.sb.ToString());
}
// Signal that all bytes have been received.
receiveDone.Set();
// Get the rest of the data.
client.BeginReceive(state.buffer, 0, StateObject.BufferSize, 0,
new AsyncCallback(ReceiveCallback), state);
}
}
catch (Exception e)
{
Console.WriteLine(e.ToString());
}
}
The Server:
just commented out the lines that close the socket:
//handler.Shutdown(SocketShutdown.Both);
//handler.Close();
Later i planed to keep a List of Sockets so i can send Messages to them, but it already fails here.
I'm greatfull for any hints, also I would like to hear your opinion on using this tenique for a server that has to serve at max 100 clients, which could send a request any 2 seconds. (The communication should be both ways, so that the client and the Server can send a Message at any time without waiting for a Message to respond to).
Thank you and good evening
Martin

EndReceive only returns 0 when the socket is closed. Your clients will never set the receiveDone handle because the server never closes the socket. The callback is called when data is received OR when the connection is terminated.
You need to detect the end of message (like the example you linked too).
eg. (Modified version of the code you linked)
content = state.sb.ToString();
if (content.IndexOf("<EOF>") > -1) {
// All the data has been read from the
// client. Display it on the console.
Console.WriteLine("Read {0} bytes from socket. \n Data : {1}",
content.Length, content );
// Echo the data back to the client.
Send(handler, content);
{ // NEW
// Reset your state (persist any data that was from the next message?)
// Wait for the next message.
handler.BeginReceive(state.buffer, 0, StateObject.BufferSize, 0,
new AsyncCallback(ReadCallback), state);
}
} else {
// Not all data received. Get more.
handler.BeginReceive(state.buffer, 0, StateObject.BufferSize, 0,
new AsyncCallback(ReadCallback), state);
}

Related

Asynchronous Socket chat crashes on BeginReceive

This is console chat application is based on asynchronous socket. It crashes during BeginReceive:
The error is "An established connection was aborted by the software in your host machine." The antivirus is not the problem.
This is where Receive() is called.
static void RunClient()
{
// Connect to a remote device.
try
{
// Connect to the remote endpoint.
client.BeginConnect(remoteEndPoint,
new AsyncCallback(ConnectCallback),
client);
connectDone.WaitOne();
while (client.Connected)
{
try
{
Console.WriteLine("Input: ");
const string END_OF_FILE = "<EOF>";
string message = $"{Console.ReadLine()}{END_OF_FILE}";
Send(client, message);
sendDone.WaitOne();
// Receive the response from the remote device.
Receive(client);
receiveDone.WaitOne();
// Write the response to the console.
Console.WriteLine($"Response received : {response}");
}
catch (Exception exception)
{
Console.WriteLine(exception.ToString());
}
}
// Release the socket.
client.Shutdown(SocketShutdown.Both);
client.Close();
}
catch (Exception exception)
{
Console.WriteLine(exception.ToString());
}
}
Edit: It works once, and then the error message shows.
Edit 2:
This is the Receive method.
private static void Receive(Socket client)
{
try
{
// Create the state object.
StateObjectClient state = new StateObjectClient();
state.workSocket = client;
// Begin receiving the data from the remote device.
client.BeginReceive(state.buffer,
0,
StateObjectClient.BUFFER_SIZE,
0,
new AsyncCallback(ReceiveCallback),
state);
}
catch (Exception exception)
{
Console.WriteLine(exception.ToString());
}
}
I think your error is a fundamental misunderstanding of how TCP works.
TCP is a stream protocol, not a message protocol. The only gurantees for a TCP stream are
the bytes you send will be received in the same order they are sent
the bytes will be received only once
But you can send a message of 100 bytes and the other side can
receive a 100 byte chunk
100 1 byte chunks
2 50 byte chunks
...
So you must keep looping till you have received everything. This is turn mean that you must know how big a message you expect. Either
always use the same size
prefix the message witha length of well known length (4 ascii bytes say)
or have a recognizable end of message
How to do this
I assume that 'respnse' contains a string of the last received block.
StringBuilder msg = new StringBuilder();
while(true){
Receive(client);
receiveDone.WaitOne();
msg.Append(response);
if(response.EndsWith(END_OF_FILE))
break;
}
response = msg.ToString();
Not being able to see how you unpack the received bytes I hope the EndsWith is correct, maybe there is a newline of something tacked on te end

EndReceive in Async Socket without strings

I'm following this example about the creation of an async tcp listener in C#.
MSDN Example
I see that all data is encoded as string to check for message completeness. More precisely, every message sent is already a string, which we append the 'EOF' char to for string termination.
The server side part i'm talking about is in this snippet:
public static void ReadCallback(IAsyncResult ar) {
String content = String.Empty;
// Retrieve the state object and the handler socket
// from the asynchronous state object.
StateObject state = (StateObject) ar.AsyncState;
Socket handler = state.workSocket;
// Read data from the client socket.
int bytesRead = handler.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));
// Check for end-of-file tag. If it is not there, read
// more data.
content = state.sb.ToString();
if (content.IndexOf("<EOF>") > -1) {
// All the data has been read from the
// client. Display it on the console.
Console.WriteLine("Read {0} bytes from socket. \n Data : {1}",
content.Length, content );
// Echo the data back to the client.
Send(handler, content);
} else {
// Not all data received. Get more.
handler.BeginReceive(state.buffer, 0, StateObject.BufferSize, 0,
new AsyncCallback(ReadCallback), state);
}
}
}
Is there a way, as i usually do with TcpListener/TcpClient classes, to check if received bytes are available on the socket?
I mean something like this:
private void HandleClientConnection(TcpClient client)
{
NetworkStream clientStream = client.GetStream();
MemoryStream memoryStream = new MemoryStream();
while (true)
{
int read = clientStream.ReadByte();
if (read != -1)
{
memoryStream.WriteByte((byte)read);
}
else
{
break;
}
}
}
I'm aware that i probably misunderstood this example, or at least the Begin/End part and the "legacy" async pattern. But this is my goal, do you know some way to get it working without involving strings?
You said : "Is there a way to check if received bytes are available on the socket?"
In general 'EndReceive' will block the thread until data is available. So you don't need to do anything because 'EndReceive' is doing all the job for you.
'bytesRead' is an int that shows you how much data you have received.
a quote from docs.microsoft
The EndReceive method will block until data is available.1
But if you are using a SYNC socket (which you are not) then it's another topic.

How to transfer a file by socket PHP to C# [duplicate]

This question already has answers here:
How to receive a file over TCP which was sent using socket.FileSend Method
(2 answers)
Closed 7 years ago.
Hi after a lot of research i didn't found a solution to my case
I have a C# socket server what's is running on my server and i need to transfer files to it by Socket from my website that's in PHP.
What i have now ?
Php part:
$file = array('file' => Input::file('file'));
$fp = stream_socket_client("tcp://localhost:9192", $error_number, $error_string);
if ( !$fp ) {
echo "$error_number ($error_string)\n";
} else {
fwrite($fp, $file['file']);
}
fclose($fp);
C# Socket Server:
String content = String.Empty;
// Retrieve the state object and the handler socket
// from the asynchronous state object.
StateObject state = (StateObject)ar.AsyncState;
Socket handler = state.workSocket;
// Read data from the client socket.
int bytesRead = handler.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));
// Check for end-of-file tag. If it is not there, read
// more data.
content = state.sb.ToString();
if (content.IndexOf("<EOF>") > -1)
{
// All the data has been read from the
// client. Display it on the console.
Console.WriteLine("Read {0} bytes from socket. \n Data : {1}",
content.Length, content);
// Echo the data back to the client.
Send(handler, content);
}
else
{
// Not all data received. Get more.
handler.BeginReceive(state.buffer, 0, StateObject.BufferSize, 0,
new AsyncCallback(ReadCallback), state);
}
}
When i try to make the connection the C# instantly refuses it what i'm doing wrong ?
I'm using Laravel 5 on PHP part.
I found a solution in this question:
How to receive a file over TCP which was sent using socket.FileSend Method
Sorry for waste your time :)

Async Socket Programming. Failed to receive complete data

I followed this link http://msdn.microsoft.com/en-us/library/bew39x2a(v=vs.110).aspx to write this program.
public string ReceiveResponse(Socket client, int bufferSize)
{
// Receive the response from the remote device.
Receive(client, bufferSize);
// Wait until we receive entire response.
receiveDone.WaitOne();
return response;
}
And my receive callback is
public static void ReceiveCallback(IAsyncResult ar)
{
StateObject so = (StateObject)ar.AsyncState;
Socket s = so.WorkSocket;
int read = s.EndReceive(ar);
if (read > 0)
{
so.Sb.Append(Encoding.ASCII.GetString(so.Buffer, 0, read));
s.BeginReceive(so.Buffer, 0, 1024, 0,
new AsyncCallback(ReceiveCallback), so);
}
else
{
if (so.Sb.Length > 1) // Code never reaching this block??
{
//All of the data has been read, so displays it to the console
string strContent;
strContent = so.Sb.ToString();
Console.WriteLine(String.Format("Read {0} byte from socket" +
"data = {1} ", strContent.Length, strContent));
}
receiveDone.Set();
}
}
As commented in my code else block never reaching so my receiveDone manual reset event blocking my unit test forever.
When Microsoft says this is the way to go then why it is not working for me???
I really need it for real time and multi threaded environment. I wasted a lot time on this but couldn't find a proper reason why this is happening? and how I can fix this?

How to determine the end of a file transfer (data) from the client to the server (Socket)

Simple situation:
The client on a Socket sends a pieces(e.g., 256 byte) of the file (data) in the format byte []to the server. The server receives the data asynchronously.
How to determine when a file (data) is transmitted completely? (Server-side)
Here's the code on server-side responsible for receiving data
public static void ReadCallback(IAsyncResult ar)
{
String content = String.Empty;
// Retrieve the state object and the handler socket
// from the asynchronous state object.
StateObject state = (StateObject)ar.AsyncState;
Socket handler = state.workSocket;
// Read data from the client socket.
int bytesRead = handler.EndReceive(ar);
if (bytesRead > 0)
{
BinaryWriter writer = new BinaryWriter(File.Open(#"D:\test.png", FileMode.Append));
writer.Write(state.buffer, 0, bytesRead);
writer.Close();
// All the data has been read from the
// client. Display it on the console.
Console.WriteLine("Read {0} bytes from socket!",
bytesRead);
handler.BeginReceive(state.buffer, 0, StateObject.BufferSize, 0,
new AsyncCallback(ReadCallback), state);
}
}
Is there a method that allows to make the some following?
if (bytesRead > 0)
{
....
if(state.buffer!=end of receive)
{
handler.BeginReceive(state.buffer, 0, StateObject.BufferSize, 0,
new AsyncCallback(ReadCallback), state);
}
}
Or, I may to try add some information to the this byte[] object (e.g., some string with <EOF> tag)
but I must to analyse this info on each step.
May I do this check more simple and how? Or use another way ...
The only way to do it is to sent a header (of specific size) in front of every message. So, the each message should consist of header and body. The data stream should look like this:
[HEADER][BODY][HEADER][SOME BIGGER BODY][HEADER][SOME EXTRA BIG BODY]
As I said, the header should be of specific size and should contain some custom service fields inlcuding the size of the message's body in bytes. In your case the header could contain only body size, i.e. int value (4 bytes). The receive process should look like this:
Receive 4 bytes (header);
Retrieve body size from header (just convert header to int);
Receive the number of bytes specified in header (i.e. receive message body);
Handle message body;
Go to 1.
I know, it may seem complicated for you, but it is the common way to do it. But you can simplify the code by using Rx library. After implementing some extensions methods for socket (WhenReadExact, the implementation could easily be found over Internet, for example here), the code will look like this:
var whenFileReceived = from header in socket.WhenReadExact(4)
let bodySize = BitConverter.ToInt32(header)
from body in socket.WhenReadExact(bodySize)
select body;
whenFileReceived.Subscribe(
file =>
{
// Handle file here
});

Categories