How to make/simulate persistent TCP connection? - c#

It looks like WCF TCP connections are not persistent. First ping reply takes a while but subsequent processes take less time. After a while it takes long again -another re-connection?
SERVER> Started on net.tcp://0.0.0.0:999
CLIENT> Connection created to net.tcp://localhost:999 //Not a real connection, ready to connect
CLIENT> Ping reply in 1s163ms //First connection
CLIENT> Ping reply in 22ms //Already connected
CLIENT> Ping reply in 26ms
CLIENT> Ping reply in 24ms
CLIENT> Ping reply in 325ms //Re-connected
CLIENT> Ping reply in 19ms
CLIENT> Ping reply in 767ms //Re-connected
If it's true, what is the idle time value for a tcp connection before it will be disconnected? I need to keep the connection alive.
Update Modified code:
NetTcpBinding tcpBind = new NetTcpBinding();
tcpBind.ReliableSession.Enabled = true;
tcpBind.ReliableSession.Ordered = true;
tcpBind.ReliableSession.InactivityTimeout = TimeSpan.FromMinutes(10);
ServiceHost svh = new ServiceHost(typeof(ServiceImplementation));
svh.AddServiceEndpoint(
typeof(WCFSimple.Contract.IService),
//new NetTcpBinding(),
tcpBind,
String.Format("net.tcp://{0}:{1}", ip, port));
svh.Open();
Now I got another error:
The action http://tempuri.org/IService/Pong is not supported by this endpoint. Only WS-ReliableMessaging February 2005 messages are processed by this endpoint.
Update I modified only server side and it caused the error. Then I modified client side's TCP as reliable messaging.

I don't think Ping is a good tool to test a TCP connection. Because Ping uses ICMP as its underlying protocol instead of TCP.
I suggest you create a WCF client, connect to the service and then check the TCP connection via some network sniffering tools or simply use netstat for quick check.

Normally, WCF connections are transient, though there is some connection pooling that goes on in the background.
Using net.tcp as the transport, persistent (long term) connections are possible. The code you've posted is one way to achieve that.
For more information, and some alternatives, check out What You Need To Know About One-Way Calls, Callbacks, And Events, an MSDN magazine article from October 2006.
Also of use are the IsInitiating and IsTerminating properties available on the OperationContract attribute.

Related

Console app SignalR client Disconnect Timeout

I am trying to set Disconnect Timeout to higher value from the default 30s.
All examples on web are more JS oriented.
var hubConnection = new HubConnection("http://localhost:8087");
var testHubProxy = hubConnection.CreateHubProxy("TestHub");
Error: System.TimeoutException: Couldn't reconnect within the configured timeout of 00:00:30, disconnecting.
This did not work:
GlobalHost.Configuration.DisconnectTimeout = TimeSpan.FromSeconds(35);
Update:
It looks like DisconnectTimeout needs to be set on the server side!?
What is the reason for disallowing different clients to have different Disconnect Timeout?
Disconnect Timeout is configured on server-side. The main reasons could be as follows:
We know the server may take some N-time units to respond so that the all clients may be well aware.
The server should be pinging the clients for connection at regular times. So the server is aware of clients connection and can manage other hubs and eradicate the expired connections from its connection pool.
The client is not supposed to set disconnect timeout because it does not know when could it shutdown e.g. the internet switched off accidentally on client side than the client is not able to tell server that I am not going to connect to you again. Yes but we have some events at client-side which tells it that it is not connected to the signalr hub anymore. Please see the reconnecting and disconnected events.
Summary:
Disconnect timeout is to inform the server that its client is not connected anymore even if it disconnects disgracefully .

TcpClient SocketException with timeout after 20s no matter what

I'd like to wait for a slow response from a client with TcpClient but get a timeout after about 20s no matter how I configure it. This is my attempt:
using (var client = new TcpClient { ReceiveTimeout = 9999999, SendTimeout = 9999999 })
{
await client.ConnectAsync(ip, port);
using (var stream = client.GetStream())
{
// Some quick read/writes happen here via the stream with stream.Write() and stream.Read(), successfully.
// Now the remote host is calculating something long and will reply if finished. This throws the below exception however instead of waiting for >20s.
var bytesRead = await stream.ReadAsync(new byte[8], 0, 8);
}
}
The exception is an IOException:
Unable to read data from the transport connection: A connection
attempt failed because the connected party did not properly respond
after a period of time, or established connection failed because
connected host has failed to respond.
...which contains a SocketException inside:
A connection attempt failed because the connected party did not
properly respond after a period of time, or established connection
failed because connected host has failed to respond
SocketErrorCode is TimedOut.
The 20s seems to be an OS default on Windows but isn't it possible to override it from managed code by interacting with TcpClient? Or how can I wait for the response otherwise?
I've also tried the old-style BeginRead-EndRead way and the same happens on EndRead. The problem is also not caused by Windows Firewall or Defender.
I'd like to wait for a slow response from a client
It's important to note that it's the connection that is failing. The connection timeout is only for establishing a connection, which should always be very fast. In fact, the OS will accept connections on behalf of an application, so you're literally just talking about a packet round-trip. 21 seconds should be plenty.
Once the connection is established, then you can just remove the ReceiveTimeout/SendTimeout and use asynchronous reads to wait forever.
It turns out that the remote host wasn't responding in a timely manner, hence the problem. Let me elaborate, and though this will be a solution very specific to my case maybe it will be useful for others too.
The real issue wasn't a timeout per se, as the exception indicated, but rather what exceptions thrown on subsequent Read() calls have shown: "An existing connection was forcibly closed by the remote host"
The remote host wasn't purposely closing the connection. Rather what happened is that when it was slow to respond it was actually so busy that it wasn't processing any TCP traffic either. While the local host wasn't explicitly sending anything while waiting for a response this still was an issue: the local host tried to send ACKs for previous transmissions of the remote host. Since these couldn't be delivered the local host determined that the remote host "forcibly closed" the connection.
I got the clue from looking at the traffic with Wireshark (always good to try to look at what's beneath the surface instead of guessing around): it was apparent that while the remote host was busy it showed complete radio silence. At the same time Wireshark showed retransmission attempts carried out by the local host, indicating that this is behind the issue.
Thus the solution couldn't be implemented on the local host either, the behavior of the remote host needed to be changed.

TcpListener and TcpClient sharing local port

I have 2 instances of the same application, on different machines, that should talk with each other, where no one is a typical server or client.
Both instances of the application has a TcpListener, local port = 8000.
One application instance (call it "A") creates a TcpClient. Now, this client can't have local port = 8000, or the constructor throws the socket exception "Only one usage of each socket address (protocol/network address/port) is normally permitted".
So, I create this first client with a random local port, and run Connect() to connect with the other application instance "B".
"B" accepts the connection using TcpListener.AcceptTcpClient(), which returns a TcpClient that can be used to communicate with "A". Though, this TcpClient has the same IP and Port as the TcpListener!? How is this possible, when I could not use the same port when I created the TcpClient manually on "A"? I actually really would like them to use the same port as the listener, on both machines...
So, how can I create the TcpClient on "A" with same port as the TcpListener?
I think you might not fully understand the address port client server architecture.
TcpListener is listening to any connection on address and port. After connection established you can use the "Socket" to receive and send messages from the client and server both.
example:
0.0.0.1 is machine A.
0.0.0.2 is machine B.
you can put a TcpListener that is listening on port 8000 on machine A. When the TcpClient on machine B will make try to connect machine A on port 8000 the TcpClient on machine B will get a generated (by the OS) port.
and then you will have a connection
0.0.0.1:8000 -> 0.0.0.2:3587(Generated port) - so you dont need to worry for the client listening port.
A TCP Connection has always a server and a client side. The server is listening (waiting) for a connection and the client connects to the server.
When the server gets the connection request, AcceptTcpClient gives you the socket of the server side to communicate with the client. A TCP Connection is always defined with the IP Addresses and Ports of the two sides: serverip:serverport and clientip:clientport.
If you want a really symmetrically System, both instances would have a server and a client that connects to the other server. All data that would then always be sent from client to server over the connection that was established by the client.
For Example:
ClientA connects to ServerB -> ConnectionAB
ClientB connects to ServerA -> ConnectionBA
ApplicationA sends data to ApplicationB over ConnectionAB
ApplicationB sends data to ApplicationA over ConnectionBA
If your goal is to use 2 TCP endpoints to talk to each other, without one of them being an
explicit server always, you probably should run a listener (on port 8000, in your case)
on both machines. Next, let each machine try randomly for the connection -- let each
machine pick a random time (between 0 and T) and then wake up. Whichever machine
wakes up first, will call connect() and establish the connection.
As #nivpenso pointed, the end point doing the connect need not explicitly bind to
a port. The connect() step explicitly assigns a temporary random port to that
end point.
So, if hostA initiates the connection, here are all the endpoints you would see
(you can use netstat to see these connections)
HostA:
-- listener: 8000
-- connection to hostB:port8000, localport:xyz
HostB:
-- listener: 8000
-- connection to hostA:port:xyz, localport:8000
On the other hand, if hostB initiates the connection, here are all the endpoints you
would see:
HostA:
-- listener: 8000
-- connection to hostB:port:xyz', localport:8000
HostB:
-- listener: 8000
-- connection to hostA:port8000, localport:xyz'
In the Internet, BGP uses a similar method to connection 2 TCP peers.

Uniting TCP and UDP in C#

So ideally, I am looking for a way to unite TCP and UDP on the server and manage both these connections under individual client threads. Currently, I am wondering if it is possible to accept a TCP connection and set up UDP communication from that.
Here is my ideal setup:
Client connects on TCP to server via TCPClient.connect()
Server accepts TCP connection via TCPListener
when server accepts TCP connection, it also gets the IPEndpoint from the TCP connection
and uses that to begin UDP communcation with:
serverUDPSocket.BeginReceiveFrom (byteData, 0, 1024,
SocketFlags.None, ref (Endpoint)ThatIPEndpointThatIJustMentioned,
new AsyncCallback(client.receiveUDP),
(Endpoint)ThatIPEndpointThatIJustMentioned);
^so this is where I am running into a little bit of a theoretical issue. From my understanding, the endpoints for TCP and UDP would be formatted differently. How can I resolve this issue? I would like to avoid having the client connect to UDP on a separate thread and then uniting these threads under a single managing class.
EDIT:
Here is the code that I am trying to implement:
//Listening for TCP
TcpClient newclient = listenTCP.AcceptTcpClient(); //Accept the client
Client clientr = new Client(newclient); //Create a new Client class to manage the connection
clientr.actionThread = new Thread(clientr.action); //This thread manages the data flow from the client via the TCP stream
clientr.actionThread.Start(clientr);
EndPoint endPoint = newclient.Client.RemoteEndPoint; //so this is the sketchy part. I am trying to get the endpoint from the TCP connection to set up a UDP "connection". I am unsure about the compatibility as UDP and TCP sockets are different.
UDPSocket.BeginReceiveFrom(new byte[1024],0,1024, SocketFlags.None,ref endPoint, new AsyncCallback(clientr.receiveUDP), null); //the AsyncCallBack is like the manager thread for UDP (same as in TCP)
clients.Add(clientr);
There is no problem in creating two listeners in one application, even if they use different protocol. I suppose you are not asking if you can do it on the same port (there is no point to do it anyway).
However listener is consuming thread so it need different thread if there is gui or some process to do in application (for example calculations meanwhile).
If you want to do everything in one thread you must first receive message from first listener, then setup second one. There is no possibility to setup 2 listeners in one thread at the same time because if you setup first listener it will consome whole thread waiting for message.
This was due to a lack of understanding of UDP on my part from the code level.
I ended up setting up the other method I described where it would accept initial UDP packets individually and then direct the communication (EndPoint + Message) towards a managing client class by comparing IP addresses.

Spoof IP address for HTTP web request?

I have a web service on a server in my company that we have restricted access to from all but one other server on our network.
I do however need to make calls to this from another machine. Is there a way I can spoof the other servers IP address in order to send an http request to the web service? I only need to send it info I don't need any returned data. It's for logging hits from another server on our main server.
I am using this
IPEndPoint endpointAddress = new IPEndPoint(IPAddress.Parse(ipAddress), 80);
using (Socket socket = new Socket(endpointAddress.AddressFamily, SocketType.Stream, ProtocolType.Tcp))
{
socket.SendTimeout = 500;
socket.Connect(endpointAddress);
socket.Send(byteGetString, byteGetString.Length, 0);
}
but get an exception
A connection attempt failed because
the connected party did not properly
respond after a period of time, or
established connection failed because
connected host has failed to respond
23.202.147.163:80
In general, it is not possible to establish a TCP connection with a server without being able to receive and process some reply packets from that server. HTTP is built upon TCP, and TCP starts communications with a "3-way handshake" that lets the client and server communicate.
The start of an HTTP request is not a single packet.
You could use a proxy to bounce your requests from an IP address that has access.

Categories