Why disconnect a TCP socket in order to connect? - c#

I'm working on a piece of code, where a connection is made to a TCP socket.
The code contains the following excerpt:
// Close the socket if it is still open
if (_socket != null)
{
Disconnect();
}
// Create the socket object
_socket = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
The DisConnect() method does (amongst other things):
var socket = _socket;
_socket = null;
socket.Close();
I don't understand the beginning: why disconnect in order to connect?
I have tried removing that part of the code, but then the whole thing became very unstable.
Does anybody have an idea?
Thanks

Once a TCP socket has been closed, it can't be reused, so a new socket is needed for a new TCP connection.
If you want to reuse the same socket for a new TCP connection after a disconnect, you need to use the Socket.Disconnect() method with the reuseSocket parameter set to true.

Related

Socket not connected exception after calling EndAccept and accessing RemoteEndPoint

When accessing the RemoteEndPoint property of an accepted socket on the server, a SocketException: 'The socket is not connected' is sometimes thrown.
This happens occasionally (like once in 100 connection attempts) and only when there is a significant latency over the network (e.g. 10ms+, wifi network). Seems to be some kind of race condition but I'm not sure what can be done to prevent this.
Server code:
this.Socket = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
this.Socket.Bind(new IPEndPoint(IPAddress.Parse("0.0.0.0"), port));
this.Socket.Listen(0);
this.Socket.BeginAccept(OnSocketAccepted, null);
private void OnSocketAccepted(IAsyncResult ar)
{
var socket = Socket.EndAccept(ar);
var endPoint = socket.RemoteEndPoint; // SocketException: The socket is not connected
}
Client code:
var socket = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
socket.Connect(ip, port);
// times out after a couple of seconds if the exception happened on the server
Server is running on Mono 6.4.0.198 on ARMv7 rev4 Raspberry Pi 3b+
Client is running on Windows 10 .NET framework 4.6.1 console app
I thought EndAccept basically guaranteed that the socket would be in a connected state and the RemoteEndPoint would be set. I've gone through the whole msdn EndAccept and RemoteEndPoint documentation and can't find any obvious mistakes or misunderstandings.
The Socket can close after you have called EndAccept() and before you have queried RemoteEndPoint. It can also close before your callback calls EndAccept(), this will also throw a Socket Exception.
There a a number of race conditions that can happen in here, particularly if your system is slow. You can check Socket.Connected but even that isn't guaranteed.
The correct approach is a Try/Catch and gracefully exit or throw an unrecoverable socket.
e.g.,
catch (SocketException ex)
#region SocketException
{
/// Some SocketExceptions we manage quietly. Others we surface as critical errors.
if ((SocketError)ex.ErrorCode == SocketError.AddressAlreadyInUse)
{
Log.Error("Endpoint failed to start. IPEndPoint {ipEndPoint} already in use.", this.localIPEndPoint.ToString());
// Execution will continue after finally{}
}
else
{
Log.Error(ex, "Endpoint has ended with an unrecoverable socket error:", Name);
throw;
}
}

c# fixed tcp client local endpoint port causes SocketException

Can i unbind socket from local endpoint? For security purposes, i need to fix source port for TCP communication. In this client code i fix source port to 42448:
Socket s = new Socket(AddressFamily.InterNetwork, SocketType.Stream,
ProtocolType.Tcp);
IPEndPoint localEP = new IPEndPoint(IPAddress.Parse("192.168.1.123"), 42448);
s.Bind(localEP);
s.Connect(remoteEP);
s.Send(new byte[] { 0x01, 0x02, 0x03 });
s.Close();
It works only once. Second time it throws SocketException (that address already in use) on the s.Connect line as i see in netstat, there is one connection from this source port 42448 with TIME_WAIT state, even if i close the app. after about 1 minute this TIME_WAIT connection disappears and i can run my code, but again just once. how can i properly unbind this socket so i can run code many times?
Update 1
it is not a server socket, so there is no listening here. LingerOption is also doesnt work:
LingerOption lo = new LingerOption(false, 0);
s.SetSocketOption(SocketOptionLevel.Socket, SocketOptionName.Linger, lo);

Tcp Hole Punching in c# using ReuseAddress

I am trying to accomplish Tcp hole punching with socket option as reuse address.
First step- Run and tcp listener in server S with active open tcp port 8001.
Second step- Run a Tcp socket with reuse address(method name is enableReuseAddres(Socket sck) mentioned below) in socket option on client A which is behind the NAT on port 8001.
Third step- Connect A => S.
Fourth step- Send data from A => S and get confirm data from S => A.
Fifth step- Get remote endpoint of A which is X.X.X.X:8001(External IP and Port of A).
Sixth Step- Listen on a socket with port 8001(method name is runServer mentioned below),in client A with reuse address(method name is enableReuseAddres(Socket sck) mentioned below) in socket option.
Disclaimer:- No error found and able to bind the same endpoint which is used to connect to the server S with the help of ReuseAddress and able to listen on the same port 8001.
But when I try to check the port 8001 is opened or closed I always get port is closed,of client A.
public void runServer()
{
Socket sk = new Socket(AddressFamily.InterNetwork,
SocketType.Stream, ProtocolType.Tcp);
enableReuseAddres(sk);
sk.Bind(loclEP);
sk.Listen(1);
var connection_socket = sk.Accept();
MessageBox.Show("Connected");
}
IPEndPoint loclEP = new IPEndPoint(IPAddress.Any, 8001);
public void enableReuseAddres(Socket sck)
{
sck.SetSocketOption(SocketOptionLevel.Socket,
SocketOptionName.ReuseAddress, true);
sck.SetSocketOption(SocketOptionLevel.Socket,
SocketOptionName.KeepAlive, true);
}

Close a socket and then reopen it from the same port in .net

Well, I wonder if some one can help with a problem that I encounter....
I want to close a socket and then rerun from the same port. This is what i am doing...
opening:
UdpServer = new Socket(AddressFamily.InterNetwork, SocketType.Dgram, ProtocolType.Udp);
UdpServerIpEndPoint = new IPEndPoint(IPAddress.Any, 9050);
UdpEndPoint = (EndPoint)UdpServerIpEndPoint;
UdpServer.Bind(UdpServerIpEndPoint);
closeing:
UdpServer.Shutdown(SocketShutdown.Both);
UdpServer.Disconnect(true);
UdpServer.Close();
After I close it. and the I try to reconnect it with the same code as above, I get error:
Additional information: Only one usage of each socket address
(protocol/network address/port) is normally permitted
I checked for exception during closing, but I didnt get any, i guessed they were closed properly, so actually, what is causing this problem? Please help!
I got answer....
I need to use this after decleration of socket...
socket.SetSocketOption(SocketOptionLevel.Socket,SocketOptionName.ReuseAddress, true);
You could look at this 2 ways.
Don't actually Receive whilst your are in your stopped state, just in your BeginReceive, just drop/ignore the data
If you really need to recreate the socket, then don't perform the disconnect on your Server because you haven't actually got a connection. Your disconnect is throwing
System.Net.Sockets.SocketException (0x80004005): A request to send or receive data was disallowed because the socket is not connected and (when sending on a datagram socket using a sendto call) no address was supplied
For reference, in case anyone else stumbles onto this question but looking for the UdpClient implementation.
int port = 1234;
var socket = new Socket(AddressFamily.InterNetwork, SocketType.Dgram, ProtocolType.Udp);
var endPoint = new IPEndPoint(IPAddress.Any, port);
socket.Bind(endPoint);
var updClient = new UdpClient();
updClient.Client = socket;
updClient.Connect(_ipAddress, port);

TCPIP server single connection

i am using c# sockets Asynchronous mode.
i need to serve only one connection in my application from a server point of view. once one is connected then i would like to refuse any more connection requests.
also the server only serves to connect to a single client. when the communication is done the server has to be restarted.
but from what i have read on the topic, it is not possible to close beginaccept.
i would like some ideas regarding how get around this situation.
Normally, in the BeginAccept async callback you would call BeginAccept again so that another connection can be accepted. However, you can omit this step if you do not want to allow another connection. So that the connection is refused in a timely manner, consider also closing the listening socket in the callback. The accepted Socket will remain open in this case for you to use even though the listening socket is closed.
class SocketTest
{
private Socket m_Listener = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
public void Test()
{
m_Listener.Bind(new IPEndPoint(IPAddress.Loopback, 8888));
m_Listener.Listen(16);
m_Listener.BeginAccept(AcceptCallback, null);
}
private void AcceptCallback(IAsyncResult ar)
{
Socket s = m_Listener.EndAccept(ar);
m_Listener.Close();
/* Use s here. */
}
}

Categories

Resources