Too slow socket response (21 seconds) using TCP protocol - c#

I am trying to create socket and connect to a device. The problem occurs when the device is not in the network and I try to connect. I get false as response (which is ok and on which base I update status of my device), but the problem is that I get the response in 21 seconds. I am using this function to connect:
public bool Connect(IPEndPoint ipEndPoint, IPAddress ipAddress, Guid id, bool isAlive)
{
try
{
clSocket = new Socket(ipAddress.AddressFamily, SocketType.Stream, ProtocolType.Tcp);
clSocket.NoDelay = false;
clSocket.ReceiveTimeout = 1000;
clSocket.SendTimeout = 1000;
clSocket.Connect(ipEndPoint);
return true;
}
catch (Exception ex)
{
return false;
}
}
As much as I read about "21 seconds timeout" I found out that I have to change the register:
HKEY_LOCAL_MACHINE\System\CurrentControlSet\Services\Tcpip\Parameters
Value Name: TcpMaxDataRetransmissions
Data Type: REG_DWORD - Number
Valid Range: 0 - 0xFFFFFFFF
Default: 3
I am reffering to this articles:
http://getin2me.blogspot.com/2010/08/are-you-also-facing-windows-sockets-21.html and this post:
https://social.msdn.microsoft.com/Forums/en-US/fd586377-34b3-4cb8-a3af-0a24c608e399/connectex-winsock-question?forum=vcgeneral
Why in Windows 8 I can not find this register? Is there any other solution so I can get quick (by quick I mean normal <1ms to <20ms i.e.) response true(connected) or false(not connected)?

by quick I mean normal <1ms to <20ms i.e.)
If the device is not there you can not get a response about the failed connection that fast. A TCP connections gets established by the 3-way-handshake. In this handshake the client first sends a SYN packet to the server and waits for the SYN+ACK back.
If the server is there but the port is closed it will send a RST back (instead of SYN+ACK) and the client knows that that the server is unreachable. This can be done in RTT time, which is a few ms in a local network but can be easily more than 20ms if you are on the internet.
If the server is not there it can not send a response back. In this case the client will retry to send the SYN multiple times because the packet might simply be lost. How long it will wait for the response depends on the OS and tuning, but often the first retry is done after 1 second, the second after 3 seconds... until after some time the client simply gives up and assumes the server is not there. This means in this case it will take multiple seconds and there is nothing you can do about it.

You could try pinging the address first and see if you get a response, if you dont, dont attempt to try to connect to it
Ping pinger = new Ping();
try
{
PingReply reply = pinger.Send(ip);
if (reply.Status == IPStatus.Success)
{
}
else
{
}
}

Related

UDP Client - Reception of enqueued packets

I am developing a UDP Client PC application. It is supposed to receive UDP datagrams from more than 4 devices.
The system behaves in the following way:
Multiple devices are communicating with each other via UDP broadcasts on a fixed port (11000) forming a personal area network with no connectivity to the internet.
PC application is executed on a computer connected to the same network.
PC application listens to UDP broadcasts on 11000 port to discover the devices.
When a specific command is received from the PC application, that device goes into a different execution mode while other devices continue to broadcast their packets.
This behaves in the desired manner when there is only one device in the personal area network.
I am facing a strange issue when there are two or more devices in the network, such that:
I set the endPoint to the desired IPAddress and Port of the desired device using the discovered device list.
I call myUDP.Receive(ref endPoint); to receive UDP Datagram
This returns with the Datagram which was broadcasted by the second device in the network, rather than returning the response from the device with which I am trying to communicate. I have verified using the Wireshark that the response is sent from the device.
I tried looping through for a finite number of times to get the desired datagram.
// Some code which initializes the endPoint with desired IP Address and Port
...
// Some code which sends the data
...
// Some code which sets the IP Address of the device from which the response is expected
selectedIPAddress = IPAddress.Parse(labelIPAddressSettings.Text.Trim());
copyendPoint = endPoint;
// Listen to response
do
{
rexdDatagram = myUDP.Receive(ref endPoint);
if (endPoint.Address != selectedIPAddress)
{
// This datagram is not from the desired device
// Restore to the desired endpoint
endPoint = copyendPoint;
// Not sure if there is way to discard this enqueued datagram
}
i_timeout = i_timeout + 1;
if (i_timeout == 10)
{
// Datagram from the desired device has not been received
break;
}
// Not sure if the thread needs to sleep, debugging..
Thread.Sleep(1000);
} while (1);
Question:
Is my code correct to loop within enqueued datagrams? Is there a way to discard previous datagrams and start afresh?
The parameter remoteEP on the method UdpClient.Receive is not meant for specifying from which remote endpoint to receive from, but rather to specify which remote endpoint sent the data. You cannot selectively receive only from a specific endpoint.
Instead, you'll have to receive everything from everyone, and discard the packages that were not sent from your desired remote endpoint. You can do this like so:
byte[] receivedData = null;
var attempts = 0;
while (attempts < 10)
{
var recvEp = new IPEndPoint(IPAddress.Any, 0);
readData = myUDP.Receive(ref recvEp);
if (recvEp.Address == selectedIPAddress)
{
// We received data from the correct remote source
receivedData = readData;
break;
}
attempts++;
}
This code will receive data from anywhere, and if it doesn't receive data from the correct endpoint within 10 attempts, it will stop. Resulting in receivedData being null.
You might want to convert your code to wait for a certain amount of time not a certain amount of attempts, to increase the chances of actually receiving something. This could be done like so:
var start = DateTime.Now;
byte[] receivedData = null;
while((DateTime.Now - start).TotalSeconds < 10)
{
var recvEp = new IPEndPoint(IPAddress.Any, 0);
readData = myUDP.Receive(ref recvEp);
if (recvEp.Address == selectedIPAddress)
{
// We received data from the correct remote source
receivedData = readData;
break;
}
}
This code will try for 10 seconds, and stop after 10 seconds if nothing was received. This is not perfectly clean code, for example if you want to you can make this whole thing async.
Note: It is possible that both code snippets will result in an infinite loop, as myUDP.Receive(ref recvEp) will block as long as there isn't any incoming data. So if all your remote endpoints decide to stop sending data at the same time, the receive call will never return

Listen to responses from 2 TcpClient instances against the same IP, but different ports

I'm working on a TCP connection where my client connects to a server's IP on 2 different ports. So I have 2 instances of TcpClient objects, one connecting to the IP on port 9000 and the other on port 9001.
The aim of 2 connections is that the server uses the active connection on port 9000 to give certain responses to the client frequently, and the client uses these responses to form and send a request on port 9001.
Now, the first time I connect on 9000, I get a response, I then form a request and fire off via 9001. Now I have a feeling I'm doing something wrong with the way I'm managing asynchronous requests to both ports, but I can't figure an alternate way of doing this:
IPAddress IPAddress = IPAddress.Parse("192.168.1.10");
public static async Task ConnectToPort9000()
{
TcpClient TcpClient1 = new TcpClient();
try
{
await TcpClient1.ConnectAsync(IPAddress, 9000);
if (TcpClient1.Connected)
{
byte[] Buffer = new byte[1024];
while (await TcpClient1.GetStream().ReadAsync(Buffer, 0, Buffer.Length) > 0)
{
//Server returns a message on this port
string Port9000Response = Encoding.UTF8.GetString(Buffer, 0, Buffer.Length);
//Setting ConfigureAwait(false) so that any further responses returned
//on this port can be dealt with
await Task.Run(async () =>
{
await SendRequestToPort9001BasedOnResponseAsync(Port9000Response);
}).ConfigureAwait(false);
}
}
}
catch (Exception)
{
throw;
}
}
private async Task SendRequestToPort9001BasedOnResponseAsync(string Port9000Response)
{
//Open connection on port 9001 and send request
TcpClient TcpClient2 = new TcpClient();
await TcpClient2.ConnectAsync(IPAddress, 9001);
if (TcpClient2.Connected)
{
//Handle each string response differently
if (Port9000Response == "X")
{
//Form a new request message to send on port 9001
string _NewRequestMesssage = "Y";
byte[] RequestData = Encoding.UTF8.GetBytes(_NewRequestMesssage);
new SocketAsyncEventArgs().SetBuffer(RequestData, 0, RequestData.Length);
await TcpClient2.GetStream().WriteAsync(RequestData, 0, RequestData.Length);
await TcpClient2.GetStream().FlushAsync();
//Handle any responses on this port
//At this point, based on the request message sent on this port 9001
//server sends another response on **port 9000** that needs separately dealing with
//so the while condition in the previous method should receive a response and continue handling that response again
}
else if (Port9000Response == "A")
{
//Do something else
}
}
}
The issue I am having at the moment is, after I send the request on port 9001, when processing any response messages on port 9001, the server has already sent me a response on port 9000, but my while loop on the first method isn't getting triggered, and it seems like that's because it's still executing the second method to process request/response on port 9001. I tried using ConfigureAwait(false) to basically fire and forget, but it doesn't seem to be working. Am I handling asynchronous processes the wrong way? Or should I look at alternatives such as action/delegates?
The aim of 2 connections is that the server uses the active connection on port 9000 to give certain responses to the client frequently, and the client uses these responses to form and send a request on port 9001.
Please don't do this. Socket programming is hard enough without making it extremely more complicated with multiple connections. Error handling becomes harder, detection of half-open connections becomes harder (or impossible), and communication deadlocks are harder to avoid.
Each socket connection is already bidirectional; it already has two independent streams. The only thing you need to do is always be reading, and send as necessary. The read and write streams are independent, so keep your reads and writes independent.

Is this a feasible way to determine if a port can be used by a server for Http or Ws?

I'm developing an application that hosts a browser control. The client (in the browser, using a localhost address) communicates with the server via websockets and the server handles the Http requests.
The users can define ports for both Http and Ws, but (since several instances of the application can be opened) I need to detect, if they are usable - if not, I notify the users that an alternative port will be used.
Verifying that the intended Http port is blocked was possible using a HttpListener, but (for reasons I don't understand) the listener could apparently use a port already used by another application for a websocket connection.
So I ended up with the following code, which appears to do the job. I use it to first test a specified port and, if that fails, I loop through a range of port numbers and try until the method returns True.
private static bool testPort(int port)
{
bool result = false;
System.Net.IPEndPoint endpoint = new System.Net.IPEndPoint(System.Net.IPAddress.Loopback, port);
using (System.Net.Sockets.Socket s = new System.Net.Sockets.Socket(System.Net.Sockets.AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.IP)) {
try {
Console.WriteLine("Testing port {0}", port);
s.Connect(endpoint);
s.Bind(endpoint);
result = true;
} catch (SocketException ex) {
switch (ex.SocketErrorCode) {
case SocketError.InvalidArgument:
//This error is apparently thrown when a port is occupied.
result = false;
break;
case SocketError.ConnectionRefused:
//NOTE: This error is apparently thrown when a port is not occupied (but the connection fails, because the socket cannot connect since the port is not being used?).
result = true;
break;
default:
result = false;
break;
}
} catch (Exception ex) {
result = false;
}
}
return result;
}
But I'm not sure, if maybe it's just a "lucky coincidence". Like I mentioned, it works as far as I could test it, but does it make any sense? And: is it reliable?
The code is subject to a race condition. The connect call might fail because the port is not in use, but another program may then take that port before the function is able to return.
Testing a bunch of ports could result in noticeable delays as well. For example a firewall may be configured to drop packets rather than sending a connection refused response. In this case the connect call would block until a timeout is reached.
As a side note, Bind needs to be called before Connect to work, however in this case the Bind call should be removed. You cannot bind a connecting socket to the same endpoint you're attempting to connect to.

TCP socket.receive() seems to drop packets

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

SocketException: An existing connection was forcibly closed under IIS 7, but OK under IIS 6

We have had an .ashx application running under IIS 6/Windows Server 2003 for a few years now. We've recently been trying to get some new servers up and running and need to migrate to Win 2k8 R2 and IIS 7.5, however I'm having a bear of a time getting the application to run well on the new servers.
The .ashx is a web interpreter for a custom message queuing engine we have that talks via TCP. So, inside the .ashx we create a socket to talk to the message queue server. Nothing about this architecture has changed, but the error that I get on the Win 2k8 and IIS 7.5 setup, which runs .Net 4, is
System.Net.Sockets.SocketException (0x80004005): An existing
connection was forcibly closed by the remote host at
System.Net.Sockets.Socket.Receive(Byte[] buffer, SocketFlags
socketFlags)
We don't get this error on the older setup - same code, though it's running the .Net 3.5 runtime.
Please keep in mind that this error is not being thrown from an HTTP-facing socket, but rather from the socket that is trying to talk to the message queue server. I have verified that I do not believe I have a firewall issue by running a "raw" telnet session from the web server to the message queue and am able to successfully interact with the message queue.
Here is how we set up the socket:
this.m_sock = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.IP);
System.Net.IPAddress ip = System.Net.IPAddress.None;
// Before bothering the DNS server, try to parse numeric IP
try
{
ip = System.Net.IPAddress.Parse(host);
}
catch (FormatException)
{
// Not a numeric IP. Do the DNS lookup.
// (BTW: DNS lookup will convert the IP, but only after a failing lookup, which is slow)
IPHostEntry ipadd = System.Net.Dns.GetHostEntry(host);
// (Note: That lookup might fail. It'll throw a SocketException.)
ip = ipadd.AddressList[0];
}
try
{
this.m_sock.Connect(ip, port);
this.m_sock.SetSocketOption(SocketOptionLevel.IP, SocketOptionName.ReuseAddress, true);
this.m_sock.SetSocketOption(SocketOptionLevel.IP, SocketOptionName.NoDelay, true);
this.m_sock.SetSocketOption(SocketOptionLevel.Socket, SocketOptionName.KeepAlive, 1);
this.m_sock.ReceiveTimeout = 60 + this.m_timeout;
this.m_sock.Blocking = true;
this.m_sock.ReceiveBufferSize = 65536;
this.m_sock.SendBufferSize = 65536;
if (ok != "" && !this.m_isweb)
{
Console.WriteLine(ok);
}
break;
}
catch (SocketException)
{
this.m_sock.Close();
this.m_sock = null;
}
And now a snippet of the "ReadSome" method that blows up on us at the this.m_sock_Receive:
if (this.m_sock.Poll(1000000, SelectMode.SelectRead))
{
n = this.m_sock.Available;
if (n == 0)
n = 1; // Presume at least one byte readable
if (max > 0 && n > max)
n = max;
byte[] buf = new byte[n];
int rcvd = this.m_sock.Receive(buf, SocketFlags.None);
if (rcvd == 0)
throw new knetmq_Exception(this, "Read EOF",
knetmq_Exception.codes.EOF);
return buf;
}
Before the "Receive" happens, there is a "Send" that occurs without exception, however I do not see the payload on the other side.
Any help is appreciated!
Oh Joy! I fixed it!
The short of it: I hadn't set my TTL, and on the new server TTL was getting consistently exceeded.
More in-depth: The new server happened to be on a slightly different network. Because we didn't set TTL, the TTL defaulted to 1. A wireshark discovered that the TTL was being exceeded repeatedly and so a TCP RST was issued, which caused the error to be thrown. That's why the messages were never received by the remote host.
I banged my head on this one for 2 days, so I hope anyone who ends up getting that SocketException can see this and look for TTL issues!

Categories

Resources