I have a problem with configuration and starting WCF service.
In my application there is a method that starts service. Something like this
void Start(string protocol, string address, string port)
{
host = new ServiceHost(_myService,
new Uri(String.Format("{0}://{1}{2}/Sample", protocol, address, port)));
//...Some configuration (bindings, behaviors, etc.)
host.Open();
}
Let my computer has an IP 192.168.0.1. When I pass 'address' parameter with a value '192.168.0.2' an error occurred
"A TCP error (10049: The requested address is not valid in its context.)
occurred while listening on IP Endpoint=192.168.0.2:1234"
That's right because it's not my IP. But after that if I pass correct value (my real IP) I get the same error about IP 192.168.0.2! So I can't reconfigure and restart server without restarting application.
Why does it happen? How can I avoid such behavior?
Looks like WCF caches a socket object in class ExclusiveTCPTransportManager.
It's seems to be good solution for me:
public static class WCFBugWorkaround
{
public static bool IsConnectionPossible(this ServiceHost host)
{
try
{
foreach (var baseAddress in host.BaseAddresses)
{
IPAddress[] ipAddresses = Dns.GetHostAddresses(baseAddress.DnsSafeHost);
IPAddress ipAddr = ipAddresses.Where(e => e.AddressFamily == AddressFamily.InterNetwork).FirstOrDefault();
if (ipAddr == null)
{
return false;
}
using (Socket s = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp))
{
System.Net.IPEndPoint localEP = new IPEndPoint(ipAddr, baseAddress.Port);
s.Bind(localEP);
}
}
}
catch (Exception ex)
{
return false;
}
return true;
}
}
ServiceHost host = ...;
...
if (host.IsConnectionPossible())
{
host.Open();
}
Thank's to Francheska for showing me the right direction :)
I can't see from your question how you are adding the correct endpoint, but I suspect you are attempting to modify the endpoint address. With WCF services, you cannot make changes to the endpoint address after calling
host.Open();
because at this point the service is (if you have no errors) up and accepting requests from clients at the specified address and port number.
You need to create a new ServiceHost object with the correct endpoint address (and dispose of the old one) if you wish to host the service at a new address.
EDIT:
After playing around with the example solution you have posted, I have found a solution to the issue. I think something is going wrong because you are using the same port number for both tries (in the example solution I downloaded you don't specify this, so the port defaulted to 808). The error you are experiencing vanishes if you change your code as follows to specify a different port number in the base address for the 2nd try:
try
{
var host2 = CreateServiceHost("localhost:5432", serviceImpl);
Console.WriteLine("#2, config: " + host2.BaseAddresses.First().ToString());
host2.Open();
}
catch (Exception ex)
{
Console.WriteLine(ex.Message);
}
There seems to be something buggy underneath WCF itself, probably on a socket level, where the port is somehow still unavailable after the first error with the incorrect IP.
I did a quick google and found this article where someone experienced a delay in reusing a port after closing a socket. If you always need to use the same port number, perhaps you could wait a certain amount of time for the port to become free again before trying to create the service host again.
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
So I'm trying to connect to another PC via TCP protocol using sockets, 192.168.1.72 is another PC's address, however, I'm not relly sure im going the right road. I have server also oon different computer, and theese two programs seem to work well on same computer, when in line with _clientSocket.Connect();, i use IPAdress.Loopback instead o host. Am I doint the right aproach, or should i look elsewhere, and if i am, how can i make this function work, because now it simply crashes and indicates there is something wrong with host declaration
private static void LoopConnect()
{
IPAddress host = new IPAddress(Encoding.ASCII.GetBytes("192.168.1.72"));
int attempts = 0;
while(!_clientSocket.Connected)
{
try
{
attempts++;
_clientSocket.Connect(host, 100);
}
catch (SocketException)
{
Console.Clear();
Console.WriteLine("Connection attempts: " + attempts.ToString());
}
}
Console.Clear();
Console.WriteLine("Connected");
}
If you supply the IP adddress as a string, you need to use the static Parse method:
IPAddress host = IPAddress.Parse("192.168.1.72");
Im trying to follow this code sample from microsoft, who is a basic code for sending/receiving data over network from windows 10 computer/phone.
Im on VS2015, i have a phone on W10 and my computer also.
The problem is that my application seems to create packet and send one to establish the connection (i have seen this packet with wireshark), but i never received it on the server side.
Here is code to listen port from the actual internet connection available and wait for a connection :
public static async void StartServer()
{
try
{
StreamSocketListener listener = new StreamSocketListener();
//ConnectionProfile internetConnectionProfile = NetworkInformation.GetInternetConnectionProfile();
//await listener.BindServiceNameAsync("5043", SocketProtectionLevel.PlainSocket, internetConnectionProfile.NetworkAdapter);
listener.ConnectionReceived += OnConnection;
await listener.BindServiceNameAsync("5043");
Debug.WriteLine("Server Started !");
}
catch (Exception)
{
Debug.WriteLine("Error StartServer Method !");
}
}
The method "OnConnection" is never reach cause the event "ConnectionReceived" is never called.
Here is the code to establish connection (the string ipDestination contain the internet ip address from my phone for example, that i get from checkip.dyndns.org) :
private static StreamSocket socket;
public static async void Connect(string ipDestination)
{
try
{
//Destination Ip address
HostName host = new HostName(ipDestination);
ConnectionProfile internetConnectionProfile = NetworkInformation.GetInternetConnectionProfile();
socket = new StreamSocket();
socket.Control.KeepAlive = true;
await socket.ConnectAsync(host, "5043");
//EXCEPTION RAISE HERE after a moment "System.Runtime.InteropServices.COMException, cant join destination.
Debug.WriteLine("Connected !");
}
catch (Exception)
{
Debug.WriteLine("Erreur Connect Method !");
}
}
I think i should miss something but i dont know why and im block at this part since a long and can't continue my project...
I apologize for the bad english I try to make my best :)
Update from comments :
As Jay Zuo suggested, i have try to use local address on private
network and it works, i can establish connection, send and receive
data without problems... So the problem come when i use internet IP
address, and i still can't figure why...
As Kiewic suggested, i have simplify my code and commented the
precedent version.
I can't seem to find anything that tells me if a port in my router is open or not.
Is this even possible?
The code I have right now doesn't really seem to work...
private void ScanPort()
{
string hostname = "localhost";
int portno = 9081;
IPAddress ipa = (IPAddress) Dns.GetHostAddresses(hostname)[0];
try
{
System.Net.Sockets.Socket sock =
new System.Net.Sockets.Socket(System.Net.Sockets.AddressFamily.InterNetwork,
System.Net.Sockets.SocketType.Stream,
System.Net.Sockets.ProtocolType.Tcp);
sock.Connect(ipa, portno);
if (sock.Connected == true) // Port is in use and connection is successful
MessageBox.Show("Port is Closed");
sock.Close();
}
catch (System.Net.Sockets.SocketException ex)
{
if (ex.ErrorCode == 10061) // Port is unused and could not establish connection
MessageBox.Show("Port is Open!");
else
MessageBox.Show(ex.Message);
}
}
Try this:
using(TcpClient tcpClient = new TcpClient())
{
try {
tcpClient.Connect("127.0.0.1", 9081);
Console.WriteLine("Port open");
} catch (Exception) {
Console.WriteLine("Port closed");
}
}
You should probably change 127.0.0.1 to something like 192.168.0.1 or whatever your router's IP address is.
A better solution where you can even specify a timeout:
using System;
using System.Net.Sockets;
// ...
bool IsPortOpen(string host, int port, TimeSpan timeout)
{
try
{
using(var client = new TcpClient())
{
var result = client.BeginConnect(host, port, null, null);
var success = result.AsyncWaitHandle.WaitOne(timeout);
client.EndConnect(result);
return success;
}
}
catch
{
return false;
}
}
And, in F#:
open System
open System.Net.Sockets
let isPortOpen (host: string) (port: int) (timeout: TimeSpan): bool =
try
use client = new TcpClient()
let result = client.BeginConnect(host, port, null, null)
let success = result.AsyncWaitHandle.WaitOne timeout
client.EndConnect result
success
with
| _ -> false
let available = isPortOpen "stackoverflow.com" 80 (TimeSpan.FromSeconds 10.)
printf "Is stackoverflow available? %b" available
There is no way to know if the port is forwarded in your router, except if there is a program listening on that port.
As you may see in the Clinton answer, the .Net class being used is TcpClient and that is because you are using a TCP socket to connect to. That is the way operating systems make connections: using a socket. However, a router just forwards the packets (layer 3 of the OSI Model) in or out. In your case, what your router is doing is called: NAT. It is one public IP shared by a one or more private IPs. That´s why you are making a port forwarding.
There may be a lot of routers in the path of the packets, and you will never know what had happened.
Let´s imagine you are sending a letter in the traditional way. Perhaps you can write in the letter that the receiver must answer, in order to check he/she is there (you and the receiver are the sockets). If you receive an answer you will be sure he/she is there, but if you don´t receive anything you don´t know if the mailman (in your case the router) forgot to deliver the letter, or the receiver hadn´t answered. You would also never know if the mailman has asked a friend to deliver that letter. Moreover, the mailman won´t open the letter in order to know he/she may answer because you are waiting for a reply. All you may do is wait some time to receive the answer. If you don´t receive anything in that period you will assume that the receiver isn´t where you sent the letter. That is a "timeout".
I saw an answer mentioning the nmap software. It´s really a very good and complex soft, but I think it will work in the same way. If there is no app listening in that port, there is no way to know if it is open or not.
Please, let me know if I was clear.
If you're connecting to the loopback adapter — localhost or 127.0.0.1 (there's no place like 127.0.0.1!), you're unlikely to ever go out to the router. The OS is smart enough to recognize that it's a special address. Dunno if that holds true as well if you actually specify your machine's "real" IP address.
See also this question: What is the purpose of the Microsoft Loopback Adapter?
Also note that running traceroute localhost (tracert localhost in Windows) shows that the only network node involved is your own machine. The router is never involved.
Other than BeginConnect you can also use ConnectAsync (added in .NET Framework 4.5 I think?).
TcpClient client = null;
try {
client = new TcpClient();
var task = client.ConnectAsync(host, port);
if (task.Wait(timeout)) {//if fails within timeout, task.Wait still returns true.
if (client.Connected) {
// port reachable
}
else
// connection refused probably
}
else
// timed out
}
catch (Exception ex) {
// connection failed
}
finally {
client.Close();
}
Full project is here because paping refuses to run and I couldn't find another "ping host:port" tool to my likes.
A port forward on the router cannot be tested from inside the LAN, you need to connect from the WAN (internet) side to see if a port forward is working or not.
Several internet sites offer services to check if a port is open:
What's My IP Port Scanner
GRC | ShieldsUP!
If you want to check with your own code, then you need to make sure the TCP/IP connection is rerouted via an external proxy or setup a tunnel. This has nothing to do with your code, it's basic networking 101.
public static bool PortInUse(int port)
{
bool inUse = false;
IPGlobalProperties ipProperties = IPGlobalProperties.GetIPGlobalProperties();
IPEndPoint [] ipEndPoints = ipProperties.GetActiveTcpListeners();
foreach(IPEndPoint endPoint in ipEndPoints)
{
if(endPoint.Port == port)
{
inUse = true;
break;
}
}
return inUse;
}
For me, I needed something blocking until the connection to the port is available or after a certain amount of retries. So, I figured out this code:
public bool IsPortOpen(string host, int port, int timeout, int retry)
{
var retryCount = 0;
while (retryCount < retry)
{
if (retryCount > 0)
Thread.Sleep(timeout);
try
{
using (var client = new TcpClient())
{
var result = client.BeginConnect(host, port, null, null);
var success = result.AsyncWaitHandle.WaitOne(timeout);
if (success)
return true;
client.EndConnect(result);
}
}
catch
{
// ignored
}
finally { retryCount++; }
}
return false;
}
Hope this helps!
also you can use ConnectAsync like
public async Task<bool> IsIPAndPortOpen(string hostOrIPAddress, int port, TimeSpan timeOut)
{
try
{
using (var client = new TcpClient())
{
var ct = new CancellationTokenSource(timeOut).Token;
await client.ConnectAsync(hostOrIPAddress, port, ct);
return true;
}
}
catch
{
return false;
}
}
public string GetAvailablePort()
{int startingPort=1000;
string portnumberinformation = string.Empty;
IPEndPoint[] endPoints;
List<int> portArray = new List<int>();
IPGlobalPr`enter code here`operties properties = IPGlobalProperties.GetIPGlobalProperties();`enter code here`
//getting active tcp listners
endPoints = properties.GetActiveTcpListeners();
portArray.AddRange(from n in endPoints
where n.Port >= startingPort
select n.Port);
portArray.Sort();
for (int i = 0; i < portArray.Count; i++)
{
if (check condition)
{
do somting
}
}
return portnumberinformation;
}
If it is Router the simplest way to check it through online services like
Port Checker
Port Forwarding Test
You can also try using telenet to chek wether port is accessible or not
telenet [ip-address] [port]
The exception is Remoting Exception - Authentication Failure. The detailed message says "Unable to read data from the transport connection: the connection was closed."
I'm having trouble with creating two simple servers that can comunicate as remote objects in C#. ServerInfo is just a class I created that holds the IP and Port and can give back the address. It works fine, as I used it before, and I've debugged it. Also the server is starting just fine, no exception is thrown, and the channel is registered without problems. I'm using Forms to do the interfaces, and call some of the methods on the server, but didn't find any problems in passing the parameters from the FormsApplication to the server when debugging. All seems fine in that chapter.
public ChordServerProgram()
{
RemotingServices.Marshal(this, "PADIBook");
nodeInt = 0;
}
public void startServer()
{
try
{
serverChannel = new TcpChannel(serverInfo.Port);
ChannelServices.RegisterChannel(serverChannel, true);
}
catch (Exception e)
{
Console.WriteLine(e.ToString());
}
}
I run two instances of this program. Then startNode is called on one of the instances of the application. The port is fine, the address generated is fine as well. As you can see, I'm using the IP for localhost, since this server is just for testing purposes.
public void startNode(String portStr)
{
IPAddress address = IPAddress.Parse("127.0.0.1");
Int32 port = Int32.Parse(portStr);
serverInfo = new ServerInfo(address, port);
startServer();
//node = new ChordNode(serverInfo,this);
}
Then, in the other istance, through the interface again, I call another startNode method, giving it a seed server to get information from. This is where it goes wrong. When it calls the method on the seedServer proxy it just got, a RemotingException is thrown, due to an authentication failure. (The parameter I'll want to get is the node, I'm just using the int to make sure the ChordNode class has nothing to do with this error.)
public void startNode(String portStr, String seedStr)
{
IPAddress address = IPAddress.Parse("127.0.0.1");
Int32 port = Int32.Parse(portStr);
serverInfo = new ServerInfo(address, port);
IPAddress addressSeed = IPAddress.Parse("127.0.0.1");
Int32 portSeed = Int32.Parse(seedStr);
ServerInfo seedInfo = new ServerInfo(addressSeed, portSeed);
startServer();
ChordServerProgram seedServer = (ChordServerProgram)Activator.GetObject(typeof(ChordServerProgram), seedInfo.GetFullAddress());
// node = new ChordNode(serverInfo,this);
int seedNode = seedServer.nodeInt;
// node.chordJoin(seedNode.self);
}
Try setting the ensureSecurity to false, and it should start working.
ChannelServices.RegisterChannel(serverChannel, false);
You've specified that security is a must on your Remoting server in startServer() with:
ChannelServices.RegisterChannel(serverChannel, true);
Yet the 'client' end does not specify security, hence the authorisation error. You need to specify tcp channel security on both ends unless the server security setting is set to 'false'. In your second startNode method you need to do the following before using Activator.GetObject, note no port specified on the TcpChannel unlike the server end:
TcpChannel ClientChan = new TcpChannel();
ChannelServices.RegisterChannel(ClientChan, true);
Furthermore, unless you're doing it in some code you haven't given us, you also do not seem to have registered a well known service type server side, although you say it's been working in the debugger so maybe that's not necessary in the case. See MSDN on RegisterWellKnownServiceType.