TCPIP Asynchronous Server connection dropout - c#

i have written(Copied) code for a tcpip server.
We have software that sends a message via TCPIP and expects a return message back to say Receive is Acknowledged. This works fine. But after sending the acknowledgment the connection drops out. I am not sure where in the code this dropout is occurring. So when the next message is sent, there is no connection so it does a rollback and reconnects again and then send the message. So every time i send multiple messages i will keep getting rollback alerts. We will be constantly sending messages all day long. Below is the code :
class Program
{
// State object for reading client data asynchronously
public class StateObject
{
// 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 StringBuilder sb = new StringBuilder();
}
public class AsynchronousSocketListener
{
// Thread signal.
public static ManualResetEvent allDone = new ManualResetEvent(false);
public AsynchronousSocketListener()
{
}
public static void StartListening()
{
// Data buffer for incoming data.
byte[] bytes = new Byte[1024];
// Establish the local endpoint for the socket.
// The DNS name of the computer
// running the listener is "host.contoso.com".
IPHostEntry ipHostInfo = Dns.Resolve(Dns.GetHostName());
IPAddress ipAddress = ipHostInfo.AddressList[0];
ipAddress = IPAddress.Parse("127.0.0.1");
IPEndPoint localEndPoint = new IPEndPoint(ipAddress, 8080);
// Create a TCP/IP socket.
Socket listener = new Socket(AddressFamily.InterNetwork,
SocketType.Stream, ProtocolType.Tcp);
// Bind the socket to the local endpoint and listen for incoming connections.
try
{
listener.Bind(localEndPoint);
listener.Listen(100);
while (true)
{
// Set the event to nonsignaled state.
allDone.Reset();
// Start an asynchronous socket to listen for connections.
Console.WriteLine("Waiting for a connection...");
listener.BeginAccept(
new AsyncCallback(AcceptCallback),
listener);
// Wait until a connection is made before continuing.
allDone.WaitOne();
}
}
catch (Exception e)
{
Console.WriteLine(e.ToString());
}
Console.WriteLine("\nPress ENTER to continue...");
Console.Read();
}
public static void AcceptCallback(IAsyncResult ar)
{
// Signal the main thread to continue.
allDone.Set();
ar.AsyncWaitHandle.WaitOne(100);
// Get the socket that handles the client request.
Socket listener = (Socket)ar.AsyncState;
Socket handler = listener.EndAccept(ar);
// Create the state object.
StateObject state = new StateObject();
state.workSocket = handler;
handler.BeginReceive(state.buffer, 0, StateObject.BufferSize, 0,
new AsyncCallback(ReadCallback), state);
}
public static void ReadCallback(IAsyncResult ar)
{
String content = String.Empty;
String s1 = "MSH|^~\\&|BB|NSCCH|MILLENNIUM|BB|20150522080258137||ACK";
String s2 = "|20150522080258137883|P|2.4";//\r\nMSA|AA|Q245548634T287475114";
//String s3 = String.Empty;
String s4 = "MSA|AA|Q245548634T287475114";
//string s5 = "0x02";
int value = Convert.ToInt32("0x1C", 16);
char cc = (char)value;
int value_eob = Convert.ToInt32("0x0b", 16);
char eob = (char)value_eob;
int value_eod = Convert.ToInt32("0x0D", 16);
char eod = (char)value_eod;
int value_eoa = Convert.ToInt32("0x0A", 16);
char eoa = (char)value_eoa;
/*StringBuilder sb1 = new StringBuilder(s5);
sb1.Append(s1);
sb1.Append(s2);
s3 = sb1.ToString();*/
//byte[] s4 = Encoding.ASCII.GetBytes(s3);
// 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();
//s3 = state.sb.ToString();
// s3 = s1.ToString() + s2.ToString();
if (bytesRead < 1024) //content.IndexOf("<EOF>") > -1)
{
string s6 = eob.ToString() + s1 + s2 + eod.ToString() + s4 + cc.ToString() + eod.ToString() + eoa.ToString();// "\r\n";// +cc.ToString() + "\r\n";
// 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);
Console.WriteLine("Send {0} bytes from socket. \n Data : {1}",
s6.Length, s6);
// Echo the data back to the client.
Send(handler, s6);
}
else
{
// Not all data received. Get more.
handler.BeginReceive(state.buffer, 0, StateObject.BufferSize, 0,
new AsyncCallback(ReadCallback), state);
}
}
else
{
if (content.Length > 0)
{
string s6 = eob.ToString() + s1 + s2 + eod.ToString() + s4 + cc.ToString() + eod.ToString() + eoa.ToString();// "\r\n";// +cc.ToString() + "\r\n";
// 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);
Console.WriteLine("Send {0} bytes from socket. \n Data : {1}",
s6.Length, s6);
// Echo the data back to the client.
Send(handler, s6);
}
}
// Added code
handler.BeginReceive(state.buffer,0, StateObject.BufferSize, 0,
new AsyncCallback(ReadCallback), state);
}
private static void Send(Socket handler, String data)
{
// Convert the string data to byte data using ASCII encoding.
byte[] byteData = Encoding.ASCII.GetBytes(data);
// Begin sending the data to the remote device.
handler.BeginSend(byteData, 0, byteData.Length, 0,
new AsyncCallback(SendCallback), handler);
}
private static void SendCallback(IAsyncResult ar)
{
try
{
// Retrieve the socket from the state object.
Socket handler = (Socket)ar.AsyncState;
// Complete sending the data to the remote device.
int bytesSent = handler.EndSend(ar);
Console.WriteLine("Sent {0} bytes to client.", bytesSent);
// handler.Shutdown(SocketShutdown.Both);
// handler.Close();
}
catch (Exception e)
{
Console.WriteLine(e.ToString());
}
}
public static int Main(string[] args)
{
StartListening();
return 0;
}
}
}

You have at least two major bugs in your code:
You are assuming that a receive operation will always complete having filled the provided buffer, unless the client has stopped sending data (i.e. there's no more data to be received at the moment). This is often going to be true, but it is not guaranteed and your code will fail spuriously if it makes that assumption.
Once you believe that you have received all of the current transmission from the client, you do not call BeginReceive() again. This renders the connection completely useless from that point forward.
Another possible bug is:
Your code does not correctly partition transmitted data. There does not seem to be any code here that will reliably detect the boundary between two different logical messages in the stream of bytes received. Depending on how quickly data is sent by a client, it is possible that some or all data intended to be part of a later logical message is consumed as part of an earlier logical message.
Unfortunately, there is not enough precise detail provided in your question. The phrase "connection drops out" is non-specific and has no well-defined technical meaning. It could mean you get an error on the socket, or it could simply mean that you never receive any more data, or it could mean something else entirely.
That said, if you mean "never receive any more data", then I would say it is most likely that the #2 bug above is the basic cause of your problem. Of course, the #1 bug can in conjunction with the #2 bug also lead to "never receive any more data".
Without a good, minimal, complete code example that reliably reproduces the problem (please note that for network-related issues, a complete example includes both endpoints of the connection), it's impossible to know for sure all of the bugs in the code example, never mind what the actual problem is. However, I would recommend fixing the above bugs and see if that improves things.
As a general rule, your network code should run like this:
Receive data
Interpret the data, identifying logical message boundary (if any)
If a complete logical message has been received, process it. Be sure to retain any excess data that might have been received, for processing as part of the next logical message.
Continue the above, always initiating a new receive operation after handling the results of the current completed operation, until a receive operation completes with a byte count of zero.
When a zero-byte receive operation completes, complete processing of the data received so far (if there is any not yet processed) and acknowledge the graceful closure of the connection by sending any remaining data (if any) and calling Socket.Shutdown(SocketShutdown.Both), and only then calling Socket.Close() to actually close the socket.

Related

How do I keep a client socket connection open and send/receive multiple messages in a console app

I am connecting to a server via TCP socket and sending in strings of data and expecting responses. The responses are unique to the request string and there are two responses per request. One that says the server completed an intermediate task and another indicating the task is complete. These tasks take up to about 20 seconds to complete. Note - I have no access to the server program/code its proprietary.
The client should be able to send in string requests anytime and sometimes fairly quickly. Requests could stack up and the client needs to wait for the unique responses to each request as they are received.
Assuming this needs an asynchronous client I am using the example right from the MS site.
https://learn.microsoft.com/en-us/dotnet/framework/network-programming/asynchronous-client-socket-example
Developing in a console app, I am able to connect and send string requests and I get one response back. The program then exits. New to async sockets I'm not sure how to keep the socket "alive" or open and randomly Console.Read new strings, send them, and get both responses as they are received.
Here is my client code.
public static Socket ClientSocket = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
// 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
{
// 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;
public static void StartClient()
{
// Connect to a remote device.
try
{
IPEndPoint remoteEP = new IPEndPoint(ip, port);
// Create a TCP/IP socket.
Socket client = new Socket(ip.AddressFamily,
SocketType.Stream, ProtocolType.Tcp);
// Connect to the remote endpoint.
client.BeginConnect(remoteEP,
new AsyncCallback(ConnectCallback), client);
connectDone.WaitOne();
Console.WriteLine("Enter a message string: \n");
message = Console.ReadLine();
// Send test data to the remote device.
Send(client, message + "\r\n"); // \r\n required for server to know end of string
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);
}
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("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
{
// 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();
}
// Signal that all bytes have been received.
receiveDone.Set();
}
// Added this here to see if receiving would continue, does not work
client.BeginReceive(state.buffer, 0, StateObject.BufferSize, 0,
new AsyncCallback(ReceiveCallback), state);
}
catch (Exception e)
{
Console.WriteLine(e.ToString());
}
}
private static void Send(Socket client, String data)
{
// Convert the string data to byte data using ASCII encoding.
byte[] byteData = Encoding.ASCII.GetBytes(data);
// Begin sending the data to the remote device.
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());
}
}
At the very least, you could wrap your read-send-receive logic in a loop:
while (true) {
Console.WriteLine("Enter a message string: \n");
message = Console.ReadLine();
if (message == "quit") break;
// Send test data to the remote device.
Send(client, message + "\r\n"); // \r\n required for server to know end of string
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);
}
I also recommend that you learn how to use the Task asynchronous programming (TAP) model, which is the recommended approach for new development. TAP uses the async and await keywords, along with the Task classes, to achieve asynchronicity in a concise, readable way.

Why C# socket server can't find the eof from python client?

update
no matter \r\n or '\n' neither of them works.
if I change the indexof("<eof>")> -1 to index("<eof>") == -1, it worked. And I Google it and find that the eof always be at the -1 but I don't know why, the msdn can't be wrong.
The code is simple I just copy them from
python tutorial
C# MSDN
If I use the server code in the first link in Python, the python can print out the msg sent from client. But if I use the C# server, the indexof("<EOF>") always be -1, which means the msg sent from client never be printed by the C# server, why?
Server code
C#
using System;
using System.Net;
using System.Net.Sockets;
using System.Text;
using System.Threading;
// State object for reading client data asynchronously
public class StateObject
{
// 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 StringBuilder sb = new StringBuilder();
}
public class AsynchronousSocketListener
{
// Thread signal.
public static ManualResetEvent allDone = new ManualResetEvent(false);
public AsynchronousSocketListener()
{
}
public static void StartListening()
{
// Data buffer for incoming data.
byte[] bytes = new Byte[1024];
// Establish the local endpoint for the socket.
// The DNS name of the computer
// running the listener is "host.contoso.com".
IPHostEntry ipHostInfo = Dns.Resolve(Dns.GetHostName());
IPAddress ipAddress = ipHostInfo.AddressList[0];
IPEndPoint localEndPoint = new IPEndPoint(ipAddress, 11000);
// Create a TCP/IP socket.
Socket listener = new Socket(AddressFamily.InterNetwork,
SocketType.Stream, ProtocolType.Tcp);
// Bind the socket to the local endpoint and listen for incoming connections.
try
{
listener.Bind(localEndPoint);
listener.Listen(100);
while (true)
{
// Set the event to nonsignaled state.
allDone.Reset();
// Start an asynchronous socket to listen for connections.
Console.WriteLine("Waiting for a connection...");
listener.BeginAccept(
new AsyncCallback(AcceptCallback),
listener);
// Wait until a connection is made before continuing.
allDone.WaitOne();
}
}
catch (Exception e)
{
Console.WriteLine(e.ToString());
}
Console.WriteLine("\nPress ENTER to continue...");
Console.Read();
}
public static void AcceptCallback(IAsyncResult ar)
{
// Signal the main thread to continue.
allDone.Set();
// Get the socket that handles the client request.
Socket listener = (Socket)ar.AsyncState;
Socket handler = listener.EndAccept(ar);
// Create the state object.
StateObject state = new StateObject();
state.workSocket = handler;
handler.BeginReceive(state.buffer, 0, StateObject.BufferSize, 0,
new AsyncCallback(ReadCallback), state);
}
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();
int res = 0;
res = content.IndexOf("<EOF>");
if (res > -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);
}
}
}
private static void Send(Socket handler, String data)
{
// Convert the string data to byte data using ASCII encoding.
byte[] byteData = Encoding.ASCII.GetBytes(data);
// Begin sending the data to the remote device.
handler.BeginSend(byteData, 0, byteData.Length, 0,
new AsyncCallback(SendCallback), handler);
}
private static void SendCallback(IAsyncResult ar)
{
try
{
// Retrieve the socket from the state object.
Socket handler = (Socket)ar.AsyncState;
// Complete sending the data to the remote device.
int bytesSent = handler.EndSend(ar);
Console.WriteLine("Sent {0} bytes to client.", bytesSent);
handler.Shutdown(SocketShutdown.Both);
handler.Close();
}
catch (Exception e)
{
Console.WriteLine(e.ToString());
}
}
public static int Main(String[] args)
{
StartListening();
return 0;
}
}
client code
python
#!/usr/bin/python3 # This is client.py file
import socket
# create a socket object
s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
# get local machine name
host = socket.gethostname()
port = 11000
# connection to hostname on the port.
s.connect((host, port))
msg='Hi Server!'+ "\r\n"
s.send(msg.encode('ascii'))
# Receive no more than 1024 bytes
msg = s.recv(1024)
s.close()
print (msg.decode('ascii'))
This can be due to different line endings: \n and \r\n.
Check your apps are sending and awaiting the same.

TCP C# Server Python Client cannot communicate

I am writing some socket server, client application and I have a major problem. My goal is to create an async Server App in C# and a basic client APP in python. When I do follow simple examples both program work. But when I write an async Server with read and write handler messages being send from the client APP, it does not work.
Here is the example Server code that I am using.
using System;
using System.Net;
using System.Net.Sockets;
using System.Text;
using System.Threading;
// State object for reading client data asynchronously
public class StateObject
{
// 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 StringBuilder sb = new StringBuilder();
}
public class AsynchronousSocketListener
{
// Thread signal.
public static ManualResetEvent allDone = new ManualResetEvent(false);
public AsynchronousSocketListener()
{
}
public static void StartListening()
{
// Data buffer for incoming data.
byte[] bytes = new Byte[1024];
// Establish the local endpoint for the socket.
// The DNS name of the computer
// running the listener is "host.contoso.com".
IPHostEntry ipHostInfo = Dns.Resolve(Dns.GetHostName());
IPAddress ipAddress = ipHostInfo.AddressList[0];
IPEndPoint localEndPoint = new IPEndPoint(ipAddress, 3333);
IPEndPoint ipLocal = new IPEndPoint(IPAddress.Any, 3333);
// Create a TCP/IP socket.
Socket listener = new Socket(AddressFamily.InterNetwork,
SocketType.Stream, ProtocolType.Tcp);
// Bind the socket to the local endpoint and listen for incoming connections.
try
{
listener.Bind(ipLocal);
listener.Listen(100);
while (true)
{
// Set the event to nonsignaled state.
allDone.Reset();
// Start an asynchronous socket to listen for connections.
Console.WriteLine("Waiting for a connection...");
listener.BeginAccept(
new AsyncCallback(AcceptCallback),
listener);
// Wait until a connection is made before continuing.
allDone.WaitOne();
}
}
catch (Exception e)
{
Console.WriteLine(e.ToString());
}
Console.WriteLine("\nPress ENTER to continue...");
Console.Read();
}
public static void AcceptCallback(IAsyncResult ar)
{
// Signal the main thread to continue.
allDone.Set();
// Get the socket that handles the client request.
Socket listener = (Socket)ar.AsyncState;
Socket handler = listener.EndAccept(ar);
// Create the state object.
StateObject state = new StateObject();
state.workSocket = handler;
handler.BeginReceive(state.buffer, 0, StateObject.BufferSize, 0, new AsyncCallback(ReadCallback), state);
}
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);
Console.WriteLine("\n Enters(0)");
if (bytesRead > 0)
{
Console.WriteLine("\n Enters(1)");
// 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
{
Console.WriteLine("\n Detect");
// Not all data received. Get more.
handler.BeginReceive(state.buffer, 0, StateObject.BufferSize, 0,
new AsyncCallback(ReadCallback), state);
}
}
Console.WriteLine("\n Enters(1)");
}
private static void Send(Socket handler, String data)
{
// Convert the string data to byte data using ASCII encoding.
byte[] byteData = Encoding.ASCII.GetBytes(data);
// Begin sending the data to the remote device.
handler.BeginSend(byteData, 0, byteData.Length, 0,
new AsyncCallback(SendCallback), handler);
}
private static void SendCallback(IAsyncResult ar)
{
try
{
// Retrieve the socket from the state object.
Socket handler = (Socket)ar.AsyncState;
// Complete sending the data to the remote device.
int bytesSent = handler.EndSend(ar);
Console.WriteLine("Sent {0} bytes to client.", bytesSent);
handler.Shutdown(SocketShutdown.Both);
handler.Close();
}
catch (Exception e)
{
Console.WriteLine(e.ToString());
}
}
public static int Main(String[] args)
{
StartListening();
return 0;
}
}
and here is the python code for a simple test client
import socket
HOST, PORT = "127.0.0.1", 3333
data = "data"
sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
try:
sock.connect((HOST, PORT))
sock.sendall(data)
print data
finally:
sock.close()
As I have inserted some debug code on Server's ReadCallback, I see that the routine is called, but it doesn't process the received data as a message. It doesn't seem to have an endpoint.
Any ideas or solutions will be appreciated.
Your ReadCallback ignores the case when bytesRead == 0, which means the client stopped sending data. If your Python code is actually sending "data" without "<EOF>", then your connection is simply forgotten by the C# server.
Regarding your C# code, there are a few things you could improve:
Use ManualResetEventSlim, it's faster, it doesn't use an operating system handle (unless you actually use the WaitHandle property)
You should handle exceptions from EndAccept in AcceptCallback and EndReceive in ReadCallback, and probably improve exception handling in SendCallback
You're creating a string from your StringBuilder in ReadCallback every time, which goes totally against the purpose of using a StringBuilder; you should parse each string you get from Encoding.ASCII.GetString to search for each character, <, E, O, F and > in succession
// Add to StateObject
public const string EOF = "<EOF>";
public int eofOffset = -1;
public int searchOffset = 0;
// In ReadCallback
string data = Encoding.ASCII.GetString(state.buffer, 0, bytesRead);
state.sb.Append(data);
int o = state.searchOffset + state.eofOffset + 1;
while (o < state.sb.Length)
{
if (state.sb[o] != StateObject.EOF[state.eofOffset + 1])
{
state.eofOffset = -1;
state.searchOffset++;
o = state.searchOffset;
}
else
{
state.eofOffset++;
if (state.eofOffset == StateObject.EOF.Length)
{
break;
}
o++;
}
}
// Replace this:
//content = state.sb.ToString();
//if (content.IndexOf("<EOF>") > -1)
// with this:
if (state.eofOffset == StateObject.EOF.Length)
{
// Here is a good place to turn the StringBuilder into a string
// Perhaps truncate data to send back up to state.searchOffset
// ...
}
Not an expert for C#, but I think You have problem with Python program.
try:
sock.connect((HOST, PORT))
sock.sendall("data")
print data
finally:
sock.close()
You're trying to print data, which is not defined. Therefore, except part would be executed (if it existed). Then, program is finished with socket being closed.

Reading information from a port waits even though data available

I am having a problem sending information down a socket and receiving a response. I have a demo program which is performing correctly so I know it is not an issue with the client on the other end.
The requestData is sent and the client acts correctly and responds, but my code never exits the loop in read response.
Could the client be responding before I am listening? How can I make sure I never miss an incoming message?
networkStream = tcpClient.GetStream();
StreamWriter clientStreamWriter = new StreamWriter();
clientStreamWriter.WriteLine(requestData);
clientStreamWriter.Flush();
// Continuously read data on the socket and if it is more than just a ping, read the response.
StringBuilder sbReadBuffer = new StringBuilder();
while (true)
{
String response = readresponse(timeoutOn30Seconds);
if (response.Length > 1 && (!response.Contains("\r\n") || response.Contains(",")))
{
break;
}
}
sbReadBuffer.Append(received);
return sbReadBuffer.ToString();
readResponse:
private string readresponse(Boolean timeoutOn30Seconds)
{
// Get network stream.
DateTime lastConTime = DateTime.Now;
Int32 i = 0;
// Start listening to stream.
while (!networkStream.DataAvailable)
{
Log.W(".");
// Only check every 10ms.
Thread.Sleep(10);
// If no response in 30mins stop listening and give an offline warning.
if ((DateTime.Now - lastConTime).TotalSeconds > tcpClient.ReceiveTimeout)
{
received = "CLIENT NOT FOUND";
return received;
}
// Only check if application online every 1s.
if (i > 100)
{
if (Process.GetProcessesByName(ConfigurationManager.AppSettings["ClientName"]).FirstOrDefault() == null && Convert.ToInt32(ConfigurationManager.AppSettings["Device"]) != 680)
{
received = "CLIENT NOT FOUND";
return received;
}
i = 0;
}
i++;
}
// If data has been writted to the buffer, read it out and assign output variable and return that string for length comparison.
byte[] receiveBuffer = new byte[tcpClient.ReceiveBufferSize];
Int32 receiveCount = networkStream.Read(receiveBuffer, 0, receiveBuffer.Length);
received = new ASCIIEncoding().GetString(receiveBuffer, 0, receiveCount);
return received;
}
DataAvailable isn't a good method to know if data are coming, especially in a while loop that is surely faster than network communications.
A better way could be to use the Read method (bytes read) to know where data are available, into a timed loop; so change your while condition in this manner (and then adjust the other parts)
while (networkStream.Read(receiveBuffer, 0, receiveBuffer.Length) > 0)
{
Log.W(".");
// Only check every 10ms.
Thread.Sleep(10);
but I prefer, if possible, an async approach, so your client will be notified when data are incoming.
See this answer that use this kind of approach.
Basically set an async callback that will be fired when data are coming
public void StartListening() {
IPHostEntry ipHostInfo = Dns.Resolve(Dns.GetHostName());
IPEndPoint localEP = new IPEndPoint(ipHostInfo.AddressList[0],11000);
Console.WriteLine("Local address and port : {0}",localEP.ToString());
Socket listener = new Socket( localEP.Address.AddressFamily,
SocketType.Stream, ProtocolType.Tcp );
try {
listener.Bind(localEP);
listener.Listen(10);
while (true) {
allDone.Reset();
Console.WriteLine("Waiting for a connection...");
listener.BeginAccept(
new AsyncCallback(SocketListener.acceptCallback),
listener );
allDone.WaitOne();
}
} catch (Exception e) {
Console.WriteLine(e.ToString());
}
Console.WriteLine( "Closing the listener...");
}
and there you can read your data
public static void acceptCallback(IAsyncResult ar) {
// Get the socket that handles the client request.
Socket listener = (Socket) ar.AsyncState;
Socket handler = listener.EndAccept(ar);
// Signal the main thread to continue.
allDone.Set();
// Create the state object.
StateObject state = new StateObject();
state.workSocket = handler;
handler.BeginReceive( state.buffer, 0, StateObject.BufferSize, 0,
new AsyncCallback(AsynchronousSocketListener.readCallback), state);
}
Here full MSDN documentation
You dont read in while loop. To clear DataAvailable flag, you have to read from networkStream.
Sample usage :
http://msdn.microsoft.com/en-us/library/system.net.sockets.networkstream.dataavailable%28v=vs.100%29.aspx

Sending and receiving progress monitoring in socket asynchronous

I saw examples of asynchronous socket server here http://msdn.microsoft.com/en-us/library/fx6588te.aspx#Y0
How do I know the total of bytes that are currently being received and the total of bytes that is currently being sent by the server and display that to progress bar? Thank You.
using System;
using System.Net;
using System.Net.Sockets;
using System.Text;
using System.Threading;
// State object for reading client data asynchronously
public class StateObject {
// 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 StringBuilder sb = new StringBuilder();
}
public class AsynchronousSocketListener {
// Thread signal.
public static ManualResetEvent allDone = new ManualResetEvent(false);
public static void StartListening() {
// Data buffer for incoming data.
byte[] bytes = new Byte[1024];
// Establish the local endpoint for the socket.
// The DNS name of the computer
// running the listener is "host.contoso.com".
IPHostEntry ipHostInfo = Dns.Resolve(Dns.GetHostName());
IPAddress ipAddress = ipHostInfo.AddressList[0];
IPEndPoint localEndPoint = new IPEndPoint(ipAddress, 11000);
// Create a TCP/IP socket.
Socket listener = new Socket(AddressFamily.InterNetwork,
SocketType.Stream, ProtocolType.Tcp );
// Bind the socket to the local endpoint and listen for incoming connections.
try {
listener.Bind(localEndPoint);
listener.Listen(100);
while (true) {
// Set the event to nonsignaled state.
allDone.Reset();
// Start an asynchronous socket to listen for connections.
Console.WriteLine("Waiting for a connection...");
listener.BeginAccept(
new AsyncCallback(AcceptCallback), listener );
// Wait until a connection is made before continuing.
allDone.WaitOne();
}
} catch (Exception e) {
Console.WriteLine(e.ToString());
}
Console.WriteLine("\nPress ENTER to continue...");
Console.Read();
}
public static void AcceptCallback(IAsyncResult ar) {
// Signal the main thread to continue.
allDone.Set();
// Get the socket that handles the client request.
Socket listener = (Socket) ar.AsyncState;
Socket handler = listener.EndAccept(ar);
// Create the state object.
StateObject state = new StateObject();
state.workSocket = handler;
handler.BeginReceive( state.buffer, 0, StateObject.BufferSize, 0,
new AsyncCallback(ReadCallback), state);
}
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);
}
}
}
private static void Send(Socket handler, String data) {
// Convert the string data to byte data using ASCII encoding.
byte[] byteData = Encoding.ASCII.GetBytes(data);
// Begin sending the data to the remote device.
handler.BeginSend(byteData, 0, byteData.Length, 0,
new AsyncCallback(SendCallback), handler);
}
private static void SendCallback(IAsyncResult ar) {
try {
// Retrieve the socket from the state object.
Socket handler = (Socket) ar.AsyncState;
// Complete sending the data to the remote device.
int bytesSent = handler.EndSend(ar);
Console.WriteLine("Sent {0} bytes to client.", bytesSent);
handler.Shutdown(SocketShutdown.Both);
handler.Close();
} catch (Exception e) {
Console.WriteLine(e.ToString());
}
}
public static int Main(String[] args) {
StartListening();
return 0;
}
}
The TCP protocol does not specify the message size, you have to do this within the payload that you are sending.
You could prepend the data length to the the data that you are sending down the pipe and read this as on receipt of the first chunk of data. This will then give you the total data size which you can use to calculate the percentage read, which you can display as a progress bar.
This is a lot of code and I am not going to read it.
The Socket class does not remember how many bytes you have written to it and how many bytes came out of it. You can track that yourself in two variables of type long.
If you want to know how many bytes are currently queued, you can find out using the Socket.Available property for the receive queue. For the send queue you cannot find out.

Categories