如何捕获 SocketException
How to catch a SocketException
我在构造以下 F# try..with
语句的 with
部分时遇到问题。那里有很多异常处理示例,但是当主机不存在时,我找不到任何特定匹配从 Dns.GetHostEntry
返回的 SocketException
的示例。我会继续寻找,但不胜感激。
let test_smtp (smtp_server_address : string) (port : int) =
let expectedResultCode = 220
let hostEntry : IPHostEntry =
try
Dns.GetHostEntry(smtp_server_address)
with
| :? System.Net.Sockets.SocketException -> printfn "GetHostEntry threw an exception "
let endPoint : IPEndPoint = new IPEndPoint (hostEntry.AddressList.[0], port)
( use tcpSocket = new Socket(endPoint.AddressFamily, SocketType.Stream, ProtocolType.Tcp)
tcpSocket.Connect(endPoint)
let temp_result = check_response tcpSocket expectedResultCode
temp_result
)
到目前为止,你所拥有的一切都很好;您只需要添加 as (name)
语法来为异常对象命名,然后添加 when (test)
语法来测试某个条件是否成立。例如:
try
Dns.GetHostEntry(smtp_server_address)
with
| :? System.Net.Sockets.SocketException as ex when ex.SocketErrorCode = SocketError.HostNotFound ->
failwith "Host not found"
(注意:我的原始代码针对 int 测试了 SocketErrorCode
,因为我误读了 MSDN 文档。但是 SocketErrorCode
is a System.Net.Sockets.SocketError
enum value。)
关于您的代码的一条评论:您不需要 use tcpSocket = ...
表达式周围的括号。您可以将其与代码的其余部分内联编写,当 tcpSocket
值在函数末尾超出范围时,F# 将处理该值:
let test_smtp (smtp_server_address : string) (port : int) =
let expectedResultCode = 220
let hostEntry : IPHostEntry =
try
Dns.GetHostEntry(smtp_server_address)
with
| :? System.Net.Sockets.SocketException as ex when ex.SocketErrorCode = SocketError.HostNotFound ->
failwith "GetHostEntry threw an exception "
let endPoint : IPEndPoint = new IPEndPoint (hostEntry.AddressList.[0], port)
use tcpSocket = new Socket(endPoint.AddressFamily, SocketType.Stream, ProtocolType.Tcp)
tcpSocket.Connect(endPoint)
check_response tcpSocket expectedResultCode
以下不是解决方案,而是解决方法。它解决了主机未找到错误的问题,而不必使用@rmunn 的回答中提到的 railway-oriented programming 。 (顺便说一下,这是一篇很棒的文章。)
所以如果Dns.GetHostEntry
抛出异常或者check_response
未能从HELO
得到正确的响应,那么false
可以返回。
module net_utilF_mod
open System
open System.Text
open System.Threading
open System.Net
open System.Net.Sockets
open System.IO
type Smtp1() =
member this.X = "F#"
let send_data (socket : Socket) (data : string) =
let dataArray : byte [] = Encoding.ASCII.GetBytes(data)
socket.Send(dataArray, 0, dataArray.Length, SocketFlags.None)
let check_response (socket:Socket) expectedResultCode =
while socket.Available = 0 do
System.Threading.Thread.Sleep 100
let responseArray : byte [] = Array.zeroCreate 1024
socket.Receive(responseArray, 0, socket.Available, SocketFlags.None) |> ignore
let responseData : string = Encoding.ASCII.GetString(responseArray)
let responseCode : int = Convert.ToInt32(responseData.Substring(0,3))
if responseCode = expectedResultCode then
true
else
false
let test_smtp (smtp_server_address : string) (port : int) =
let helo_msg = String.Format("HELO {0}\r\n", Dns.GetHostName())
let hostEntry : IPHostEntry =
try
Dns.GetHostEntry(smtp_server_address)
with
| :? System.Net.Sockets.SocketException as ex when ex.SocketErrorCode = SocketError.HostNotFound ->
let tempEntry : IPHostEntry = Dns.GetHostEntry(@"localhost")
tempEntry
let email_server_reachable =
match hostEntry.HostName with
| @"localhost" -> false
| _ -> true
if false = email_server_reachable then
false
else
let endPoint : IPEndPoint = new IPEndPoint (hostEntry.AddressList.[0], port)
( use tcpSocket = new Socket(endPoint.AddressFamily, SocketType.Stream, ProtocolType.Tcp)
tcpSocket.Connect(endPoint) |> ignore
let temp_response =
if true = check_response tcpSocket 220 then
send_data tcpSocket helo_msg |> ignore
check_response tcpSocket 250
else
false
temp_response
)
我在构造以下 F# try..with
语句的 with
部分时遇到问题。那里有很多异常处理示例,但是当主机不存在时,我找不到任何特定匹配从 Dns.GetHostEntry
返回的 SocketException
的示例。我会继续寻找,但不胜感激。
let test_smtp (smtp_server_address : string) (port : int) =
let expectedResultCode = 220
let hostEntry : IPHostEntry =
try
Dns.GetHostEntry(smtp_server_address)
with
| :? System.Net.Sockets.SocketException -> printfn "GetHostEntry threw an exception "
let endPoint : IPEndPoint = new IPEndPoint (hostEntry.AddressList.[0], port)
( use tcpSocket = new Socket(endPoint.AddressFamily, SocketType.Stream, ProtocolType.Tcp)
tcpSocket.Connect(endPoint)
let temp_result = check_response tcpSocket expectedResultCode
temp_result
)
到目前为止,你所拥有的一切都很好;您只需要添加 as (name)
语法来为异常对象命名,然后添加 when (test)
语法来测试某个条件是否成立。例如:
try
Dns.GetHostEntry(smtp_server_address)
with
| :? System.Net.Sockets.SocketException as ex when ex.SocketErrorCode = SocketError.HostNotFound ->
failwith "Host not found"
(注意:我的原始代码针对 int 测试了 SocketErrorCode
,因为我误读了 MSDN 文档。但是 SocketErrorCode
is a System.Net.Sockets.SocketError
enum value。)
关于您的代码的一条评论:您不需要 use tcpSocket = ...
表达式周围的括号。您可以将其与代码的其余部分内联编写,当 tcpSocket
值在函数末尾超出范围时,F# 将处理该值:
let test_smtp (smtp_server_address : string) (port : int) =
let expectedResultCode = 220
let hostEntry : IPHostEntry =
try
Dns.GetHostEntry(smtp_server_address)
with
| :? System.Net.Sockets.SocketException as ex when ex.SocketErrorCode = SocketError.HostNotFound ->
failwith "GetHostEntry threw an exception "
let endPoint : IPEndPoint = new IPEndPoint (hostEntry.AddressList.[0], port)
use tcpSocket = new Socket(endPoint.AddressFamily, SocketType.Stream, ProtocolType.Tcp)
tcpSocket.Connect(endPoint)
check_response tcpSocket expectedResultCode
以下不是解决方案,而是解决方法。它解决了主机未找到错误的问题,而不必使用@rmunn 的回答中提到的 railway-oriented programming 。 (顺便说一下,这是一篇很棒的文章。)
所以如果Dns.GetHostEntry
抛出异常或者check_response
未能从HELO
得到正确的响应,那么false
可以返回。
module net_utilF_mod
open System
open System.Text
open System.Threading
open System.Net
open System.Net.Sockets
open System.IO
type Smtp1() =
member this.X = "F#"
let send_data (socket : Socket) (data : string) =
let dataArray : byte [] = Encoding.ASCII.GetBytes(data)
socket.Send(dataArray, 0, dataArray.Length, SocketFlags.None)
let check_response (socket:Socket) expectedResultCode =
while socket.Available = 0 do
System.Threading.Thread.Sleep 100
let responseArray : byte [] = Array.zeroCreate 1024
socket.Receive(responseArray, 0, socket.Available, SocketFlags.None) |> ignore
let responseData : string = Encoding.ASCII.GetString(responseArray)
let responseCode : int = Convert.ToInt32(responseData.Substring(0,3))
if responseCode = expectedResultCode then
true
else
false
let test_smtp (smtp_server_address : string) (port : int) =
let helo_msg = String.Format("HELO {0}\r\n", Dns.GetHostName())
let hostEntry : IPHostEntry =
try
Dns.GetHostEntry(smtp_server_address)
with
| :? System.Net.Sockets.SocketException as ex when ex.SocketErrorCode = SocketError.HostNotFound ->
let tempEntry : IPHostEntry = Dns.GetHostEntry(@"localhost")
tempEntry
let email_server_reachable =
match hostEntry.HostName with
| @"localhost" -> false
| _ -> true
if false = email_server_reachable then
false
else
let endPoint : IPEndPoint = new IPEndPoint (hostEntry.AddressList.[0], port)
( use tcpSocket = new Socket(endPoint.AddressFamily, SocketType.Stream, ProtocolType.Tcp)
tcpSocket.Connect(endPoint) |> ignore
let temp_response =
if true = check_response tcpSocket 220 then
send_data tcpSocket helo_msg |> ignore
check_response tcpSocket 250
else
false
temp_response
)