2

I did a simple translation of the example C# code here:

let socket_CreateBindListen (sv_ : string) (pt_ : int) : Socket option =
    let (he : IPHostEntry) = Dns.GetHostEntry(sv_)
    let rsock, ipe =
        he.AddressList
        |> Seq.map (fun s ->
            let (ipe2 : IPEndPoint) = new IPEndPoint (s, pt_)
            let (rsock2 : Socket) = new Socket (ipe2.AddressFamily, SocketType.Stream, ProtocolType.Tcp)
            rsock2.Connect ipe2 ///// <---- No connection could be made because the target machine actively refused it
            rsock2, ipe2)
        |> Seq.find (fun (s, t) -> s.Connected)
    try
        rsock.Bind ipe
        rsock.Listen 10
        printfn "%s now listening on port %d" sv_ pt_
        Some (rsock)
    with
        | _ ->
            printfn "Failed to connect to %s on port %d" sv_ pt_
            None

socket_CreateBindListen "127.0.0.1" 50000

I made sure to first open port 50000 on my machine for TCP for both inbound and outbound connections. (I even tried disabling the firewall completely.) Nothing seems to be working. I keep getting the error message:

No connection could be made because the target machine actively refused it.

I am using Windows 8. I would really appreciate some pointers on what else I might try.

Thanks in advance for your time.


EDIT

I hope I am not violating any of StackOverflow's posting policies by blogging about my progress here.

I have updated the code to the following:

let socket_CreateBindListen (sv_ : string) (pt_ : int) : Socket option =
    let (he : IPHostEntry) = Dns.GetHostEntry(sv_)
    let rsock, ipe =
        he.AddressList
        |> Seq.map (fun s ->
            let (ipe2 : IPEndPoint) = new IPEndPoint (s, pt_)
            let (rsock2 : Socket) = new Socket (ipe2.AddressFamily, SocketType.Stream, ProtocolType.Tcp)
            try
                rsock2.Connect ipe2
                rsock2, ipe2
            with
                | _ ->
                    null, null)
        |> Seq.find (fun (s, t) -> (s <> null) && (s.Connected))
    try
        rsock.Bind ipe
        rsock.Listen sbl
        printfn "%s now listening on port %d" sv_ pt_
        Some (rsock)
    with
        | _ ->
            printfn "Failed to connect to %s on port %d" sv_ pt_
            None

Now I am getting the following error:

KeyNotFoundException was unhandled
An unhandled exception of type 'System.Collections.Generic.KeyNotFoundException' occurred in FSharp.Core.dll

I have looked extensively on Google and Bing, without any luck.


EDIT 2

As requested by Jack P., here is the output from netstat -a, as well as what happens when the binary is executed:

PS C:\Users\shredderroy> netstat -a

Active Connections

  Proto  Local Address          Foreign Address        State
  TCP    0.0.0.0:80             SPEEDMACHINE:0         LISTENING
  TCP    0.0.0.0:135            SPEEDMACHINE:0         LISTENING
  TCP    0.0.0.0:445            SPEEDMACHINE:0         LISTENING
  TCP    0.0.0.0:2179           SPEEDMACHINE:0         LISTENING
  TCP    0.0.0.0:49152          SPEEDMACHINE:0         LISTENING
  TCP    0.0.0.0:49153          SPEEDMACHINE:0         LISTENING
  TCP    0.0.0.0:49154          SPEEDMACHINE:0         LISTENING
  TCP    0.0.0.0:49155          SPEEDMACHINE:0         LISTENING
  TCP    0.0.0.0:49156          SPEEDMACHINE:0         LISTENING
  TCP    192.168.0.139:139      SPEEDMACHINE:0         LISTENING
  TCP    192.168.0.139:49159    bn1wns2011708:https    ESTABLISHED
  TCP    192.168.0.139:49167    vc-in-f108:imaps       ESTABLISHED
  TCP    192.168.0.139:49171    vc-in-f108:imaps       ESTABLISHED
  TCP    192.168.0.139:49239    a23-67-250-112:http    CLOSE_WAIT
  TCP    [::]:80                SPEEDMACHINE:0         LISTENING
  TCP    [::]:135               SPEEDMACHINE:0         LISTENING
  TCP    [::]:445               SPEEDMACHINE:0         LISTENING
  TCP    [::]:2179              SPEEDMACHINE:0         LISTENING
  TCP    [::]:49152             SPEEDMACHINE:0         LISTENING
  TCP    [::]:49153             SPEEDMACHINE:0         LISTENING
  TCP    [::]:49154             SPEEDMACHINE:0         LISTENING
  TCP    [::]:49155             SPEEDMACHINE:0         LISTENING
  TCP    [::]:49156             SPEEDMACHINE:0         LISTENING
  UDP    0.0.0.0:500            *:*
  UDP    0.0.0.0:4500           *:*
  UDP    0.0.0.0:5355           *:*
  UDP    127.0.0.1:53194        *:*
  UDP    127.0.0.1:60316        *:*
  UDP    127.0.0.1:61644        *:*
  UDP    192.168.0.139:137      *:*
  UDP    192.168.0.139:138      *:*
  UDP    [::]:500               *:*
  UDP    [::]:4500              *:*
  UDP    [::]:5355              *:*
  UDP    [fe80::b193:4f6:d053:6324%20]:546  *:*
PS C:\Users\shredderroy> cd "C:\Users\shredderroy\Documents\Visual Studio 2012\Projects\FSharp\SocketTests_Server\SocketTests_Server\bin\Debug
"
PS C:\Users\shredderroy\Documents\Visual Studio 2012\Projects\FSharp\SocketTests_Server\SocketTests_Server\bin\Debug> .\SocketTests_Server.exe
Unhandled Exception: System.Net.Sockets.SocketException: No connection could be made because the target machine actively refused it [::1]:50000
   at System.Net.Sockets.Socket.DoConnect(EndPoint endPointSnapshot, SocketAddress socketAddress)
   at System.Net.Sockets.Socket.Connect(EndPoint remoteEP)
   at SocketTests_Server.TestModule_1.heo@22.Invoke(IPAddress s) in C:\Users\shredderroy\Documents\Visual Studio 2012\Projects\FSharp\SocketTests_Server\SocketTests_Server\TestModule_1.fs:line 25 at Microsoft.FSharp.Collections.SeqModule.TryFind[T](FSharpFunc`2 predicate, IEnumerable`1 source)
   at SocketTests_Server.TestModule_1.socket_CreateBindListen_1(String sv_, Int32 pt_) in C:\Users\shredderroy\Documents\Visual Studio
2012\Projects\FSharp\SocketTests_Server\SocketTests_Server\TestModule_1.fs:line 20
   at SocketTests_Server.Program.Main(String[] args) in C:\Users\shredderroy\Documents\Visual Studio 2012\Projects\FSharp\SocketTests_Server\SocketTests_Server\Program.fs:line 9
PS C:\Users\shredderroy\Documents\Visual Studio 2012\Projects\FSharp\SocketTests_Server\SocketTests_Server\bin\Debug>

I am going to keep trying. So far I have added my programme, SocketTests_Server.exe, to the list of allowed programmes in Windows Firewall, opened the relevant port for inbound and outbound connections, disabled the firewall completely--all to no avail.

Shredderroy
  • 2,860
  • 2
  • 29
  • 53
  • I suspect you're getting the `KeyNotFoundException` because the `Seq.find` is not able to find any matching elements in the sequence. If you use the code I posted -- which uses `Seq.tryPick` to handle that situation -- if the program can't connect, at least it won't crash. – Jack P. Feb 04 '13 at 04:12
  • BTW -- Can you open a command prompt and run `netstat -an` and post the output? It can be useful in diagnosing connection issues like this. – Jack P. Feb 04 '13 at 04:15
  • I have posted the information in Edit 2. Thanks so much for your time. – Shredderroy Feb 04 '13 at 10:46

3 Answers3

6

I think what is happening is that you are connecting twice, one of the addresses connects fine. Your code then keeps looking through the remaining addresses and tries to connect again.

Your code is lacking the equivalent of break in the C# code.

Some possible solutions:

  1. use a while loop instead of Seq.map
  2. Use a reference variable inside the map
  3. Compress all the code into Seq.find and remove the call to map (probably the most elegant)
John Palmer
  • 25,356
  • 3
  • 48
  • 67
  • I have the very strong suspicion that somehow or other, you are absolutely correct about the cause of the error. However, when I put a breakpoint at the return line `rsock2, ipe2` I get the error even before the programme hits the breakpoint. – Shredderroy Feb 04 '13 at 01:53
  • 3
    @Shredderroy Breakpoints can be a bit funny with F# lambdas sometimes - try putting a `printfn` – John Palmer Feb 04 '13 at 03:54
5

I translated the code from the page you linked -- it compiles, though I haven't tried running it.

open System
open System.Text
open System.Net
open System.Net.Sockets

let connectSocket (server : string, port : int) : Socket option =
    // Get host related information.
    let hostEntry = Dns.GetHostEntry server

    // Loop through the AddressList to obtain the supported AddressFamily. This is to avoid 
    // an exception that occurs when the host IP Address is not compatible with the address family 
    // (typical in the IPv6 case). 
    hostEntry.AddressList
    |> Seq.tryPick (fun address ->
        let ipe2 = IPEndPoint (address, port)
        let rsock2 = new Socket (ipe2.AddressFamily, SocketType.Stream, ProtocolType.Tcp)
        rsock2.Connect ipe2
        if rsock2.Connected then
            Some rsock2
        else None)

// This method requests the home page content for the specified server. 
let socketSendReceive (server : string, port : int) : string =
    let request =
        sprintf "GET / HTTP/1.1\r\nHost: %s\r\nConnection: Close\r\n\r\n" server
    let bytesSent =
        Encoding.ASCII.GetBytes request
    let bytesReceived = Array.zeroCreate 256

    // Create a socket connection with the specified server and port.
    match connectSocket (server, port) with
    | None ->
        "Connection failed"
    | Some s ->
        // Send request to the server.
        s.Send (bytesSent, Array.length bytesSent, SocketFlags.None)
        |> ignore

        // Receive the server home page content. 
        let mutable bytes = 0
        let mutable page =
            sprintf "Default HTML page on %s:\r\n" server

        // The following will block until the page is transmitted. 
        while bytes > 0 do
            bytes <- s.Receive (bytesReceived, Array.length bytesReceived, SocketFlags.None)
            page <- page + Encoding.ASCII.GetString (bytesReceived, 0, bytes)

        page

//
let main args =
    let port = 80

    let host =
        if Array.isEmpty args then
            // If no server name is passed as argument to this program,  
            // use the current host name as the default.
            Dns.GetHostName ()
        else
            args.[0]

    socketSendReceive (host, port)
    |> Console.WriteLine

EDIT: I did a little digging, and "actively refused" is the key to that error message, according to: No connection could be made because the target machine actively refused it. In short, double-check that the server you're trying to connect to is set up properly; when the connection is actively refused, there's no firewall problem -- the server is actually rejecting your connection.

If you're absolutely certain the server is set up correctly, there's one last thing you could try. According to Socket Connection Is Actively Refused (MSDN Forums), you may need to use the IPAddress.NetworkToHostOrder Method to set the port value correctly for the IPEndPoint. In that case, just add this as the first line in my connectSocket function (above):

let port = IPAddress.NetworkToHostOrder port

EDIT 2: Looking at the netstat information you posted -- there's no server LISTENING on port 50000. If you're sure the server software is set up correctly, make sure it's using the port you want (and not just choosing a random port).

Community
  • 1
  • 1
Jack P.
  • 11,487
  • 1
  • 29
  • 34
  • P, thanks so much for taking the trouble. My problem is that I am unable to bind and listen on a specific port (50000, in my example). – Shredderroy Feb 04 '13 at 01:55
  • @Shredderroy I just edited my answer to add more information about actively refused connections -- hopefully it'll help you solve your problem. – Jack P. Feb 04 '13 at 12:53
0

First, I would like to thank everyone, in particular, @Jack P. and @John Palmer, for reading my code and offering very good and instructive suggestions. Your guidance is greatly appreciated.


I have circumvented the problem described above by using the TcpListener and TcpClient classes instead. So I thought I would write the simple F# translations of this server function and this client function, which together implement the server and client. Hopefully, this sample code will save other beginners some time.


Server

let connectAndListen () : unit =
    let (laddr : IPAddress) = IPAddress.Parse ("127.0.0.1")
    let lpt = 32000
    let (svr : TcpListener) = new TcpListener (laddr, lpt)
    try
        svr.Start ()
        let (bta : byte[]) = Array.create 256 (byte (0))
        while true do
            printfn "Waiting for a connection..."
            let (cl : TcpClient) = svr.AcceptTcpClient ()
            printfn "Connected"
            let (ns : NetworkStream) = cl.GetStream ()
            let mutable (i : int) = ns.Read (bta, 0, (Array.length bta))
            while i <> 0 do
                let (dat : string) = System.Text.Encoding.ASCII.GetString (bta, 0, i)
                printfn "Received:  %s" dat
                let (msg : byte[]) = System.Text.Encoding.ASCII.GetBytes (dat.ToUpper ())
                ns.Write (msg, 0, (Array.length msg))
                printfn "Sent:  %s" (dat.ToUpper ())
                i <- ns.Read (bta, 0, (Array.length bta))
            cl.Close ()
    with
    | excp ->
        printfn "%s" excp.Message
    svr.Stop ()

Client

let connect (sv_ : string) (pt_ : int) (msg_ : string) : unit =
    try
        let cl = new TcpClient (sv_, pt_)
        let (dat : byte[]) = System.Text.Encoding.ASCII.GetBytes msg_
        let (st : NetworkStream) = cl.GetStream ()
        st.Write (dat, 0, (Array.length dat))
        printfn "Sent:  %s" msg_
        let (rdat : byte[]) = Array.create 256 (byte (0))
        let (i : int) = st.Read (rdat, 0, (Array.length rdat))
        let (rsp : string) = System.Text.Encoding.ASCII.GetString (rdat, 0, i)
        printfn "Received:  %s" rsp
        st.Close ()
        st.Dispose ()
    with
    | :? ArgumentNullException as excp ->
        printfn "ArgumentNullException encountered:  %s" excp.Message
    | :? SocketException as excp ->
        printfn "SocketException encountered:  %s" excp.Message
    printfn "Press ENTER to continue"
    Console.ReadLine () |> ignore

Place the code in separate projects, compile and run them. They work on my machine.

Shredderroy
  • 2,860
  • 2
  • 29
  • 53