I am implementing Master/Slave architecture in my application.
Master polls the jobs from the database and then distributes jobs among the slaves. I am using socket connection to maintain the connection among the master and slaves and to send the job to the client.
As soon as the master initiates the process, one thread starts creating the job queue and another thread starts to get job from the queue and feed them to all the connected slaves one by one. Once the slave finishes the job, it will send some acknowledgement to the master that it is free and master again feeds the job to that client. If queue is empty master just sends some acknowledgement to the client after which client again sends some acknowledgement to the master and master again checks the queue and send the job if available. This process keeps on going until the master decides that all the jobs are done.
Acknowledgement is nothing but some constant value. Whenever client receives this constant value client sends the same value back to the master and if master receives this constant values it sends the job if available in the queue else send the same value back to the client. This way master and slaves keep on communicating until the jobs are all done.
I am working with c# windows server using asynchronous sockets.
My problem is while handling data being received on client side, some time client is getting overlapping values. It is happening in the following event of client socket:
public void OnDataReceived(IAsyncResult asyn)
{
SocketPacket theSockId = null;
try
{
theSockId = (SocketPacket)asyn.AsyncState;
int iRx = theSockId.currentSocket.EndReceive(asyn);
char[] chars = new char[iRx + 1];
System.Text.Decoder d = System.Text.Encoding.UTF8.GetDecoder();
int charLen = d.GetChars(theSockId.dataBuffer, 0, iRx, chars, 0);
System.String szData = new System.String(chars);
if (OnDataRecievedFromMaster != null)
{
OnDataRecievedFromMaster(Convert.ToInt32(szData), theSockId.hostName);
}
//richTextRxMessage.Text = richTextRxMessage.Text + szData;
WaitForData(theSockId.hostName);
}
catch (ObjectDisposedException)
{
System.Diagnostics.Debugger.Log(0, "1", "\nOnDataReceived: Socket has been closed\n");
}
catch (SocketException se)
{
if (se.ErrorCode == 10054) // Error code for Connection reset by peer
{
//string msg = "Client " + socketData.hostName + " Disconnected" + "\n";
//AppendToRichEditControl(msg);
// Remove the reference to the worker socket of the closed client
// so that this object will get garbage collected
}
}
finally
{
}
}
on this event, the value of szdata is not the original value what master really sent. Most of the time the value is repeated. I am only sending integer values to client or server, no strings.
Any kind of input on why I am getting this will really be appreciated.
How are you scheduling the two threads - master and slave, if you let both of them run without any synchronization there may be a issue. Suppose the slave keeps on checking for the data without the master giving it, in that case you could end up with multiple repeated values on the client end. The fact that you are getting this error only sometimes and not always points to a concurrency bug.
Related
I'm fairly new in trying to program with Sockets. I have a class whose instance variables include a client's socket and a client's thread, in the name called clientInfo. I created a list of clientInfos to keep track of the connections going into the server, where I've successfully managed to have multiple clients send messages to each other.
listOfClients.Add(new clientInfo(listen.Accept()));
The thread of the clientInfo is in an infinite loop to always receive incoming data, as shown in the code below. The idea that I had was, if I get an exception from the server trying to receive data from a disconnected client, all I should do is remove the client in the list causing the exception, right?
I would iterate through the clients to find exactly at which spot in the list the error is coming from by sending a heartbeat message. Should sending fail, I now have the exact location of the problematic socket and then I would then close their socket, abort the thread, and remove the clientInfo from the list, right? I hope that I have the right idea for that logic. However, when I do so, I've still yet to truly solve the exception which is why (I think) the code shoots itself in the foot by closing all other connections as well. Honestly, I'm at a loss of what to do to solve this.
There's also the unfortunate factor of sending packets to each socket in the list, where the ObjectDisposedException is raised should I close, abort, and remove a socket from a list. Is there a way to completely remove an item from the list as if it were never added in the first place? I assumed removeAt(i) would have done so, but I'm wrong about that.
I've read many answers stating that the best way to handle clients disconnecting is to use socket.close() and list.removeAt(i). My desired goal is that, even if 98 out of 100 clients unexpectedly lose connection, I would like the remaining two clients to still be able to send each other packets through the server. Am I on the right path or is my approach completely wrong?
byte[] buff;
int readBytes;
while (true) {
try {
buff = new byte[clientSocket.SendBufferSize];
readBytes = clientSocket.Receive(buff);
//This line raises an exception should a client disconnect unexpectedly.
if (readBytes > 0) {
Packet pack = new Packet(buff);
handleData(pack);
}
}
catch(SocketException e) {
Console.WriteLine("A client disconnected!");
for (int i = 0; i < listOfClients.Count; i++) {
try {
string message = "This client is alive!";
Packet heartbeat = new Packet(Packet.PacketType.Send, "Server");
heartbeat.data.Add(message);
clientSocket.Send(heartbeat.toByte());
}
catch (SocketException ex) {
Console.WriteLine("Removing " + listOfClients[i].clientEndPointy.Address + ":" + listOfClients[i].clientEndPointy.Port);
//listOfClients[i].clientSocket.Disconnect(reuseSocket: true);
listOfClients[i].clientSocket.Close();
listOfClients[i].clientThread.Abort();
listOfClients.RemoveAt(i);
}
}
}
}
I am working on client-server appliction in C#. The comunication between them is with TCP sockets. The server listen on specific port for income clients connection. After a new client arrived, his socket being saved in a socket list. I define every new client socket with receive timeout of 1 ms. To receive from the client sockets without blocking my server I use the threadpool like this:
private void CheckForData(object clientSocket)
{
Socket client = (Socket)clientSocket;
byte[] data = new byte[client.ReceiveBufferSize];
try
{
int dataLength = client.Receive(data);
if (dataLength == 0)// means client disconnected
{
throw (new SocketException(10054));
}
else if (DataReceivedEvent != null)
{
string RemoteIP = ((IPEndPoint)client.RemoteEndPoint).Address.ToString();
int RemotePort = ((IPEndPoint)client.RemoteEndPoint).Port;
Console.WriteLine("SERVER GOT NEW MSG!");
DataReceivedEvent(data, new IPEndPoint(IPAddress.Parse(RemoteIP), RemotePort));
}
ThreadPool.QueueUserWorkItem(new WaitCallback(CheckForData), client);
}
catch (SocketException e)
{
if (e.ErrorCode == 10060)//recieve timeout
{
ThreadPool.QueueUserWorkItem(new WaitCallback(CheckForData), client);
}
else if(e.ErrorCode==10054)//client disconnected
{
if (ConnectionLostEvent != null)
{
ConnectionLostEvent(((IPEndPoint)client.RemoteEndPoint).Address.ToString());
DisconnectClient(((IPEndPoint)client.RemoteEndPoint).Address.ToString());
Console.WriteLine("client forcibly disconected");
}
}
}
}
My problem is when sometimes the client send 2 messages one after another, the server doesn't receive the second message. I checked with wireshark and it shows that both of the messages were received and also got ACK.
I can force this problem to occur when I am putting break point here:
if (e.ErrorCode == 10060)//recieve timeout
{
ThreadPool.QueueUserWorkItem(new WaitCallback(CheckForData), client);
}
Then send the two messages from the client, then releasing the breakpoint.
Does anyone met this problem before?
my problem is when sometimes the client send 2 messages one after another, the server doesn't receive the second message
I think it's much more likely that it does receive the second message, but in a single Receive call.
Don't forget that TCP is a stream protocol - just because the data is broken into packets at a lower level doesn't mean that one "send" corresponds to one "receive". (Multiple packets may be sent due to a single Send call, or multiple Send calls may be coalesced into a single packet, etc.)
It's generally easier to use something like TcpClient and treat its NetworkStream as a stream. If you want to layer "messages" on top of TCP, you need to do so yourself - for example, prefixing each message with its size in bytes, so that you know when you've finished receiving one message and can start on the next. If you want to handle this asynchronously, I'd suggest sing C# 5 and async/await if you possibly can. It'll be simpler than dealing with the thread pool explicitly.
Message framing is what you need to do. Here: http://blog.stephencleary.com/2009/04/message-framing.html
if you are new to socket programming, I recommend reading these FAQs http://blog.stephencleary.com/2009/04/tcpip-net-sockets-faq.html
To start I am coding in C#. I am writing data of varying sizes to a device through a socket. After writing the data I want to read from the socket because the device will write back an error code/completion message once it has finished processing all of the data. Currently I have something like this:
byte[] resultErrorCode = new byte[1];
resultErrorCode[0] = 255;
while (resultErrorCode[0] == 255)
{
try
{
ReadFromSocket(ref resultErrorCode);
}
catch (Exception)
{
}
}
Console.WriteLine(ErrorList[resultErrorCode[0] - 48]);
I use ReadFromSocket in other places, so I know that it is working correctly. What ends up happening is that the port I am connecting from (on my machine) changes to random ports. I think that this causes the firmware on the other side to have a bad connection. So when I write data on the other side, it tries to write data to the original port that I connected through, but after trying to read several times, the connection port changes on my side.
How can I read from the socket continuously until I receive a completion command? If I know that something is wrong with the loop because for my smallest test file it takes 1 min and 13 seconds pretty consistently. I have tested the code by removing the loop and putting the code to sleep for 1 min and 15 seconds. When it resumes, it successfully reads the completion command that I am expecting. Does anyone have any advice?
What you should have is a separate thread which will act like a driver of your external hardware. This thread will receive all data, parse it and transmit the appropriate messages to the rest of your application. This portion of code will give you an idea of how receive and parse data from your hardware.
public void ContinuousReceive(){
byte[] buffer = new byte[1024];
bool terminationCodeReceived = false;
while(!terminationCodeReceived){
try{
if(server.Receive(buffer)>0){
// We got something
// Parse the received data and check if the termination code
// is received or not
}
}catch (SocketException e){
Console.WriteLine("Oops! Something bad happened:" + e.Message);
}
}
}
Notes:
If you want to open a specific port on your machine (some external hardware are configured to talk to a predefined port) then you should specify that when you create your socket
Never close your socket until you want to stop your application or the external hardware API requires that. Keeping your socket open will resolve the random port change
using Thread.Sleep when dealing with external hardware is not a good idea. When possible, you should either use events (in case of RS232 connections) or blocking calls on separate threads as it is the case in the code above.
Sometimes when reading a socket from the TcpClient class, the stream comes in without interpreting the data instantly. For example if I connect to an IRC server and I want to interpret the text in the channel to recognize commands. If somebody types a command, !time and !time is a valid function, it would write back to the server the current time.
The problem is if someone spams that same command !time at a high rate, the socket would be flooded. If someone else tried to execute !time it would not write back to the server until the while() loop finished reading the flooded socket stream. This could take minutes if not at all if the user kept spamming/flooding the command.
static void Connect(String hostname, int port)
{
try
{
socket = new TcpClient(hostname, port);
socket.ReceiveBufferSize = 4096;
Console.WriteLine("Successfully connected to " + hostname);
NetworkStream stream = socket.GetStream();
reader = new StreamReader(stream);
writer = new StreamWriter(stream);
write("USER " + username + " 8 * :" + description, writer);
write("NICK " + username, writer);
write("NS IDENTIFY " + password, writer);//Authenticate account
read(reader);//read the stream
reader.Close();
writer.Close();
stream.Close();
socket.Close();
}
catch
{
Console.WriteLine("Failed to connect to " + hostname);
}
}
read() function below:
static void read(StreamReader reader)
{
try
{
while (true)
{
interpret(reader.ReadLine());
}
}
catch
{
Console.WriteLine("Unable to read from server");
}
}
What could I do so the stream cannot be harmed if it were to be flooded? So that if someone did flood the stream with !time it would not stop other users from also seeing the time if they so typed !time.
Thank you.
Chatbot solution
You will have to process all the incoming text at least far enough to separate messages, and determine what user sent each message. Then you can split them into separate queues by user. You can either process the queues round-robin, or randomly. Or, you can implement a token bucket scheme, where every n seconds all users are given a certain number of tokens, and every command uses up a token. Users aren't allowed to go above a limit of a certain number of tokens (p seconds worth of tokens they're allowed to hoard). If there's no token for that user when a command arrives, either throw it away or queue it for the next time tokens are given out.
Server-side solution
The other users have their own sockets, don't they?
A backlog on one socket doesn't prevent you from reading the others. You just have to write the application logic so it doesn't get stuck reading from one, it goes round-robin and only reads more from the first after everyone has had a chance.
Typically you use some function like select or WaitAny which yield a list of ready sockets. Don't always read from the first socket in the list, pick the one which most closely follows the last one you read, or else pick one randomly.
I have a number of C# software applications that are add-ins for a peice of software that has a .net API.
for software licensing purposes I'm required to have a license server. I've got this, at the moment this is what it does:
when a tool is run, it contacts the license server with its computer name and username
the server recieves this request, logs the request, and checks to see if the number of requests from that machien and or user have exceeded the preconfigured maximum (2 different licensing types)
it does this using an encrypted file which lists the time, machine name, username etc
if its ok, it returns OKAY response to the computer and the tool then runs
if it doesnt return anything or if it returns a not OK response the tool will not run (the software only runs for a short time, but is regulary ran, as opposed to opening for a long time)
This works great, except I'm having a problem that the server randomly crashes, and users can't get onto it.
This is the first client-server app I've done and I'm a bit in the dark (and feel like I'm re-inventing something which is commonly used), is there any good guides for creating something like that? My apps is very simple, I have a service running on the server looping listening on a TCP port, waiting for something to be sent.
public void StartListening()
{
Listening = true;
// Set the TcpListener on port 41616.
Int32 port = 41616;
IPAddress localAddr = IPAddress.Any;
// TcpListener server = new TcpListener(port);
server = new TcpListener(localAddr, port);
// Start listening for client requests.
server.Start();
Listen();
}
public void Listen()
{
try
{
// Buffer for reading data
Byte[] bytes = new Byte[256];
String data = null;
// Enter the listening loop.
while (Listening)
{
TcpClient client = server.AcceptTcpClient();
// Get a stream object for reading and writing
NetworkStream stream = client.GetStream();
int i;
// Loop to receive all the data sent by the client.
while ((i = stream.Read(bytes, 0, bytes.Length)) != 0)
{
// Translate data bytes to a ASCII string.
data = System.Text.Encoding.ASCII.GetString(bytes, 0, i);
Console.WriteLine("Received: {0}", data);
string returnData;
// Process the data sent by the client.
data = data.ToUpper();
byte[] msg = null;// DO STUFF BASED ON DATA
// set returnData to be the response (ie OKAY)
msg = System.Text.Encoding.ASCII.GetBytes(returnData);
// Send back a response.
stream.Write(msg, 0, msg.Length);
Console.WriteLine("Sent: {0}", returnData);
// Shutdown and end connection
client.Close();
}
}
catch (Exception ex)
{
//LOG ERROR
}
finally
{
Listening = false;
server.Stop();
}
}
I have a feeling the server is hanging somewhere on the decryption /encryption of the license log, as the server runs fine for a while then just stops, and if i re-create the license log it works. But thats not the point of this post (though any tips on why I'm getting this error:
Error occured: Unable to read data from the transport connection: An existing connection was forcibly closed by the remote host. at System.Net.Sockets.NetworkStream.Read(Byte[] buffer, Int32 offset, Int32 size)
at BWSSLicenseServer.LicenseServer.Listen()
woudl be great)
My question is - how do I debug this easily in .NET? is there any good guides out there to help me? or is there any free framework for this? Should I be doing this code a totally different way (WCF, Web Service or something like that?)
ended up using CryptoLicensing as suggested in the comments
It may be something to do with the object expiring. Try adding this to your server class:
public override object InitializeLifetimeService()
{
return null;
}