I've a thread that runs following tcpConnect method. I wish to stop it at any given time by setting Program.PrepareExit to true. However my program is stuck at:
Int32 bytes = stream.Read(data, 0, data.Length); and doesn't really react to Program.PrepareExit set to true. How can i make it to always quit when I tell it so?
public static readonly Thread MyThreadTcpClient = new Thread(ThreadTcpClient);
private static void ThreadTcpClient() {
Connections.tcpConnect(ClientTcpIp, ClientTcpPort);
}
public static void Main() {
MyThreadTcpClient.Start();
.... some code....
Program.PrepareExit = true;
}
public static bool tcpConnect(string varClientIp, int varClientPort) {
var client = new TcpClient();
try {
client = new TcpClient(varClientIp, varClientPort) {NoDelay = true};
NetworkStream stream = client.GetStream();
var data = new Byte[256];
while (!Program.PrepareExit) {
Int32 bytes = stream.Read(data, 0, data.Length);
string varReadData = Encoding.ASCII.GetString(data, 0, bytes);
if (varReadData != "" && varReadData != "echo") {
VerificationQueue.EnqueueRelease(varReadData);
}
}
} catch (ArgumentNullException e) {
MessageBox.Show(e.ToString(), "ArgumentNullException");
tcpConnect(varClientIp, varClientPort);
} catch (SocketException e) {
MessageBox.Show(e.ToString(), "SocketException");
tcpConnect(varClientIp, varClientPort);
} catch (IOException e) {
if (e.ToString() != "Unable to read data from the transport connection: An existing connection was forcibly closed by the remote host.") {
}
MessageBox.Show(e.ToString());
tcpConnect(varClientIp, varClientPort);
} finally {
client.Close();
}
return false;
}
Three options suggest themselves:
Make the thread a daemon (background) thread. The process will exit when the only live threads are daemon threads
Set a timeout on the read call, possibly having to change to use the underlying socket API. That won't be pretty, to be honest.
Use asynchronous IO. Also a bit of a pain.
Do you need this thread to do anything in terms of an orderly shutdown? If not, the daemon thread approach would probably be simplest.
Related
I'm really confused. I am able to connect a TCPClient to a tcp server asynchronously. In my callback I now want to start reading some data, but when I go stream = tcpClient.GetStream(); my program doesn't exactly hang, it just does nothing. It won't go to the next line of the method, but the UI is still running (it's Unity, maybe it is multithreaded or something).
public void SetupSocket() {
try {
tcpClient = new TcpClient(host, port);
tcpClient.BeginConnect(host, port, ConnectCallback, tcpClient);
}
catch (Exception e) {
// stuff happens
return;
}
}
private void ConnectCallback(IAsyncResult result) {
if (ConnectedToServer != null)
ConnectedToServer(this, new ServerEventArgs("Connected to server."));
Debug.Log("Where am I?"); // it does get here
try {
stream = tcpClient.GetStream();
}
catch (InvalidOperationException e){
Debug.Log(e); // no exception
}
Debug.Log("Hello?"); // never gets here
BeginReadData();
}
public void BeginReadData() {
Debug.Log(stream.CanRead); // No log here!
if (stream.CanRead) {
stream.BeginRead(tcpStateObject.buffer, 0, tcpStateObject.bufferSize, EndReadData, stream);
}
}
I'm really lost at this point. I can see on my server that I connected, and when I disconnect. I send two messages to the client. It used to work with synchronous sockets, but I wanted async.
Here is the answer
I was connecting twice
tcpClient = new TcpClient(host, port);
tcpClient.BeginConnect(host, port, ConnectCallback, tcpClient);
Hi stack overflow members.
I'm struggling with some simple code but I can't get it done.
I have this asynchronous server which waits for connections.
while (clientSocket.Connected)
{
try
{
clientSocket.BeginReceive(so.buffer, 0, 200, SocketFlags.None
, new AsyncCallback(wait),so);
}
catch (Exception ex)
{
Console.WriteLine(ex.Message);
}
}
where so(shorted StateObject) it's my class:
internal class StateObject
{
public TcpClient client;
public byte[] buffer;
public StateObject()
{
buffer = new byte[200];
client = new TcpClient();
}
}
I use this class to put out the information on the callback function. However I get the system lacked sufficient buffer space or because a queue was full.
I posted a short piece from the actual program.
One interesting issue, is that if I write:
while (clientSocket.Connected)
{
try
{
byte[] buffer = new byte[200];
clientSocket.BeginReceive(buffer, 0, 200, SocketFlags.None
, new AsyncCallback(wait),so);
}
catch (Exception ex)
{
Console.WriteLine(ex.Message);
}
}
it will work, but I will not be able to pull out the buffer from the asynchronous function(wait).
I'm struggling with this and I can't find answers.
The while loop shouldn't be there, just call beginreceive after the endreceive.
This is a poor example, but may give you some ideas:
public class AsyncTCP
{
public void StartReceive()
{
byte[] buffer = new byte[200];
clientSocket.BeginReceive(buffer, 0, 200, SocketFlags.None, (state) =>
{
int bytesReceived = clientSocket.EndReceive(state);
// handle buffer.
if(bytesReceived != 0)
StartReceive();
} ,so);
}
}
If it's about getting the state within the EndReceive handler:
private void StartReceive()
{
StateObject myState = new StateObject();
myState.buffer = new byte[200];
myState.client = _client; // or whatever
myState.client.BeginReceive(so.buffer, 0, 200, SocketFlags.None, new AsyncCallback(wait),myState);
}
private void EndReceive(IAsyncResult result)
{
StateObject myState = (StateObject)result.State;
int bytesReceived = myState.client.EndReceive(result);
// handle myState.buffer
StartReceive();
}
I think there are better ways to do this, like:
- only constructing a receive buffer ones.
- put some packet header/data with lengths in it.
Good luck
How about using some TPL functions. So your code can be simplified a lot
int readBytes = await s.ReceiveTaskAsync(buffer, 0, buffer.Length);
This is the extension method ReceiveTaskAsync
public static class SocketExtensions
{
public static Task<int> ReceiveTaskAsync(this Socket socket, byte[] buffer, int offset, int count)
{
return Task.Factory.FromAsync<int>(
socket.BeginReceive(buffer, offset, count, SocketFlags.None, null, socket),
socket.EndReceive);
}
}
The problem is here
while (clientSocket.Connected)//checks connected
{
try
{
clientSocket.BeginReceive(so.buffer, 0, 200, SocketFlags.None, new AsyncCallback(wait),so);//says begin receive and continues to do endlessly
}
catch (Exception ex)
{
Console.WriteLine(ex.Message);
}
}
You've to call BeginReceive again only after you received the data.
Here's and example from msdn how to do that.
I resolved my previous problem(I just needed to remove the while loop, however I messed it up with some code from a synchronous server).
Now I have another problem, so I will use this same thread.
From what I've searched, and understood, you can open an asynchronous server with BecinAccept like this(main method):
IPEndPoint ipEndPoint = new IPEndPoint(IPAddress.Any, 8082);
TcpListener tcpListener = new TcpListener(IPAddress.Any, 8082);
server = tcpListener.Server;
server.Bind(ipEndPoint);
server.Listen(4);
server.BeginAccept(new AsyncCallback(beginConnection), server);
Then:
static void beginConnection(IAsyncResult iar)
{
Console.WriteLine("Client connected");
Socket s = (Socket)iar.AsyncState;
server = s.EndAccept(iar);
server.Listen(4); // this line was initially absent
server.BeginAccept(beginConnection, s);
}
I want to be able to connect to this server multiple clients.
However, when I try to do this, only the first client connects itself.
The client it's a simple socket, which just echoes back from the server, what we read from the console.
I thought that since in the main method I've called server.Listen(4), I will be able to connect 4 clients.
Then I thought of calling recursively BeginAccept in the beginConnection method.
And last, I received the error, that I must call first the Listen method, so I added that too.
Still no luck.
This is my first question and I hope you can help me.
I have 2 programs, a Server and a Client and my problem is in the Client.
After 2 or 3 days of running, it uses more than 300MB of RAM (I can tell this by seeing the TaskManager) and never releases it! Also, I have to say that this Client receives data every second from GPS devices.
I have analyzed my Client with the ANTS Memory Profiler and I noticed that I create an object several times and they are never destroyed.
Here is my code:
private static TcpClient _client;
private readonly ManualResetEvent _receiveDone = new ManualResetEvent(false);
public void Receive()
{
if (_client.Connected)
{
_receiveDone.Reset();
ObjectState state = new ObjectState();
state.WorkSocket = _client.Client;
state.Data = new byte[_client.ReceiveBufferSize];
_client.Client.BeginReceive(state.Data, 0, Convert.ToInt32(_client.ReceiveBufferSize), 0, ReceiveCallback, state);
if (!_receiveDone.WaitOne(20000))
{
//after 20 seconds WITHOUT RECEIVING DATA, do some code to test if the connection is alive
}
}
}
void ReceiveCallback(IAsyncResult ar)
{
ObjectState state = (ObjectState)ar.AsyncState;
Socket client = state.WorkSocket;
if (client.Connected)
{
int bytesRead = client.EndReceive(ar);
if (bytesRead > 0)
{
string response = Encoding.ASCII.GetString(state.Data, 0, bytesRead);
doProcess(response);
client.BeginReceive(state.Data, 0, Convert.ToInt32(_client.ReceiveBufferSize), 0, ReceiveCallback, state);
_receiveDone.Set();
}
else
{
//Disconnection
}
}
}
public class ObjectState
{
public Socket WorkSocket;
public byte[] Data;
}
The ANTS Memory Profiler tells me I have thousands of live instances of byte[]. (because I always create new instances of ObjectState)
First thing I wanted to do: Dispose all the ObjectState that I create after I call BeginReceive, but I only get the first message.
Then I wanted to stop using the ObjectState... How?
This is my modified code:
private _data byte[];
public void Receive()
{
if (_client.Connected)
{
_receiveDone.Reset();
_data = new byte[_client.ReceiveBufferSize];
_client.Client.BeginReceive(_data, 0, Convert.ToInt32(_client.ReceiveBufferSize), 0, ReceiveCallback, null);
if (!_receiveDone.WaitOne(20000))
{
//after 20 seconds of inactivity do some code to test if the connectio is alive
}
}
}
void ReceiveCallback(IAsyncResult ar)
{
Socket client = _cliente.Client;
if (client.Connected)
{
int bytesRead = client.EndReceive(ar);
if (bytesRead > 0)
{
string response = Encoding.ASCII.GetString(_data, 0, bytesRead);
doProcess(response);
client.BeginReceive(_data, 0, Convert.ToInt32(_client.ReceiveBufferSize), 0, ReceiveCallback, null);
_receiveDone.Set();
}
else
{
//Disconnection
}
}
}
What's wrong with this? I only get the first message, so this is not good.
Then if I remove the _receiveDone.Set it gets all the messages, BUT the _receiveDone.WaitOne(2000) always is executed every 20 seconds, no matter if I actually am receiving data, and this is not good either.
So my question is, what can I do to reduce the using of so much RAM? I hope this explains well what my problem is.
EDIT:
I uploaded these images, I hope they can be helpful too.
if (client.Connected)
{
int bytesRead = client.EndReceive(ar);
// etc..
Calling EndReceive is not optional, you have to call it or you'll leak resources. Use try/catch to catch an ObjectDisposedException.
I think the primary problem is that you're depending on BeginReceive to return 0 bytes when there's nothing available. But that's not how it works. BeginReceive will block until there is data available, or until the client disconnects.
In the first case, the ReceiveCallback passes the state object to client.BeginReceive. Now you have an ObjectState instance out there waiting for data from the client. The _receiveDone event is set, so your Receive method exits but the client connection is still open and you have a pending asynchronous read.
The next time Receive is called, it will create another ObjectState instance and issue another asynchronous read request.
The second case is pretty scary. Your _data array is at class scope and gets reallocated every time. So it's possible that an asynchronous read can fill the buffer you pass it, but then the data is lost when you get to ReceiveCallback.
Your code only does the timeout check for the first receive. After that, things can hang indefinitely. I would suggest something more like:
private _data byte[];
private bool _receiving = false;
public void StartReceiving()
{
if (_receiving)
{
// ERROR: Already receiving
throw new InvalidOperationException();
}
_receiving = true;
Receive();
}
public void Receive()
{
if (_client.Connected)
{
_data = new byte[_client.ReceiveBufferSize];
var ir _client.Client.BeginReceive(_data, 0, Convert.ToInt32(_client.ReceiveBufferSize), 0, ReceiveCallback, null);
if (!_ir.WaitOne(20000))
{
//after 20 seconds of inactivity do some code to test if the connectio is alive
}
}
}
void ReceiveCallback(IAsyncResult ar)
{
Socket client = _cliente.Client;
int bytesRead;
try
{
bytesRead = client.EndReceive(ar);
if (bytesRead > 0)
{
string response = Encoding.ASCII.GetString(_data, 0, bytesRead);
doProcess(response);
// Calling Receive here ensures that the timeout check happens
// with every read.
Receive();
}
else
{
_receiving = false;
}
}
catch
{
// Catch SocketException and others here
}
}
Note that you don't need the _receiveDone event. You can check it with the IAsyncResult.WaitHandle.
I have built a server that receives requests from a client and gives a response that depends on the request Type. If the request type is streaming, the server must send data array. While the server’s streaming data the client may send a stop request to stop the streaming. If the request and the response is transferred on the same TCP connection the server only receives the stop request when all the data has finished streaming to the client. I think I must use Asynchronous write to solve this problem. This is my code:
First I create a loop back to receive connection from clients:
while (!done)
{
try
{
Socket socket = listener.AcceptSocket();
ClientInteraction clIr = new ClientInteraction(socket, statusList);
Thread thread = new Thread(new ThreadStart(clIr.Process));
thread.Start();
}
catch (Exception ex)
{
Console.WriteLine(ex.ToString());
}
}
}
In Process function of ClientInteraction class :
Public void Process()
{
ns = new NetworkStream(socket);
while (true)
{
try
{
this.myReadBuffer = new byte[socket.ReceiveBufferSize];
this.numberOfBytesRead = ns.Read(myReadBuffer, 0, myReadBuffer.Length);
}
catch
{
break;
}
if (numberOfBytesRead == 0)
{
break;
}
else
{
HandleRequest(myReadBuffer, numberOfBytesRead);
}
}
}
In HandleRequest Function, if request’s STREAM, I will send data in an array to client:
Public void HanldeRequest(……)
{
myCompleteMessage = "";
myCompleteMessage =
String.Concat(myCompleteMessage, Encoding.ASCII.GetString(myReadBuffer, 0, numberOfBytesRead));
If(myCompleteMessage == “Stream”)
{
//I get data and call SendData function
foreach(.......)
{
//get data
........
SendData(data);
}
}
}
public void SendData(byte[] data)
{
try
{
//ns.Write(data, 0, data.Length);
ns.BeginWrite(data, 0, data.Length, new AsyncCallback(StreamData), null);
}
catch
{
}
}
public void StreamData(IAsyncResult asynResult)
{
if(asynResult != null)
ns.EndWrite(asynResult);
}
With this code, I connected with client, send data to client. But I still can’t receive Stop request until all data is streamed. Please show me the correct way to fix my problem. Thank you.
I think you can try using multithread to solve this problem. I have met this circumstance and multithread is a good choice to solve. You can create a thread to write and a thread to read.
I have build a basic .NET server-client infrastructure using TcpListener and SocketClient.
It is multithreaded and asynchronious. The problem is, that the server crashes at some point when over 30 clients are connected at once.
I could not yet locate the cause for the crashes though I do use quite a few Try-Catch blocks to make sure to log all excepions.
So I'm thinking, I may be doing something wrong conceptually in the server code. I hope you guys can help me find the cause for those crashes. The code is the following:
Starting server and listening for a connection:
public void StartServer()
{
isConnected = true;
listener.Start();
connectionThread = new Thread(new ThreadStart(ListenForConnection));
connectionThread.Start();
}
private void ListenForConnection()
{
while (isConnected)
{
try
{
TcpClient client = listener.AcceptTcpClient();
ClientConnection connection = new ClientConnection(this, client);
connections.Add(connection);
}
catch (Exception ex)
{
log.Log("Exception in ListenForConnection: " + ex.Message, LogType.Exception);
}
}
}
The ClientConnection class:
public class ClientConnection : IClientConnection
{
private TcpClient client;
private ISocketServer server;
private byte[] data;
private object metaData;
public TcpClient TcpClient
{
get { return client; }
}
internal ClientConnection(ISocketServer server, TcpClient client)
{
this.client = client;
this.server = server;
data = new byte[client.ReceiveBufferSize];
lock (client.GetStream())
{
client.GetStream().BeginRead(data, 0, client.ReceiveBufferSize, ReceiveMessage, null);
}
}
internal void ReceiveMessage(IAsyncResult ar)
{
int bytesRead;
try
{
lock (client.GetStream())
{
bytesRead = client.GetStream().EndRead(ar);
}
if (bytesRead < 1)
return;
byte[] toSend = new byte[bytesRead];
for (int i = 0; i < bytesRead; i++)
toSend[i] = data[i];
// Throws an Event with the data in the GUI Dispatcher Thread
server.ReceiveDataFromClient(this, toSend);
lock (client.GetStream())
{
client.GetStream().BeginRead(data, 0, client.ReceiveBufferSize, ReceiveMessage, null);
}
}
catch (Exception ex)
{
Disconnect();
}
}
public void Disconnect()
{
// Disconnect Client
}
}
And sending data from the server to one or all clients:
public void SendDataToAll(byte[] data)
{
BinaryWriter writer;
try
{
foreach (IClientConnection connection in connections)
{
writer = new BinaryWriter(connection.TcpClient.GetStream());
writer.Write(data);
writer.Flush();
}
}
catch (Exception ex)
{
// Log
}
}
public void SendDataToOne(IClientConnection client, byte[] data)
{
BinaryWriter writer;
try
{
writer = new BinaryWriter(client.TcpClient.GetStream());
writer.Write(data);
writer.Flush();
}
catch (Exception ex)
{
// Log
}
}
At some point the server crashes and I really got no starting point where to even look for the problem. If needed I can provide more code.
Any help is very appreciated :-)
Andrej
You should make access to the connections field thread safe.
In SendData, you are iterating over connections and sending data to each client. If a new client connects when the foreach loop is executing, you will get an exception with the message "Collection was modified; enumeration operation may not execute" since the collection is modified while you are iterating over it which is not allowed.
Modify the line in SendDataToAll to
foreach (IClientConnection connection in connections.ToList())
to make the problem go away (solution is courtesy of Collection was modified; enumeration operation may not execute).
It's possible that the Disconnect call in the catch block of the ClientConnection.ReceiveMessage method is throwing an exception, which then propogates out of the catch and is unhandled.
To be sure of catching all exceptions and logging them, try registering an event handler to the AppDomain.CurrentDomain.UnhandledException event. Also, if you're running the server as a Windows Service, there may be an .NET exception entry in the Application Event Log.