What is the correct way to handle a disconnection and re-connection event with the windows StreamSocket class (TCP)?
I have an issue where calling "Invalid Operation, method was called at an unexpected time" when calling async_connect after a disconnection event
do I need to create a new streamsocket, or wait for some amount of time before attempting to re-connect?
https://learn.microsoft.com/en-us/uwp/api/windows.networking.sockets.streamsocket
The solution was to add the following code:
// on catching an exception
socket.dispose();
connect();
// connect function
connect():
socket = new StreamSocket ...
It was necessary to 1) call socket.dispose() on the socket which the client disconnected from and 2) create a new socket (socket = new StreamSocket(...)). Reusing the same socket to connect did not work.
Related
I have just recently started development for a server - multiple clients application using Socket.
The server doesn't need to keep track of the connected clients; If there is a client that requests for connection, server accepts it. If there is a request from any client (to get some data), server will response to that client.
/// <summary>
/// Callback when server accepts a new incoming connection.
/// </summary>
/// <param name="result">Incoming connection result object.</param>
private void AcceptedCallback(IAsyncResult result)
{
try
{
Socket clientSocket = _socket.EndAccept(result); // Asynchronously accepts an incoming connection attempt
if (clientSocket.Connected) // Check if the client is in 'Connected' state
{
StateObject state = new StateObject();
state.clientSocket = clientSocket;
clientSocket.BeginReceive(state.buffer, 0, StateObject.BufferSize, SocketFlags.None, // Start listening to client request
ReceiveCallback, state);
}
else
{
clientSocket.Close(); // Terminate that client's connection
Log.writeLog("TCPServer(AcceptedCallback)"
, "Client's status is not connected.");
}
}
catch (Exception ex)
{
Log.writeLog("TCPServer(AcceptedCallback)"
, ex.Message);
clientSocket.Close();
}
finally
{
Accept(); // Start to accept new connection request
}
}
I have 3 questions about this:
For each BeginReceive that I create for the newly connected client, does my server application creates a new thread/object to hold that client?
If after the client is connected, and the network cable is pulled off at the client side and plug back in, the client will connect to the server again and this is considered a new connection on the server, if this scenario occurs again and again, will my server program crashes?
Hence, do I need to keep track of each client that is connected to the server, and find a way to track their state so I can call Close/Dispose on them?
So far in my testing for scenario 2, there are no abnormalities detected in my server program, but I hope someone would help clarify this for me. Thank you.
No, it will use a IO completion thread from a pool of threads.
No, you can code and should code to cater for this. If something happens on the client side that the OS can detect, it will send a TCP fin/ack to the server. This should result in any BeginXXX method still waiting to go the Async Callback Method. From there your call to EndXXX method should either throw an exception or return zero bytes being read from the socket.
This depends on what you mean by keep track of to dispose of them properly. If you mean dispose of them if you detect an error, no, you can put clean up code in your EndXXX methods. If you mean so that you can signal clients gracefully if you shut the server down, then yes.
I have a "start" and "stop" button. When clicking the start button, a new socket is created and a connection is made. When clicking the stop button the socket is shutdown, disconnected, closed and disposed to make sure it is completely gone.
At least, that's what I thought: when clicking start after stopping the connection, a new socket is made etc. but as soon as I send data, the data is sent x amount of times I had created a socket (thus, x amount of times I had clicked the start button).
This is the code for the start:
soc = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp); // Socket soc; is declared at class-level
System.Net.IPAddress ipAdd = System.Net.IPAddress.Parse(IP);
System.Net.IPEndPoint remoteEP = new IPEndPoint(ipAdd, port);
try
{
soc.Connect(remoteEP);
soc.Send(jsonSettings);
}
catch (SocketException e)
{
MessageBox.Show("Could not connect to socket");
}
And this is the stop code:
if (soc != null)
{
soc.Shutdown(SocketShutdown.Both);
soc.Disconnect(false);
soc.Close();
soc.Dispose();
}
This is used within a VSTO PowerPoint add-in application if this could cause any additional specialties, when the connection is made I'm sending string data to a Python server listening to this port. Each time a connection is closed, the Python server will get out of it's listen-for-data loop and get back in it's waiting for connection state (for the multiple start/stop connections).
Code for sending data:
// this is called each time the user goes to another slide in the PowerPoint presentation
byte[] byData = System.Text.Encoding.ASCII.GetBytes(stringValue);
soc.Send(byData);
Can anyone point out what I'm doing wrong why the socket connections somehow keep on living and sending data even though I disconnected and closed them?
The observed behavior is the whole point and desired outcome from clean shutdown. From the MSDN page for Socket.Shutdown():
When using a connection-oriented Socket, always call the Shutdown method before closing the Socket. This ensures that all data is sent and received on the connected socket before it is closed.
The call to Shutdown() prevents your application from queuing additional outgoing data, it does not stop the network stack from sending data already buffered.
Since you are using a stream socket, how about declaring a network stream for your socket like this:
NetworkStream stream = new NetworkStream(soc);
Then flushing this after each send (and before closing the socket):
stream.Flush();
Also ensure you turn off Nagle's algorithm when you create the socket - it will prevent batching up items on the socket:
soc.NoDelay = true;
I am getting Access Denied exception while trying to open a socket.
My connect function is as shown.
internal void Connect()
{
try
{
//AccessPolicy = new SocketClientAccessPolicyProtocol();
args = new SocketAsyncEventArgs();
args.UserToken = socket;
args.RemoteEndPoint = endPoint;
args.Completed += new EventHandler<SocketAsyncEventArgs>(OnConnect);
**isConnected = socket.ConnectAsync(args);**
//autoEvent.WaitOne();
if (args.SocketError != SocketError.Success)
throw new SocketException((int)args.SocketError);
if(isConnected)
global::System.Windows.MessageBox.Show("Connected");
}
catch (Exception ex)
{
global::System.Windows.MessageBox.Show(ex.Message);
}
}
The function ConnectAsync however is executing fine as isConnected is coming true but socket is not getting connected.
http://drdobbs.com/windows/208403238
Looking through the code you'll see that it uses the TcpListener class to listen for incoming client connections. Once a client connects the code checks the request for the following value: <policy-file-request/>
Silverlight automatically sends this text to the policy file socket once it connects. If the request contains the proper value the code writes the contents of the client access policy back to the client stream (see the OnReceiveComplete() method). Once the policy file is received, Silverlight parses it, checks that it allows access to the desired port, and then accepts or rejects the socket call that the application is trying to make.
If this is Silverlight in the browser, you need a socket policy server in the mix. See http://msdn.microsoft.com/en-us/library/cc645032%28v=vs.95%29.aspx for details.
I'm writing a small C# Sockets application. Actually I have two, a server and a client.
The user runs the client, enters the IP and port for the server, presses 'connect', and then once connected they can enter text into a textbox and send it to the server.
The server simply displays either "No connection" or "Connection from [ip]:[port]", and the most recent received message underneath.
The server successfully receives messages, and even handles the client disconnect fine.
Now I'm trying to make it listen again after the client has disconnected but for some reason nothing I try will allow it to start listening again.
Here is part of my code:
Socket socket;
private void listen()
{
socket = new Socket(AddressFamily.InterNetwork,
SocketType.Stream, ProtocolType.Tcp);
socket.Bind(new IPEndPoint(IPAddress.Any, 12345));
socket.Listen(10);
socket.BeginAccept(new AsyncCallback(acceptAsync), socket);
}
and
private void receiveAsync(IAsyncResult res)
{
Socket socket = (Socket)res.AsyncState;
try
{
int nBytes = socket.EndReceive(res);
if (nBytes > 0)
{
Invoke(new MethodInvoker(delegate()
{
lMessage.Text = encoder.GetString(buffer);
}));
setupReceiveAsync(socket);
}
else
{
Invoke(new MethodInvoker(delegate()
{
lConnections.Text = "No Connections.";
lMessage.Text = "No Messages.";
socket.Shutdown(SocketShutdown.Both);
socket.Close();
listen();
}));
}
}
catch { }
}
The last line: listen(); is what throws the error.
I have tried simply calling socket.BeginAccept() again, but that also throws an exception.
The message I'm getting is:
Only one usage of each socket address (protocol/network address/port) is normally permitted
If I don't call my listen() function and instead just call socket.BeginAccept(), then I get "You must first call socket.listen()"
If I call the socket.listen() function, then it tells me it's already connected and cart start listening.
Once I have made an asynchronous connection, and received several asynchronous messages, how then do I begin receiving again?
Your socket variable already has an listening socket assigned to it the second time you call listen(), which is why it tells you only one usage is permitted. All you need to repeat is the socket.BeginAccept(new AsyncCallback(acceptAsync), socket) call. So try replacing the call to listen() inside your receiveAsync(...) method with socket.BeginAccept(new AsyncCallback(acceptAsync), socket).
In async Begin* is always followed by End*. See Using an Asynchronous Server Socket. Your accept method should be something like:
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) {
Server, means that an app that listens on specified port/ip. Is usually, always in a listening mode - that's why it is called a server. It can connect and disconnect a client, but is always in listening mode.
This means, when a server disconnects a client - even then - it is in listening mode; meaning it can accept the incoming connections as well.
Though, disconnection request can come from client or can be forcefully applied by server.
The process for a server is:
Bind to socket
Listen
Accept connections
The process for client is:
Connect to the server
Send/receive messages
There are several ways for server to handle the incoming clients, couple, as follows:
Incoming connections are maintained in a list, for instance within a List<TcpClient>.
One way of handling the incoming clients is through threads. For instance, for each incoming client, spawn a thread that would handle the communication between server and client. For instance, checkout this example.
_
private void ListenForClients()
{
this.tcpListener.Start();
while (true)
{
//blocks until a client has connected to the server
TcpClient client = this.tcpListener.AcceptTcpClient();
//create a thread to handle communication
//with connected client
Thread clientThread = new Thread(new ParameterizedThreadStart(HandleClientComm));
clientThread.Start(client);
}
}
Use single thread and use context switching to manage client communications (TX/RX).
I have multiple devices connected to a TCP/Ip port and i want to read all these devices through sockets in .Net how can i do this before this i had a single device connected and it was working fine but now i have multiple devices can anybody help me in listening multiple socket connection?
This is not a complete answer, but should point you in the right direction. You can use something like
Socket socketForClient = tcpListener.Accept();
call for every connecting client. You can have an array of Socket objects you can process/update as new connections come in or get closed.
You will want to create an asynchronous Tcp listener. Read up here: MSDN Socket Class
First you set up your listener:
private static System.Threading.ManualResetEvent connectDone =
new System.Threading.ManualResetEvent(false);
void StartListen(IPEndPoint serverEP, int numDevices)
{
sock.Bind(serverEP);
sock.Listen(numDevices); // basically sit here and wait for client to request connect
/*
* While statement not required here because AcceptConnection()
* method instructs the socket to BeginAccept()...
*/
connectDone.Reset();
sock.BeginAccept(new AsyncCallback(AcceptConnection), sock);
connectDone.WaitOne();
}
In some examples, you might see the the BeginAccept(...) method inside of a while(true) block. But you don't need that with async. I think using the while(true) is improper. Of course, you then accept connections aynchronously:
void AcceptConnection(IAsyncResult asyncRes)
{
connectDone.Set();
System.Net.Sockets.Socket s = channelworker.EndAccept(asyncRes);
byte[] messagebuffer = new byte[bufferSize];
/*
* Tell socket to begin Receiving from caller.
*/
s.BeginReceive(messageBuffer, 0, messageBuffer.Length,
System.Net.Sockets.SocketFlags.None, new AsyncCallback(Receive), s);
/*
* Tell Channel to go back to Accepting callers.
*/
connectDone.Reset();
sock.BeginAccept(new AsyncCallback(AcceptConnection), sock);
connectDone.WaitOne();
}
Usually, once you work through a couple of the asynchronous exercises and get the hang of .Beginxxx/.Endxxx
methods, and using the AsyncCallback, you will get the hang of how it works. Read through the MSDN reference I gave you and this should get you a pretty good start.
Ususally for multi connection application the server listens to a specific port, and after recieving a connection it return a new port where your device will create a new socket.