Socket not being closed properly - c#

Using the code as provided here.
When run consecutive times within 120 seconds, fails on my machine with a SocketException:
Only one usage of each socket address (protocol/network address/port) is normally permitted 127.0.0.1:24125
at System.Net.Sockets.Socket.DoConnect(EndPoint endPointSnapshot, SocketAddress socketAddress)
at System.Net.Sockets.Socket.Connect(EndPoint remoteEP)
Windows 10 x64
Adding socket.Close(); after socket.Receive(receiveBuffer); does nothing. Perhaps obvious because Dispose() should call Close() automatically anyway.
There is no difference in behaviour if ported to F#. So it's to do with how the .NET libraries are being used rather than anything language specific (again, sorry if that's obvious).
The same occurs if the output .exe is run from Windows Command Prompt or from the debugger.
After socket is disposed in code, waiting longer than 120 seconds resets the socket and it can be used once more without error.
using System;
using System.Net;
using System.Net.Sockets;
using System.Text;
namespace tcpTestCSharp
{
class Program
{
static void Main(string[] args)
{
string response = "Hello";
IPAddress ipAddress = IPAddress.Parse("127.0.0.1");
if (ipAddress != null)
{
IPEndPoint serverEndPoint = new IPEndPoint(ipAddress, 24125);
byte[] receiveBuffer = new byte[100];
try
{
using (TcpClient client = new TcpClient(serverEndPoint))
{
using (Socket socket = client.Client)
{
socket.Connect(serverEndPoint);
byte[] data = Encoding.ASCII.GetBytes(response);
socket.Send(data, data.Length, SocketFlags.None);
socket.Receive(receiveBuffer);
Console.WriteLine(Encoding.ASCII.GetString(receiveBuffer));
}
}
}
catch (SocketException socketException)
{
Console.WriteLine("Socket Exception : ", socketException.Message);
throw;
}
Console.ReadLine();
}
}
}
}

Related

No connection could be made because the target machine actively refused it, works on localhost but not my local IP

I'm working on a TCP client in C#. It works fine when I send packets to my server if the IP it's sending data to is 127.0.0.1, but when I change it to my actual ipv4 address it breaks and gives me this error message:
No connection could be made because the target machine actively refused it
I've checked netstat -a and I can see that a service is listening on port 5000 (my application), I've also opened up the port in my firewall (5000-5500).
What further actions can I take before I have to contact the sysadmin to see if something else may be blocking my connection?
Here is my TCP client:
using Microsoft.Win32;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Net.Http;
using System.Net.Sockets;
using System.Text;
using System.Threading.Tasks;
namespace TestLockedConsoleAppNet
{
class Program
{
static void Main(string[] args)
{
Console.WriteLine("Hello World");
SystemEvents.SessionSwitch += new SessionSwitchEventHandler(SystemEvents_Locked);
TestTCP();
while (true) { }
}
static void SystemEvents_Locked(object sender, SessionSwitchEventArgs e)
{
if (e.Reason == SessionSwitchReason.SessionLock)
{
Console.WriteLine("Locked");
}
TestTCP();
}
static void TestTCP()
{
TcpClient client = new TcpClient("127.0.0.1", 5000); // <-- works fine. But when I change the IP to my ipv4 address, it breaks.
Byte[] data = System.Text.Encoding.ASCII.GetBytes("Locked");
NetworkStream stream = client.GetStream();
stream.Write(data, 0, data.Length);
Console.WriteLine("Sent: {0}", "Message");
data = new Byte[256];
String responseData = String.Empty;
Int32 bytes = stream.Read(data, 0, data.Length);
responseData = System.Text.Encoding.ASCII.GetString(data, 0, bytes);
Console.WriteLine("Received: {0}", responseData);
stream.Close();
client.Close();
}
}
}
netstat -na | find "5000" provides this when I run listening to my local IPv4:
TCP 10.146.200.78:5000 0.0.0.0:0 LISTENING

Socket Exception error

I have a networking socket program in C#.net.
I have to connect with an ip: 169.254.74.65 and port:7998 and my ip is:169.254.74.63.
So I have this code:
using System;
using System.Net;
using System.Net.Sockets;
class MyTcpListener{
public static void Main(){
TcpListener server = null;
try{
Int32 port = 7998;
IPAddress localAddr = IPAddress.Parse("169.254.74.65");
server = new TcpListener(localAddr, port);
server.Start();
Byte[] bytes = new Byte[500];
String data = null;
while (true){
Console.Write("Waiting for a connection... ");
TcpClient client = server.AcceptTcpClient();
data = null;
NetworkStream stream = client.GetStream();
int i;
while ((i = stream.Read(bytes, 0, bytes.Length)) != 0){
data = System.Text.Encoding.ASCII.GetString(bytes, 0, i);
Console.WriteLine("Received: {0}", data);
}
client.Close();}
}
catch (SocketException e){
Console.WriteLine("SocketException: {0}", e);}
finally{ server.Stop(); }
Ping works fine between two IPs. Even telnet 169.254.74.65 7998 gives me proper result and listens to the correct messages. So the connection is solid.
But when I run the above code it shows an exception:
> SocketException: System.Net.Sockets.SocketException (0x80004005): The requested address is not valid in its context
at System.Net.Sockets.Socket.UpdateStatusAfterSocketErrorAndThrowException(SocketError error, String callerName)
at System.Net.Sockets.Socket.DoBind(EndPoint endPointSnapshot, SocketAddress socketAddress)
at System.Net.Sockets.Socket.Bind(EndPoint localEP)
at System.Net.Sockets.TcpListener.Start(Int32 backlog)
at System.Net.Sockets.TcpListener.Start()
at MyTcpListener.Main() in C:\Users\Administrator\source\repos\TCPListener\TCPListener\Program.cs:line 12
What is the problem here?
Your code works for me:
Have you actually hit your server at 127.0.0.1:7998 from a client socket code?
Update
So your Server IP is 169.xx.xx.65, while your own DEV machine IP is 169.xx.xx.63
Your code is something which creates a TCP Server connection. While (if I am not wrong) - you only need to connect to that HL7 machine.
Understand that the HL7 machine will be the server and your machine will be the client. So you just need TcpClient. Something like:
TcpClient client = new TcpClient("169.xx.xx.65", 7998);
Use Connect/GetStream etc methods per: https://msdn.microsoft.com/en-us/library/system.net.sockets.tcpclient(v=vs.110).aspx

In a project how to set up a "client" console application and a "server" console application

Alright so this might be worded wrong or using the wrong terminology. I want to know how I would set up a console application in my local machine that would be the "server" where it would run all my background tasks/events that happen on the client windows? I would only have one console application for the "server" and up to four "client" console applications.
Each of these would do separate things. The "server" application would just do all the calculations and functions and the client would just show in nice format what I want them to show from the results from the server.
Also I wouldn't know how to set it up in a C# type of project.
For a complete tutorial, I would recommend reading this Code Project article.
For some example code, the following client / server console applications are pulled from the MSDN.
Synchronous Client Socket Example:
using System;
using System.Net;
using System.Net.Sockets;
using System.Text;
public class SynchronousSocketClient {
public static void StartClient() {
// Data buffer for incoming data.
byte[] bytes = new byte[1024];
// Connect to a remote device.
try {
// Establish the remote endpoint for the socket.
// This example uses port 11000 on the local computer.
IPHostEntry ipHostInfo = Dns.Resolve(Dns.GetHostName())
IPAddress ipAddress = ipHostInfo.AddressList[0];
IPEndPoint remoteEP = new IPEndPoint(ipAddress,11000);
// Create a TCP/IP socket.
Socket sender = new Socket(AddressFamily.InterNetwork,
SocketType.Stream, ProtocolType.Tcp );
// Connect the socket to the remote endpoint. Catch any errors.
try {
sender.Connect(remoteEP);
Console.WriteLine("Socket connected to {0}",
sender.RemoteEndPoint.ToString());
// Encode the data string into a byte array.
byte[] msg = Encoding.ASCII.GetBytes("This is a test<EOF>");
// Send the data through the socket.
int bytesSent = sender.Send(msg);
// Receive the response from the remote device.
int bytesRec = sender.Receive(bytes);
Console.WriteLine("Echoed test = {0}",
Encoding.ASCII.GetString(bytes,0,bytesRec));
// Release the socket.
sender.Shutdown(SocketShutdown.Both);
sender.Close();
} catch (ArgumentNullException ane) {
Console.WriteLine("ArgumentNullException : {0}",ane.ToString());
} catch (SocketException se) {
Console.WriteLine("SocketException : {0}",se.ToString());
} catch (Exception e) {
Console.WriteLine("Unexpected exception : {0}", e.ToString());
}
} catch (Exception e) {
Console.WriteLine( e.ToString());
}
}
public static int Main(String[] args) {
StartClient();
return 0;
}
}
Synchronous Server Socket Example:
using System;
using System.Net;
using System.Net.Sockets;
using System.Text;
public class SynchronousSocketListener {
// Incoming data from the client.
public static string data = null;
public static void StartListening() {
// Data buffer for incoming data.
byte[] bytes = new Byte[1024];
// Establish the local endpoint for the socket.
// Dns.GetHostName returns the name of the
// host running the application.
IPHostEntry ipHostInfo = Dns.Resolve(Dns.GetHostName());
IPAddress ipAddress = ipHostInfo.AddressList[0];
IPEndPoint localEndPoint = new IPEndPoint(ipAddress, 11000);
// Create a TCP/IP socket.
Socket listener = new Socket(AddressFamily.InterNetwork,
SocketType.Stream, ProtocolType.Tcp );
// Bind the socket to the local endpoint and
// listen for incoming connections.
try {
listener.Bind(localEndPoint);
listener.Listen(10);
// Start listening for connections.
while (true) {
Console.WriteLine("Waiting for a connection...");
// Program is suspended while waiting for an incoming connection.
Socket handler = listener.Accept();
data = null;
// An incoming connection needs to be processed.
while (true) {
bytes = new byte[1024];
int bytesRec = handler.Receive(bytes);
data += Encoding.ASCII.GetString(bytes,0,bytesRec);
if (data.IndexOf("<EOF>") > -1) {
break;
}
}
// Show the data on the console.
Console.WriteLine( "Text received : {0}", data);
// Echo the data back to the client.
byte[] msg = Encoding.ASCII.GetBytes(data);
handler.Send(msg);
handler.Shutdown(SocketShutdown.Both);
handler.Close();
}
} catch (Exception e) {
Console.WriteLine(e.ToString());
}
Console.WriteLine("\nPress ENTER to continue...");
Console.Read();
}
public static int Main(String[] args) {
StartListening();
return 0;
}
}
To set this up, you would need to create a new solution in Visual Studio, and then add two console application projects to that solution, one for the client and one for the server. Once both projects are completed, you can copy and install the code provided above. Build the solution to generate a .exe file for both client and server. Locate your .exe files, run the server first, and then run the client second. You should see some output on both the server and client console windows.
EDIT: Please bear in mind that this will get you as far as running a server and client locally. When you distribute your server / client code to other machines, you will have to contend with firewalls, port forwarding, and potentially proxies depending on your network.

TcpClient not connecting to remote server

I'm trying to connect to a remote machine using the TcpClient class, but it keeps failing:
An unhandled exception of type 'System.Net.Sockets.SocketException'
occurred in System.dll
Additional information: 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
Testing the code when the client and server are local works, but when I try connecting to a remote machine, it no longer works.
Here is the server code:
using System;
using System.Collections.Concurrent;
using System.Collections.Generic;
using System.Linq;
using System.Net;
using System.Net.Sockets;
using System.Net.WebSockets;
using System.Text;
using System.Threading;
using System.Threading.Tasks;
using System.Windows.Forms;
namespace WebSocketServer
{
class Program
{
static void Main(string[] args)
{
Console.WriteLine("Starting a new WebSockets server.");
WebSocketServer server = new WebSocketServer();
Console.WriteLine("The WebSocket server has started.");
bool userRequestedShutdown = false;
while (!userRequestedShutdown)
{
Console.ReadLine();
DialogResult result = MessageBox.Show("Do you want to shut the server down?", "Warning", MessageBoxButtons.YesNo, MessageBoxIcon.Warning);
if (result == DialogResult.Yes)
{
userRequestedShutdown = true;
}
}
server.Stop();
}
class WebSocketServer
{
TcpListener server;
Thread connectionListener;
ConcurrentDictionary<TcpClient, Thread> clients = new ConcurrentDictionary<TcpClient, Thread>();
public WebSocketServer()
{
server = new TcpListener(IPAddress.Parse("127.0.0.1"), (int)Properties.Settings.Default["Port"]);
try
{
server.Start();
}
catch (Exception exception)
{
Console.WriteLine("Error while trying to start the server: {0}", exception.ToString());
}
connectionListener = new Thread(() =>
{
while (true)
{
Console.WriteLine("Waiting for a new client.");
try
{
TcpClient client = server.AcceptTcpClient();
Thread clientListener = new Thread(() =>
{
try
{
NetworkStream stream = client.GetStream();
byte[] buffer = new byte[1024];
Console.WriteLine("Wating for the client to write.");
while (client.Connected)
{
try
{
int bytesRead = stream.Read(buffer, 0, buffer.Length);
Console.WriteLine("Read {0} bytes from the client.", bytesRead);
string data = Encoding.UTF8.GetString(buffer).Substring(0, bytesRead);
Console.WriteLine("Read the following string from the client: {0}", data);
}
catch (Exception exception)
{
Console.WriteLine("Error while trying to read from a TCP client: {0}", exception.ToString());
break;
}
}
Console.WriteLine("Client disconnected. Removing client.");
}
catch (Exception exception)
{
Console.WriteLine("Error while trying to connect to a TCP client: {0}", exception.ToString());
}
client.Close();
clients.TryRemove(client, out clientListener);
});
clientListener.Start();
clients.TryAdd(client, clientListener);
}
catch (Exception exception)
{
Console.WriteLine("Error while trying to accept a TCP client: {0}", exception.ToString());
}
Console.WriteLine("A client has connected.");
}
});
connectionListener.Start();
}
public void Stop()
{
server.Stop();
connectionListener.Abort();
}
}
}
}
Here is the client code:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Net;
using System.Net.Sockets;
using System.Text;
using System.Threading;
using System.Threading.Tasks;
namespace WebSocketClient
{
class Program
{
static void Main(string[] args)
{
Console.WriteLine("Opening up a TcpClient.");
TcpClient client = new TcpClient();
client.Connect("<Remote Hostname>", <RemotePortNumber>);
Console.WriteLine("TcpClient has connected.");
NetworkStream stream = client.GetStream();
bool closed = false;
new Thread(() =>
{
while (!closed)
{
Console.WriteLine("Writing data to the stream.");
byte[] bytes = Encoding.UTF8.GetBytes("Hello, world.");
stream.Write(bytes, 0, bytes.Length);
Thread.Sleep(1000);
}
}).Start();
Console.ReadLine();
closed = true;
}
}
}
So what is the problem here? I am hosting the server on an Azure Virtual Machine, I have opened up the TCP port I am trying to use as the <RemotePortNumber> in Windows Firewall on my remote server by setting both inbound and outbound rules to allow all traffic in and out of the machine on that port, and I have created a TCP endpoint on my Azure portal that maps the external port of my Virtual Machine's hostname to the internal, private port, of my Virtual Machine, both set to map the same port number of <RemotePortNumber> for consistency. To connect, I am using a <Remote Hostname> value of <MyServiceName>.cloudapp.net. I have also tried connecting the stream by using IPAddress.Parse(<Public IP of my Azure Server>) but have had no luck...it just keeps timing out, as if I am not formatting the hostname correctly or something. What am I missing? If anyone can provide some clues as to how to debug the issue, that would also be very helpful.
Update: Running a WireShark trace, I see a lot of these messages (is this bad? I think the TCP Retransmission might be okay if we take into account that for Azure you have to route packets from the public domain's port to the private port of the VM, but not sure about whatever the RST, ACK's are):
Update: Running Microsoft Message Analyzer, I see these messages on the Local Link Layer:
Note: My VM has an Internal IP of 100.75.20.78 and a Public IP of 191.238.37.130. It has the public domain name of ovidius.cloudapp.net. I am trying to host the application on TCP port 6490. I blacked out my personal IP address for the sake of not giving it up.
I have mapped the TCP port in the Azure portal from domain to VM as follows:
After spending two mother _______ days on this (fill in the blanks), I got a little bit creative in ways of exploring alternative methods to try and see if I could rule routing issues out. I can pretty much safely conclude that Microsoft's Virtual Machine routing fails when you map a Public Port to the same Private Port.
For example, I tried setting up the new Socket endpoint below, and it worked because it didn't map the same domain port to the same Virtual Machine port like I had previously done with the WebSocketServer:
Update: Also, when hosting, I had to set up the server, not on the IP of 127.0.0.1, but the Internal IP, which in my case is 100.75.20.78.
Update Again: Contrary to the above solution, I tried to delete the old endpoint at 6490 and recreated it, and it seems to be working when I connect to that address now. I'm not entirely sure why, I can only say that the only difference here is that I had firewall rules on to allow that endpoint's port before creating the endpoint this time...not sure if that would make a difference. I'm honestly not sure what was causing the issues.
Update Yet Again: Just thought about it some more...I think it comes down to the following two issues:
You need to host the server on the Internal IP of your Azure Virtual Machine, not localhost or 127.0.0.1 like I was doing.
You need to not have the "ENABLE DIRECT SERVER RETURN" feature enabled on your Azure endpoint.

Sending and receiving UDP packets between two programs on the same computer

Is it possible to get two separate programs to communicate on the same computer (one-way only) over UDP through localhost/127... by sharing the same port #?
We're working on a student project in which we need to send UDP packets containing some telemetry between two computers. The program that generates these packets is proprietary, but I'm working on the receiver program myself with C# using System.Net.Sockets.UdpClient and System.Net.IPEndPoint.
This works fine during our group's meetings when we have multiple computers connected on which we can run the two programs separately. But it's not very useful when I'm home and trying to expand on the telemetry processing program as I only have one computer (I need a feed for testing the processing program). I can not install the program on any of the school's computers either.
When I try to run both programs on my computer at the same time (starting my program last) I get a SocketException saying that only a single use of each port is normally allowed. Which leads me to believe there must be some way to share the port (although it makes sense that only a single program can use port on a computer at any one time, I have no trouble running multiple internet browsers at the same time (and I suppose they use port 80 for http)).
REEDIT of the EDIT:
sipwiz was right, and thanks to Kalmi for the pointer to UdpClient.Client.Bind().
At the time, though, we are considering using another program that generates similar packets, and with which we are able to share port with on the same computer using my first (although naive) approach with the UDP client binding in the ctor.
Sorry for having to unmark your answer, sysrqb.
You can bind to a port multiple times using the ReuseAddress socket option.
UdpClient udpClient = new UdpClient();
udpClient.Client.SetSocketOption(SocketOptionLevel.Socket, SocketOptionName.ReuseAddress, true);
You'll need to set the same option on the UDP server socket as well.
I did not expect this to be possible, but.. well.. sipwiz was right.
It can be done very easily. (Please vote sipwiz's answer up!)
IPEndPoint localpt = new IPEndPoint(IPAddress.Any, 6000);
//Failed try
try
{
var u = new UdpClient(5000);
u.Client.SetSocketOption(SocketOptionLevel.Socket, SocketOptionName.ReuseAddress, true);
UdpClient u2 = new UdpClient(5000);//KABOOM
u2.Client.SetSocketOption(SocketOptionLevel.Socket, SocketOptionName.ReuseAddress, true);
}
catch (Exception)
{
Console.WriteLine("ERROR! You must call Bind only after setting SocketOptionName.ReuseAddress. \n And you must not pass any parameter to UdpClient's constructor or it will call Bind.");
}
//This is how you do it (kudos to sipwiz)
UdpClient udpServer = new UdpClient(localpt); //This is what the proprietary(see question) sender would do (nothing special)
//!!! The following 3 lines is what the poster needs...(and the definition of localpt (of course))
UdpClient udpServer2 = new UdpClient();
udpServer2.Client.SetSocketOption(SocketOptionLevel.Socket, SocketOptionName.ReuseAddress, true);
udpServer2.Client.Bind(localpt);
Here is the full code from the answers by Tarnay Kálmán and sipwiz:
The server code:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Net;
using System.Net.Sockets;
using System.Text;
using System.Threading.Tasks;
namespace UdpBroadcastTest
{
class Program
{
static void Main(string[] args)
{
Console.WriteLine("Sender");
// This constructor arbitrarily assigns the local port number.
UdpClient udpClient = new UdpClient();
udpClient.Client.SetSocketOption(SocketOptionLevel.Socket, SocketOptionName.ReuseAddress, true);
udpClient.Connect("localhost", 11000);
try
{
string message = String.Empty;
do
{
message = Console.ReadLine();
// Sends a message to the host to which you have connected.
Byte[] sendBytes = Encoding.ASCII.GetBytes(message);
udpClient.Send(sendBytes, sendBytes.Length);
} while (message != String.Empty);
udpClient.Close();
}
catch (Exception e)
{
Console.WriteLine(e.ToString());
}
Console.WriteLine("Press Any Key to Continue");
Console.ReadKey();
}
}
}
The client code:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Net;
using System.Net.Sockets;
using System.Text;
using System.Threading.Tasks;
namespace UdpReciever
{
class Program
{
static void Main(string[] args)
{
Console.WriteLine("Receiver");
// This constructor arbitrarily assigns the local port number.
UdpClient udpClient = new UdpClient();
udpClient.Client.SetSocketOption(SocketOptionLevel.Socket, SocketOptionName.ReuseAddress, true);
udpClient.Client.Bind(new IPEndPoint(IPAddress.Any, 11000));
try
{
//IPEndPoint object will allow us to read datagrams sent from any source.
IPEndPoint RemoteIpEndPoint = new IPEndPoint(IPAddress.Any, 0);
string message = String.Empty;
do
{
// Blocks until a message returns on this socket from a remote host.
Byte[] receiveBytes = udpClient.Receive(ref RemoteIpEndPoint);
message = Encoding.ASCII.GetString(receiveBytes);
// Uses the IPEndPoint object to determine which of these two hosts responded.
Console.WriteLine("This is the message you received: " +
message);
//Console.WriteLine("This message was sent from " +
// RemoteIpEndPoint.Address.ToString() +
// " on their port number " +
// RemoteIpEndPoint.Port.ToString());
}
while (message != "exit");
udpClient.Close();
//udpClientB.Close();
}
catch (Exception e)
{
Console.WriteLine(e.ToString());
}
Console.WriteLine("Press Any Key to Continue");
Console.ReadKey();
}
}
}
You might be able to put multiple IP addresses on your network card, or loopback, and bind the server and client to different IP addresses?
Or else the Virtual machine approach will definitely work.
Only one program can bind to a port at a time. Multiple programs can connect to one port on another system's, but the local port your different web browsers have bound themselves to is randomly assigned.
Unless you want to do some ugly inter-process communication or packet sniffing, there's no way to have multiple programs bound to one port.
Even changing your code so that I can pass in an IP address I gets the same error message it appears that you can't bind to the same port and only one port can be used
here is the sample code I used your example and Altered it to capture my ip from my local machine..
IPAddress ipAddress = Dns.Resolve(Dns.GetHostName()).AddressList[0];
IPEndPoint ipLocalEndPoint = new IPEndPoint(ipAddress, 11000);
//IPEndPoint localpt = new IPEndPoint(ipLocalEndPoint);
UdpClient udpServer = new UdpClient(ipLocalEndPoint);
udpServer.Client.SetSocketOption(
SocketOptionLevel.Socket, SocketOptionName.ReuseAddress, true);
udpServer.Connect(ipLocalEndPoint);
UdpClient udpServer2 = new UdpClient();
udpServer2.Client.SetSocketOption(
SocketOptionLevel.Socket, SocketOptionName.ReuseAddress, true);
udpServer2.Client.Bind(ipLocalEndPoint); // <<---------- Exception here
this will produce the exception on the Bind () method.. sorry.
My advice: don't pass the port number into the UdpClient constructor. From the documentation, (somewhat sparse, I know...) it looks like if you do, the UdpClient will try to bind to that port (which, as sysrqb mentioned, is not allowed). (If you don't, I believe the UdpClient will listen on a random port for any replies. You could also pick a port you know to be unused.)
When you call Connect() you need to pass in the port number the server is listening on.
bind the two programs,ie, the sender and receiver to the same port on the localhost.dats the simple answer.

Categories

Resources