Here is the rumpus.
I am building a networked app using websocket-sharp and I have run into an issue where the server sends hundreds (not consistently the same amount) of duplicate messages to the client, heres the breakdown.
1.) The client connects (This handshake works fine).
2.) Upon client connection the server sends said client the session ID created for that connection. (This works)
3.) The client receives and stores the session ID. (This works and no duplicates are sent here)
4.) The client sends a request to the lobby system on the server to create a match. (This works and is received correctly)
5.) The server receives the match creation requests, creates the match and sends the match data back to the client (One message is actually sent but the client receives hundreds of the same message (all messages are the same size and contain the same info)).
I have reviewed my lobby system logic and there is no loop that could be sending the match creation reply multiple times, furthermore I know that the "Send" method on the server is only being called once.
I have looked through the websocket-sharp documentation, I thought maybe somehow there were hundreds of sessions being made from one connection or some non-sense along those lines but I am connecting one client and only one session exits :/
Let me know if you have any ideas how this could be happening. Thanks in advance.
See below for code.
Server:
Send Method:
public void Send (string path, string targetID, string script, string method, params object[] data) {
print ("SERVER: Sending Message");
WebSocketServiceHost host = null;
GetSocketServer ().WebSocketServices.TryGetServiceHost (path, out host);
if (host != null) {
Network.Packet packet = new Network.Packet ("Server", targetID, script, method, data);
if (targetID != "Broadcast") {
GetSocketServer ().WebSocketServices.Broadcast (Formatter.singleton.Serialize (packet));
} else if (targetID == "Service") {
host.Sessions.Broadcast (Formatter.singleton.Serialize (packet));
} else {
host.Sessions.SendToAsync (Formatter.singleton.Serialize (packet), targetID);
}
}
}
Client:
Receive Methods:
GetPersistent ().OnMessage += MessageHandler;
void MessageHandler (object sender, MessageEventArgs e) {
Debug.Log ("CLIENT: Message Recieved");
Network.singleton.Recieve (e.RawData);
}
Network: (Used by both Server and Client)
Receive Methods:
public void Recieve (byte[] data) {
object obj = Formatter.singleton.Deserialize (data);
messages.Add (messages.Count, obj);
}
IEnumerator ProcessorCoro () {
WaitForSeconds delay = new WaitForSeconds (Time.deltaTime);
while (true) {
if (messages.Count >= 1) {
Process (messages [(messages.Count - 1)]);
messages.Remove ((messages.Count - 1));
}
yield return delay;
}
}
public void Process (object data) {
Network.Packet packet = (Network.Packet)data;
switch (packet.script) {
case "Home":
Home.singleton.SendMessage (packet.method, data, SendMessageOptions.DontRequireReceiver);
break;
case "Arena":
Arena.singleton.SendMessage (packet.method, data, SendMessageOptions.DontRequireReceiver);
break;
case "Client":
Client.singleton.SendMessage (packet.method, data, SendMessageOptions.DontRequireReceiver);
break;
case "Database":
Database.singleton.SendMessage (packet.method, data, SendMessageOptions.DontRequireReceiver);
break;
}
}
At the client side, you need to ensure that you call the following line only once
GetPersistent ().OnMessage += MessageHandler;
Otherwise, you would be registering the same handler multiple times to the message reception.
Note: This behavior could be desired in case you want to attach multiple handlers to the same OnMessage event.
Related
I'm trying to implement file server that sends requested file to the client.
I implemented sending, and receiving part of Server and client, using TCP protocol.
My server sends data packet dequeued from the Packet queue until packet queue is empty, and my Client Receives until received packet number is same as desired packet number.
I used SendAsync() and ReceiveAsync() method from .Net framework.
My program Seems to have no problem when I debug it, But in the real run,
Client Seems to miss some packets sent from the server.. Even Server sent data packets, for some reason, client couldn't receive some data packets. I have no clue how this can happen.
Shouldn't TCP protocol ensure Receiving every packets sent from the server?
Do you have any clues why this happens?
Here is my code..
Receive_completed is callback method for ReceiveAsync() which is called after
ReceuveAsync is completed
and Process_receive function always reads every received bytes from ReceiveAsync(), and returns true if it has completed reading packet (Otherwise, return false, and Receive() method will be called again)
and.. ignore OperationCompleted, and _receivedProperly..
internal void Receive()//method for receiving the call
{
if (_operationState)
{
try
{
bool pending =_user.ClientSocket.ReceiveAsync(_receiveArg); // This will spawn a new thread and call Receive_completed as callback method
if (pending == false)
{
_receivePendingThread = new Thread(CallReceiveCompleted); //Start New thread
_receivePendingThread.Start();
}
}
catch (Exception exception)
{
ExceptionHandler(exception, CommunicatorError.ObjectDisposed);
}
}
}
private void Receive_completed(object sender, SocketAsyncEventArgs e)
{
if (e.LastOperation == SocketAsyncOperation.Receive)
{
bool transferCompleted = false;
try
{
if (e.BytesTransferred == 0)
{
throw new Exception("Socket Closed");
}
if (e.SocketError != SocketError.Success)
{
throw new Exception("Socket Error Occured");
}
}
catch (Exception exception)
{
ExceptionHandler(exception, CommunicatorError.SocketError);
return;
} //Checks for received bytes
//call process_receive here
transferCompleted = Process_receive(); //returns if more packets are left or not (This method Gurantees reading all received bytes from ReceiveAsync()
if (_receivedProperly&& _operationState) //Succeded process
{
if (transferCompleted && _operationState) Receive();//Receive if more bytes are left
else if (_operationState)
{// No more packets to be accepted additionally
CallReceiveCompleted();// Start Callback method
}
}
}
}
I am learning to use the SocketAsyncEventArgs stuff using the MSDN tutorial. I was just wondering a few things, namely how I could go about implementing the server with full-duplex capabilities.
Currently, the MSDN example teaches you to create a server that first listens, then when something is received, to send it back. Only then does the server start listening again.
The problem I am having coming up with my own solution is that the SocketAsyncEventArgs object has only one event, Completed that is fired for both sends and receives. It has no other events.
I read on some horribly translated site that I
must use two SocketAsyncEventArgs, one receives a hair.
-unknown
I find there is a disturbingly small amount of infromation on this supposedly "enhanced" socket implementation...
Heres a little bit of my code so you can see what i'm up to.
//Called when a SocketAsyncEventArgs raises the completed event
private void ProcessReceive(SocketAsyncEventArgs e)
{
Token Token = (Token)e.UserToken;
if(e.BytesTransferred > 0 && e.SocketError == SocketError.Success)
{
Interlocked.Add(ref TotalBytesRead, e.BytesTransferred);
Console.WriteLine(String.Format("Received from {0}", ((Token)e.UserToken).Socket.RemoteEndPoint.ToString()));
bool willRaiseEvent = ((Token)e.UserToken).Socket.ReceiveAsync(e);
if (!willRaiseEvent)
{
ProcessReceive(e);
}
}
else
{
CloseClientSocket(e);
}
}
private void ProcessSend(SocketAsyncEventArgs e)
{
if (e.SocketError == SocketError.Success)
{
// done echoing data back to the client
Token token = (Token)e.UserToken;
// read the next block of data send from the client
bool willRaiseEvent = token.Socket.ReceiveAsync(e);
if (!willRaiseEvent)
{
ProcessReceive(e);
}
}
else
{
CloseClientSocket(e);
}
}
void IOCompleted(object sender, SocketAsyncEventArgs e)
{
// determine which type of operation just completed and call the associated handler
switch (e.LastOperation)
{
case SocketAsyncOperation.Receive:
ProcessReceive(e);
break;
case SocketAsyncOperation.Send:
ProcessSend(e);
break;
default:
throw new ArgumentException("The last operation completed on the socket was not a receive or send");
}
}
Thanks!
The solution was to create a separate SocketAsyncEventArgs for both Send and Receive.
It takes a bit more memory but not much because there is no need to allocate a buffer to the Send args.
I currently have a TCP Server implemented using C# SAEA. What I would like to do is forward a message between 2 TCP Clients connected to the server (Client 1 and Client 2).
The Server uses receiveSendEventArgs.AcceptSocket.ReceiveAsync and
receiveSendEventArgs.AcceptSocket.SendAsync commands to send and
receive information from each of the connected clients with no
problem.
The Server is in receiveSendEventArgs.AcceptSocket.ReceiveAsync operation for both Client 1 and Client 2.
Client 1 sends one Message and the the Server Accepts the message. The Server sees that Client 2 is also connected, and so needs to get the receiveSendEventArgs reference to Client 2 to forward the message.
However, the Server takes the reference of receiveSendEventArgs of Client 2 and begins to prepare the buffer (SetBuffer) to send the message and I believe since the Socket is still in a "ReceiveSync" state for Client 2, it blows up with the following message:
"An asynchronous socket operation is already in progress using this SocketAsyncEventArgs instance."
Is there a way to switch Client 2 state on the Server from "ReceiveAsync"to "SendAsync" so that it doesn't error out when I try to SendData to Client 2? I know the Completed event is triggered when either Sending or Receiving operations complete, however, Simply Calling my IO_Completed method directly does not change the operation.
In a for loop setting up EventHandlers for Completed events for SocketAsyncEventArgs:
eventArgObjectForPool.Completed += new EventHandler(IO_Completed);
void IO_Completed(object sender, SocketAsyncEventArgs e){
DataHoldingUserToken receiveSendToken = (DataHoldingUserToken)e.UserToken;
//More business logic here ...
// determine which type of operation just completed and call the associated handler
switch (e.LastOperation)
{
case SocketAsyncOperation.Receive:
if (Program.watchProgramFlow == true) //for testing
{
Program.testWriter.WriteLine("IO_Completed method in Receive, receiveSendToken id " + receiveSendToken.TokenId);
}
ProcessReceive(e);
break;
case SocketAsyncOperation.Send:
if (Program.watchProgramFlow == true) //for testing
{
Program.testWriter.WriteLine("IO_Completed method in Send, id " + receiveSendToken.TokenId);
}
ProcessSend(e);
break;
default:
//This exception will occur if you code the Completed event of some
//operation to come to this method, by mistake.
throw new ArgumentException("The last operation completed on the socket was not a receive or send");
}
}
private void StartReceive(SocketAsyncEventArgs receiveSendEventArgs)
{
DataHoldingUserToken receiveSendToken = (DataHoldingUserToken)receiveSendEventArgs.UserToken;
if (Program.watchProgramFlow == true) //for testing
{
Program.testWriter.WriteLine("StartReceive(), receiveSendToken id " + receiveSendToken.TokenId);
}
switch (receiveSendToken.clientInfo.currentState)
{
case MyClient.ClientState.Connecting://This occurs when we get client to connect for first time. However, it will automatically disconnect
receiveSendToken.theMediator.HandleData(receiveSendToken.theDataHolder);
// Create a new DataHolder for next message.
receiveSendToken.CreateNewDataHolder();
//Reset the variables in the UserToken, to be ready for the
//next message that will be received on the socket in this
//SAEA object.
receiveSendToken.Reset(true);
receiveSendToken.theMediator.PrepareOutgoingData();
StartSend(receiveSendToken.theMediator.GiveBack());
//******************************************************************
break;
default:
//Set the buffer for the receive operation.
receiveSendEventArgs.SetBuffer(receiveSendToken.bufferOffsetReceive, this.socketListenerSettings.BufferSize);
// Post async receive operation on the socket.
bool willRaiseEvent = receiveSendEventArgs.AcceptSocket.ReceiveAsync(receiveSendEventArgs);
//Socket.ReceiveAsync returns true if the I/O operation is pending. The
//SocketAsyncEventArgs.Completed event on the e parameter will be raised
//upon completion of the operation. So, true will cause the IO_Completed
//method to be called when the receive operation completes.
//That's because of the event handler we created when building
//the pool of SocketAsyncEventArgs objects that perform receive/send.
//It was the line that said
//eventArgObjectForPool.Completed += new EventHandler<SocketAsyncEventArgs>(IO_Completed);
//Socket.ReceiveAsync returns false if I/O operation completed synchronously.
//In that case, the SocketAsyncEventArgs.Completed event on the e parameter
if (!willRaiseEvent)
{
if (Program.watchProgramFlow == true) //for testing
{
Program.testWriter.WriteLine("StartReceive in if (!willRaiseEvent), receiveSendToken id " + receiveSendToken.TokenId);
}
ProcessReceive(receiveSendEventArgs);
}
break;
}
}
private void StartSend(SocketAsyncEventArgs receiveSendEventArgs)
{
DataHoldingUserToken receiveSendToken = (DataHoldingUserToken)receiveSendEventArgs.UserToken;
if (Program.watchProgramFlow == true) //for testing
{
Program.testWriter.WriteLine("StartSend, id " + receiveSendToken.TokenId);
}
if (Program.watchThreads == true) //for testing
{
DealWithThreadsForTesting("StartSend()", receiveSendToken);
}
if (receiveSendToken.sendBytesRemainingCount <= this.socketListenerSettings.BufferSize)
{
Program.testWriter.WriteLine("blocking:?(" + receiveSendEventArgs.AcceptSocket.Blocking + ")");
receiveSendEventArgs.SetBuffer(receiveSendToken.bufferOffsetSend, receiveSendToken.sendBytesRemainingCount);
//Copy the bytes to the buffer associated with this SAEA object.
Buffer.BlockCopy(receiveSendToken.dataToSend, receiveSendToken.bytesSentAlreadyCount, receiveSendEventArgs.Buffer, receiveSendToken.bufferOffsetSend, receiveSendToken.sendBytesRemainingCount);
}
else
{
//We cannot try to set the buffer any larger than its size.
//So since receiveSendToken.sendBytesRemainingCount > BufferSize, we just
//set it to the maximum size, to send the most data possible.
receiveSendEventArgs.SetBuffer(receiveSendToken.bufferOffsetSend, this.socketListenerSettings.BufferSize);
//Copy the bytes to the buffer associated with this SAEA object.
Buffer.BlockCopy(receiveSendToken.dataToSend, receiveSendToken.bytesSentAlreadyCount, receiveSendEventArgs.Buffer, receiveSendToken.bufferOffsetSend, this.socketListenerSettings.BufferSize);
//We'll change the value of sendUserToken.sendBytesRemainingCount
//in the ProcessSend method.
}
//post asynchronous send operation
bool willRaiseEvent = receiveSendEventArgs.AcceptSocket.SendAsync(receiveSendEventArgs);
if (!willRaiseEvent)
{
if (Program.watchProgramFlow == true) //for testing
{
Program.testWriter.WriteLine("StartSend in if (!willRaiseEvent), receiveSendToken id " + receiveSendToken.TokenId);
}
ProcessSend(receiveSendEventArgs);
}
}
This wasn't what I was wanting to do, but I was able to call the following:
receiveSendEventArgs.AcceptSocket.Write(strMyBuffer);
This allowed for me to write to the same socket and I did not have any errors. I was wanting to stick with The Async Commands but succumbed to a Sync write and it did not effect my server. Perhaps there are other solutions.
hello all i have this issue , and i am stuck with it so any help will be greatly appreciated
i have to build a socket chat (client Server) module and i have done almost 80% of the work but now i am stuck , Scenario is that i have a server app and clients connect to it now if say 4 clients are connected to server each of them can communicate to each other , one client will send message and server will receive that message and will pass it along ,this is working very fine but when 2 or more clients send a message to 3rd client at the same time than i can not get one message and client get disconnected i know i have to build up a queue structure but i am not getting succeeded in it here
here is my code structure
StartReceive(SocketAsyncEventArgs) ->
First of all i call this method to start listening for incoming messages
and when i got one message i check if it is completed Sync or Async
and after this there is an io completed listener which is called every time one receive opertaion is completed and in that io completed method i do call processReceive method which is used to process received chunks
so finally my code structure is like this
StartReceive-> IO Completed -> ProcessReceive
i have designed the structure so that every client will have a Receive SOCKETASYNCEVENTAGRS
object and a Send SOCKETASYNCEVENTAGRS at server side and i do maintain a pool for this
so each client receives and sends data through its own SOCKETASYNCEVENTAGRS object
i want a scenario such that if two or more clients send messages to 3rd client than 3rd client should not receive all messages at the same time instead it should have a queue structure and it should receive one message at a time and same for send operation
here is some of my code
private void StartReceive(SocketAsyncEventArgs receiveSendEventArgs)
{
DataHoldingUserToken receiveSendToken = (DataHoldingUserToken)receiveSendEventArgs.UserToken;
receiveSendEventArgs.SetBuffer(receiveSendToken.bufferOffsetReceive, this.socketListenerSettings.BufferSize);
bool willRaiseEvent = receiveSendEventArgs.AcceptSocket.ReceiveAsync(receiveSendEventArgs);
if (!willRaiseEvent)
{
ProcessReceive(receiveSendEventArgs);
}
}
This is IO Completed
void IO_Completed(object sender, SocketAsyncEventArgs e)
{
DataHoldingUserToken receiveSendToken = (DataHoldingUserToken)e.UserToken;
switch (e.LastOperation)
{
case SocketAsyncOperation.Receive:
ProcessReceive(e);
break;
default:
}
}
and this is my StartReceive with Queue implemented but it is not working
Queue rec = new Queue();
bool IsExecuted = true;
private void StartReceive(SocketAsyncEventArgs receiveSendEventArgs)
{
if (IsExecuted)
{
DataHoldingUserToken receiveSendToken = (DataHoldingUserToken)receiveSendEventArgs.UserToken;
rec.Enqueue(receiveSendToken);
}
try
{
receiveSendEventArgs.SetBuffer(receiveSendToken.bufferOffsetReceive, this.socketListenerSettings.BufferSize);
bool willRaiseEvent = receiveSendEventArgs.AcceptSocket.ReceiveAsync(receiveSendEventArgs);
if (!willRaiseEvent)
{
ProcessReceive(receiveSendEventArgs);
}
rec.Dequeue();
IsExecuted = true;
}
catch
{
IsExecuted = false;
StartReceive(receiveSendEventArgs);
}
}
looking for a decent help or some good direction
I'm not sure if this is the root cause of your problem but it seems to me that you are running out of DataHoldingUserToken at some time because you are never doing anything with the objects you dequeue, hence you are throwing it away.
Also note that it is recommended to use the generic form of the Queue class for non-trivial object. That would be System.Collections.Generic.Queue<DataHoldingUserToken>.
I had recently asked a related question In C# how do I have a socket continue to stay open and accept new data? and somewhat solved it, but now I'm having trouble getting my server to receive data from the same client more than once.
I have written a simple socket server using a windows form in VS that has a button that calls a receive function
public void Receive()
{
try
{
byte[] bytes = new byte[256];
received = s1.Accept().Receive(bytes);
receivedText.Text += System.Text.ASCIIEncoding.ASCII.GetString(bytes);
}
catch (SocketException e)
{
Console.WriteLine("{0} Error code: {1}.", e.Message, e.ErrorCode);
return;
}
}
It works if the first time I send from my client, but if I try sending anything else and click on receive, my server just loops and never picks up the new data. However, if I send from somewhere else, or restart the connection from my client, I'm able to send data.
I would like to have my server able to receive any amount of data from the same client(s) at a time. Please ask if you need more code/details. Not sure what's relevant as I'm pretty new to socket programming.
You must call Accept() only once per client, not every time you want to receive new data. Accept() basically waits for a client to connect to your server socket, s1 (and returns a new socket to send/receive data with this client), so here each time your Receive() function is called your socket waits for another client to connect, that's why it works only once.
Here is an example (the code comes from your previous question) :
s1.Bind(endP);
s1.Listen(10);
Socket s2 = s1.Accept(); // Waits for a client to connect and return a socket, s2, to communicate with him
while (true) {
Receive(s2);
}
...
Receive() function :
public void Receive(Socket s)
{
try
{
byte[] bytes = new byte[256];
received = s.Receive(bytes);
receivedText.Text += System.Text.ASCIIEncoding.ASCII.GetString(bytes);
}
catch (SocketException e)
{
Console.WriteLine("{0} Error code: {1}.", e.Message, e.ErrorCode);
return;
}
}