2

我在这里对示例 C# 代码进行了简单的翻译:

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

我确保首先在我的机器上为入站和出站连接打开 TCP 端口 50000。(我什至尝试完全禁用防火墙。)似乎没有任何效果。我不断收到错误消息:

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

我正在使用 Windows 8。我非常感谢一些关于我可能会尝试的其他指示。

在此先感谢您的时间。


编辑

我希望我不会因为在这里写博客而违反 StackOverflow 的任何发布政策。

我已将代码更新为以下内容:

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

现在我收到以下错误:

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

我在 Google 和 Bing 上进行了广泛的研究,但没有任何运气。


编辑 2

根据 的要求Jack P.,以下是 的输出netstat -a,以及执行二进制文件时发生的情况:

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>

我会继续努力。到目前为止,我已将我的程序 , 添加SocketTests_Server.exe到 Windows 防火墙中允许的程序列表中,打开了入站和出站连接的相关端口,完全禁用了防火墙 - 一切都无济于事。

4

3 回答 3

6

我认为正在发生的事情是您连接了两次,其中一个地址连接正常。然后,您的代码会继续查看剩余的地址并尝试再次连接。

您的代码缺少breakC# 代码中的等效项。

一些可能的解决方案:

  1. 使用 while 循环代替Seq.map
  2. 在内部使用引用变量map
  3. 将所有代码压缩到Seq.find并删除对 map 的调用(可能是最优雅的)
于 2013-02-04T00:48:53.557 回答
5

我从你链接的页面翻译了代码——它编译,虽然我没有尝试运行它。

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

编辑:我做了一点挖掘,“主动拒绝”是该错误消息的关键,根据:无法建立连接,因为目标机器主动拒绝它。简而言之,请仔细检查您尝试连接的服务器是否设置正确;当连接被主动拒绝时,没有防火墙问题——服务器实际上拒绝了您的连接。

如果您绝对确定服务器设置正确,那么您可以尝试最后一件事。根据Socket Connection Is Actively Refused (MSDN Forums),您可能需要使用IPAddress.NetworkToHostOrder 方法为 IPEndPoint 正确设置端口值。在这种情况下,只需将其添加为我的connectSocket函数(上图)的第一行:

let port = IPAddress.NetworkToHostOrder port

编辑 2:查看netstat您发布的信息 - 端口 50000 上没有服务器LISTENING。如果您确定服务器软件设置正确,请确保它使用您想要的端口(而不仅仅是选择随机端口)。

于 2013-02-04T01:27:35.297 回答
0

首先,我要感谢大家,特别是 @Jack P. 和 @John Palmer,他们阅读了我的代码并提供了非常好的和有启发性的建议。非常感谢您的指导。


TcpListener我已经通过使用andTcpClient类来规避上述问题。所以我想我会写这个服务器函数这个客户端函数的简单F#翻译,它们一起实现服务器和客户端。希望这个示例代码可以为其他初学者节省一些时间。


服务器

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 ()

客户

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

将代码放在单独的项目中,编译并运行它们。他们在我的机器上工作。

于 2013-02-07T01:08:28.807 回答