I am communicating between PC and IO modules with TCP connection over ethernet using Modbus protocol. I am using System.Net.Sockets.Socket class for opening and sending/receiving data. At first everything is fine. After some time(5 to 10 hours) I get the following SocketException with error code 10060 when the program calls Socket.Connect method. I try to reconnect after I get the exception but same exception is thrown.
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
During the normal execution(in the 5-10 hour duration before exception is thrown) I create a new tcp connection by closing old sockets and creating new ones. This is done many times. I check the number of tcp connections every time I reconnect and it stays same. I use the following method to connect many times where SocketWrapper is the class that I use to connect to modules and send/receive data.
How can I investigate this issue?
class SocketWrapper
{
IPAddress m_ipAddr;
Socket m_Socket;
int m_port;
public bool Connect(string i_szIPAddr, ProtocolType protocolType)
{
try
{
this.Disconnect();
this.m_ipAddr = IPAddress.Parse(i_szIPAddr);
this.m_port = 0x1f6;
IPEndPoint remoteEP = new IPEndPoint(this.m_ipAddr, this.m_port);
this.m_socket = new Socket(remoteEP.AddressFamily, SocketType.Stream, ProtocolType.Tcp);
this.m_socket.Connect(remoteEP);
return true;
}
catch
{
return false;
}
}
public void Disconnect()
{
if (this.m_socket != null)
{
if(this.m_socket.Connected)
this.m_socket.Shutdown(SocketShutdown.Both);
this.m_socket.Close();
this.m_socket = null;
}
}
}
Related
I'm trying to write a chat client/server in c# locally to get familiar with Sockets.
First I start the server with (very simplified) following code:
Server.cs
private readonly MessageManager _messageManager;
private readonly ChatServer _chatServer;
public ChatServerSkeleton()
{
_messageManager = new MessageManager();
_chatServer = new ChatServer();
Console.WriteLine("Server is running on: " + _messageManager.MyAddress);
}
Then I start the Client with +- same way, except I store the serveraddress in the client (I copied the server address into a prompt).
Client.cs
private readonly MessageManager _messageManager;
public ChatClient ChatClient { get; }
public ChatClientSkeleton(IPEndPoint serverAddress, string name)
{
_messageManager = new MessageManager();
ChatClient = new ChatClient(new ChatServerStub(serverAddress, _messageManager), name);
Console.WriteLine($"IPAddress of {name} is: {_messageManager.MyAddress}");
Console.WriteLine($"IPAddress of Server is: { serverAddress}");
}
MessageManager.cs
private readonly TcpListener _serverSocket;
public IPEndPoint MyAddress { get; }
public MessageManager()
{
try
{
//Create server socket on random port
_serverSocket = new TcpListener(IPAddress.Any, FindFreeTcpPort());
//Get host ip address
IPAddress[] localIps = Dns.GetHostAddresses(Dns.GetHostName());
IPAddress localhost = localIps.First(ip => ip.AddressFamily == AddressFamily.InterNetwork);
//Get port of serversocket
IPEndPoint ipEndPoint = _serverSocket.LocalEndpoint as IPEndPoint;
int port = ipEndPoint.Port;
//Create address
MyAddress = new IPEndPoint(localhost, port);
}
catch (Exception ex)
{
Console.Error.WriteLine("Something went wrong with the serversocket:");
Console.Error.WriteLine(ex);
}
}
FindFreeTcp port comes from here: https://stackoverflow.com/a/150974/5985593
Everything up till now seems to work. Let's say for example the server has now 192.168.0.219:51080 and the client 192.168.0.219:51085.
The problem occurs when I'm trying to send a message using this code in MessageManager.cs
public void Send(MethodCallMessage message, IPEndPoint address)
{
try
{
_serverSocket.Start();
TcpClient destination = new TcpClient(address.Address.ToString(), address.Port);
NetworkStream output = destination.GetStream();
MessageReaderWriter.Write(message, output);
destination.Close();
}
catch (Exception ex)
{
Console.Error.WriteLine("Failed to write a message:");
Console.Error.WriteLine(ex);
}
finally
{
_serverSocket.Stop();
}
}
More specific on the _server.Start(); line.
Anyone knows what I'm doing wrong?
Thanks in advance!
EDIT: it runs fine 1 time, when registering the client on the server. But after that if I want to send a message I get the SocketException where target machine actively refused.
I do use AcceptTcpClient() here:
MessageManager.cs
public MethodCallMessage WReceive()
{
MethodCallMessage result = null;
try
{
//_serverSocket.Start();
TcpClient client = _serverSocket.AcceptTcpClient();
NetworkStream input = new NetworkStream(client.Client, true);
result = MessageReaderWriter.Read(input);
client.Close();
}
catch (Exception ex)
{
Console.Error.WriteLine("Failed to receive a message:");
Console.Error.WriteLine(ex);
}
finally
{
//_serverSocket.Stop();
}
return result;
}
This method is used in the ServerSkeleton & ClientSkeleton as follows:
public void Run()
{
while (true)
{
MethodCallMessage request = _messageManager.WReceive();
HandleRequest(request);
}
}
So the flow is basically as follows:
I start the server (instantiate new messagemanager, 3rd snippet
and run serverskeleton (last snippet)
Server prints IP in
console, i copy the ip & start the client
Instantiate client &
set server ip to what I copy pasted
Start client skeleton (last
snippet)
A TcpListener that has called Start() listens for incoming connections and then stacks them on a queue. Once that queue is full then a socket exception results. To remove connections from the queue you need to use the AcceptTcpClient or AcceptSocket methods of TcpListener. This then gives you a connection that you can send and receive data on.
What I am guessing may be happening is that you receive your first incoming client, but dont accept and remove it to send and receive data on, and your subsequent connections are refused as the pending queue list is full (this is just a guess).
There is an overloaded method ... TcpListener.Start(int backlog) ... that allows you to set the size of the pending queue list (so you can have 5, 10 or more connections waiting to be accepted in the TcpListener)
With a server TCP socket the process is that you set it listening on a local address and a port. Clients then try to connect to that endpoint. When they connect the TCP listening socket accepts the connection and then passes that to a socket which is the socket on which data is transfered. The listening socket carries on listening for new connections, it doesnt itself transmit data.
I hope that makes sense ?
So the server would behave more like this ...
_serverSocket.Start();
TcpClient myAcceptedConnection = _serverSocket.AcceptTcpClient();
// in synchronous blocking socket situation the program flow halts
// here til a connection is established
// once you have a connection ... do stuff with myAcceptedConnection
if you wished to avoid the blocking scenario you can use TcpListener.Pending() to see if you have any connections waiting in the queue
EDIT 1:
Ok so the only weird thing I see is that you call the _serverSocket.Start() method in the MessageSend method ? A server doesnt normally start by sending out a message ... it normally waits listening for a connection, receives and reads the connection and then replies (or it might send out a greeting or such on connection).
Personally I would separate the listening aspect of the server from the sending and receiving of data ... have it in its own separate method, after all you want your server to be listening for incoming connections until you close it down. When you detect an incoming connection (perhaps by checking Pending() in a loop), then you can accept it and send and receive on the new TcpClient. When you are finished with whatever data you are transmitting/receiving on that client you can close it down , if thats what you want ... you dont need to close and open a tcp connection every time you send a message, you can leave it open til you are finished with it, in fact opening and closing tcp connections generates a bit of overhead in the handshake protocol that they go through.
There are caveats though ... Tcp connections can become "half open" especially with wireless which can lead to issues. Its a bit complicated to get into here, but I recommend this stellar set of articles by Stephen Cleary as a good read through. Read the whole blog, as there is a ton of good info in there.
So, back to simple, I would have ...
A serverStart() method where you start your server listening.
A serverAccept() method where you check if you have any pending connections and accept them if they are there.
A clientConnect() method for your client where you connect to a server
Read() and Write() methods for the server and the client where you do the data transmission.
Normally the flow would be ...
Server Listens
Client Connects
Server Accepts
Client Sends
Server Receives
(then server sends/receives, client sends/receives)
everything closes and shuts down
When I try to create a new TcpClient I am getting a SocketException, here is my code:
public void TcpOpenConnection()
{
// The next line is where the exception is occurring.
tcpClient = new TcpClient(ipAddress, port);
connected = true;
}
I have checked to make sure the port is open with netstat -a in cmd, and I even made another function to check if the port is open:
public static bool PortCheck(int port)
{
bool portOpen = false;
IPGlobalProperties ipGlobalProperties = IPGlobalProperties.GetIPGlobalProperties();
TcpConnectionInformation[] tcpConnInfo = ipGlobalProperties.GetActiveTcpConnections();
foreach (var tcpConn in tcpConnInfo)
{
if (tcpConn.LocalEndPoint.Port == port)
{
portOpen = true;
break;
}
}
return portOpen;
}
which returns true. The exception that I am getting is a SocketException and it is saying the machine I am trying to connect to is actively refusing the connection. What could be the issue here? I have also tried other ports, with no luck.
If you need more info please ask, and I will gladly supply more.
The exception that I am getting is a SocketException and it is saying the machine I am trying to connect to is actively refusing the connection.
This is likely an indication that the target host isn't listening on the port which could be caused by a number of reasons:
The router of the server's network is not correctly port-forwarded
The router's firewall / server's firewall is blocking the connections
The server and the client are not using the same port
The server is misconfigured
The list goes on... but essentially, this error means that the server isn't allowing the connection.
If the port is open and you try to connect to. You get SocketException because there is nothing for get the client connection.
So you need to host a Tcplistner on this port.
static void StartServer()
{
int port = 150;
TcpListener listner = new TcpListener(IPAddress.Any, port);
listner.Start();
// This line waits the client connection.
TcpClient remote_client = listner.AcceptTcpClient();
// do something with remote_client.
}
And you can connect to.
static void StartClient()
{
int port = 150;
IPAddress ip = IPAddress.Parse("127.0.0.1");
TcpClient client = new TcpClient();
client.Connect(ip, port);
// Do something with client.
}
I have got the following two functions to start and stop a 'local server' (Socket listener).
public String startServer(Int32 port, Int32 maximumPendingConnections, ref String errorMsg) {
try {
// Creates one SocketPermission object for access restrictions
permission = new SocketPermission(
NetworkAccess.Accept, // Allowed to accept connections
TransportType.Tcp, // Defines transport types
"", // The IP addresses of local host
SocketPermission.AllPorts // Specifies all ports
);
// Listening Socket object
sListener = null;
// Ensures the code to have permission to access a Socket
permission.Demand();
// Resolves a host name to an IPHostEntry instance
IPHostEntry ipHost = Dns.GetHostEntry("");
// Gets first IP address associated with a localhost
ipAddr = ipHost.AddressList[0];
// Creates a network endpoint
ipEndPoint = new IPEndPoint(ipAddr, port);
// Create one Socket object to listen the incoming connection
sListener = new Socket(
ipAddr.AddressFamily,
SocketType.Stream,
ProtocolType.Tcp
);
// Associates a Socket with a local endpoint
sListener.SetSocketOption(SocketOptionLevel.Socket, SocketOptionName.ReuseAddress, true); //newly added as an answer
sListener.Bind(ipEndPoint);
sListener.Listen(maximumPendingConnections);
// Begins an asynchronous operation to accept an attempt
AsyncCallback aCallback = new AsyncCallback(AcceptCallback);
sListener.BeginAccept(aCallback, sListener);
} catch (Exception e) {
//ErrorHandling
}
return ipAddr.ToString();
}
Stop Connection:
public void stopServer(ref String errorMsg) {
try {
sListener.Shutdown(SocketShutdown.Both);
sListener.Disconnect(true);
sListener.Close();
sListener.Dispose();
} catch (Exception e) {
//Errorhandling
}
}
I have found on SO that you cannot reuse a socket, however if you set sListener.Disconnect(true); it should be able to reuse it. Besides I'm creating a new socket every time on starting. What am I missing here?
It gives the error back that every socket can only be used once. It gives an error on sListener.Bind(ipEndPoint);
#Edit 14:41 - 16-12-2015
I have found that if I add the following line of code before the sListener.Bind(ipEndPoint); It works;
sListener.SetSocketOption(SocketOptionLevel.Socket, SocketOptionName.ReuseAddress, true);
If you want to actually to reuse the socket, don't do Shutdown, Close and Dispose, since these calls return the resources used by the socket to the OS. Basically, your socket handler becomes invalid and the work done by Disconnect(true) is futile then.
(You also don't need to do Shutdown and Close at the same time. Just Close will do the trick.)
The Connected property will always return false because socket is in listening state, not connected. Unfortunately, is not possible to "unlisten" the socket so you have to close it and create new socket.
Another issue is: the sequence Shutdown, Disconnect, Close and Dispose looks like kicking the dead body.
I wrote a TCP server to use the BeginAccept/EndAccept pattern. With this, I coded up a simple UnitTest using a TcpClient, and measured each portion. All tests are localhost, so I am surprised to see that TCP connection is consistently taking 1 second. I have set the Socket.NoDelay = true although I believe this only affects Send/Receive. I am not receiving the first packet of data. Any help or ideas on speed this up are appreciated.
Note: I can not change the client side to keep the connection open, and I need to be able to handle a lot of requests per second if possible.
Server Side:
public void Start()
{
System.Net.IPHostEntry localhost = System.Net.Dns.GetHostEntry(System.Net.Dns.GetHostName());
System.Net.IPEndPoint endpoint;
int port = Properties.Settings.Default.ListenPort;
//
// Setup the connection to listen on the first IP, and specified port
//
endpoint = new IPEndPoint(IPAddress.Any, port);
listenSocket = new Socket(endpoint.Address.AddressFamily, SocketType.Stream, ProtocolType.Tcp);
listenSocket.Bind(endpoint);
listenSocket.NoDelay = true; // do not wait 200 milliseconds for new data to be buffered on the connection
listenSocket.Listen(int.MaxValue);
Console.WriteLine("Listening on {0}:{1}", localhost.AddressList[0], port);
//
// Post the accept. The accept method will continuously post a new accept as soon as a connection is made
//
while (true)
{
accepted.Reset();
Connection connection = connections.Pop();
listenSocket.BeginAccept(AcceptCallback, connection);
accepted.WaitOne();
}
}
private static void AcceptCallback(IAsyncResult ar)
{
accepted.Set();
Connection connection = ar.AsyncState as Connection;
Socket remoteSocket = null;
try
{
remoteSocket = listenSocket.EndAccept(ar);
remoteSocket.NoDelay = true;
connection.RemoteSocket = remoteSocket;
//
// Start the Receive cycle
//
Receive(connection);
}
catch (SocketException)
{
Disconnect(connection);
}
}
Simple Test Client:
[TestMethod()]
public void ClientTest()
{
TestContext.BeginTimer("Connection");
TcpClient client = new TcpClient("localhost", 10300);
NetworkStream stream = client.GetStream();
TestContext.EndTimer("Connection");
...
Using a LoadTest I loaded 25 users, and the Transaction "Connection" always takes above 1 second.
Not sure why, but simply changing this:
TestContext.BeginTimer("Connection");
TcpClient client = new TcpClient("localhost", 10300);
TestContext.EndTimer("Connection");
To this:
TestContext.BeginTimer("Connection");
TcpClient client = new TcpClient();
client.Connect("localhost", 10300);
TestContext.EndTimer("Connection");
Drops the time from 1 second to .13 seconds. Will have to investigate as to why, but hopefully this will help somebody out in the future.
When you attempt to connect using the TcpClient constructor on a host that resolves to both Ipv6 and Ipv4 addresses, the connection using Ipv6 is attempted first. If it fails then it attempts to connect using the Ipv6 address. This is the cause of the 1 second delay. Here is the MSDN link:
I'm using the code below, it seem sometime the socket is not released
How did I found that?
by using process explorer(from sysinternal),
proprieties on the application
then going into TCP/IP tab.
I can see the port being used by typing "netstat -a" into a console
My problem is, after a while (like 5 weeks) there is like 40 port used by the application while it should be zero.
Anyone know why it does that?
public void Connect()
{
try {
// Resolve server address
IPHostEntry hostadd = Dns.GetHostEntry(TimeServer);
IPEndPoint EPhost = new IPEndPoint(hostadd.AddressList[0], 123);
//Connect the time server
UdpClient TimeSocket = new UdpClient();
TimeSocket.Connect(EPhost);
TimeSocket.Send(SNTPData, SNTPData.Length);
SNTPData = TimeSocket.Receive(ref EPhost);
TimeSocket.Close();
if (!IsResponseValid())
{
throw new Exception("Invalid response from " + TimeServer);
}
} catch(SocketException e)
{
throw new Exception(e.Message);
}
}
You're blocking forever on:
SNTPData = TimeSocket.Receive(ref EPhost);
If the socket never receives a packet it will sit there waiting until the process dies.
You'll need to close the socket by calling TimeSocket.Close() on a different thread or by setting a timeout on the receive using SetSocketOption.