Building a TCP Port Scanner in F#

Search for a command to run...

No comments yet. Be the first to comment.
Modern software systems often separate control logic from high-performance execution logic. This design is common in networking, distributed systems, operating systems, storage engines, and embedded s

Introduction Engineering software often combines multiple programming languages to leverage their individual strengths. A common approach is to implement computational algorithms in native C or C++ wh

Deadlocks are one of the most common synchronization problems encountered in operating systems and concurrent programming. Although the concept is frequently introduced in textbooks, observing it insi

Memory and resource allocation are fundamental operations inside the Linux kernel. Whether assigning device IDs, managing CPU masks, allocating interrupt vectors, or tracking hardware resources, the k

The Linux scheduler is one of the most important components of the operating system. Every running program, background service, and kernel thread eventually interacts with the scheduler. In this artic

One of the best ways to understand TCP networking is by building a simple port scanner.
A port scanner attempts to connect to remote TCP ports and determines whether they are available. While the implementation may be small, it exposes several important networking concepts:
This article explores how a simple F# program can test TCP port availability and introduces the exception-handling syntax commonly used in networking applications.
A TCP port is a logical communication endpoint.
Servers listen on ports waiting for incoming connections.
Examples:
| Service | Port |
|---|---|
| HTTP | 80 |
| HTTPS | 443 |
| SSH | 22 |
| SMTP | 25 |
| FTP | 21 |
When a client wants to communicate with a service, it attempts to establish a TCP connection to the target port.
Port scanning is the process of testing one or more ports to determine whether they are accepting connections.
A scanner typically reports:
| State | Meaning |
|---|---|
| Open | Service accepts connections |
| Closed | Service rejects connections |
| Filtered | Firewall blocks traffic |
| Unreachable | Host cannot be reached |
Port scanners are widely used in:
Before data can be exchanged, TCP establishes a connection between client and server.
The client sends a connection request.
The server responds.
Once both sides agree, communication begins.
If the connection succeeds, the port is considered open.
If the connection fails, the scanner can infer that the service is unavailable or inaccessible.
The .NET networking library provides the TcpClient class.
A connection can be created using:
use client =
new TcpClient("scanme.nmap.org", 80)
This statement attempts to connect to:
scanme.nmap.org80If the connection succeeds, the object is created successfully.
The entire scanner can fit into a few lines of code.
try
use client =
new TcpClient("scanme.nmap.org", 80)
printfn "Connection successful"
with
| :? SocketException ->
printfn "Connection failed"
The scanner attempts a TCP connection.
Success indicates an open port.
Failure generates a networking exception.
Networks are unpredictable.
Many things can go wrong:
Instead of crashing, the application should handle these failures gracefully.
That is where exception handling becomes important.
The try keyword marks code that might fail.
Example:
try
connect()
Meaning:
Attempt this operation.
If an error occurs,
handle it below.
Networking operations are common candidates for try blocks because they depend on external systems.
The with keyword begins exception handling.
Example:
try
connect()
with
Meaning:
If an exception occurs,
look for a matching handler.
The runtime compares the exception against each rule that follows.
The pipe symbol introduces a pattern-matching case.
Example:
| pattern -> action
Each pipe represents a possible match.
Example:
with
| case1 -> ...
| case2 -> ...
| case3 -> ...
The first matching case executes.
One of the most important operators in F# exception handling is:
:?
This performs a runtime type check.
Example:
:? SocketException
Meaning:
Is this exception a SocketException?
If yes, the match succeeds.
If no, F# continues searching for another handler.
SocketException is a .NET exception used for networking errors.
Namespace:
System.Net.Sockets
Typical causes include:
| Error | Description |
|---|---|
| Connection Refused | Service not listening |
| Timeout | No response received |
| Host Not Found | DNS lookup failed |
| Network Unreachable | Routing issue |
| Connection Reset | Peer closed connection |
Because networking failures are common, SocketException appears frequently in TCP applications.
The arrow operator is:
->
It means:
If this pattern matches,
execute the code on the right.
Example:
| :? SocketException ->
printfn "Connection failed"
Meaning:
If the exception is a SocketException,
print an error message.
Let's walk through the scanner step by step.
Attempt TCP connection.
new TcpClient(...)
Connection succeeds.
Output:
Connection successful
or
Connection fails.
A SocketException is thrown.
The exception handler matches:
:? SocketException
The failure message is displayed.
Connection failed
Port scanners depend heavily on connection outcomes.
Successful connection:
Port Open
Connection refused:
Port Closed
Timeout:
Port Filtered
Host unreachable:
Target Unreachable
Exceptions provide a simple way to classify these outcomes.
TCP scanning forms the foundation of:
Understanding how scanners work also helps administrators better understand firewall behavior and network exposure.
TcpClient provides a simple way to establish TCP sessions.SocketException represents common networking failures.try identifies code that may fail.with starts exception handling.| introduces pattern-matching cases.:? performs runtime type testing.-> specifies the action to execute after a successful match.Building a TCP port scanner is an excellent introduction to networking and systems programming.
Even a small scanner demonstrates several foundational concepts, including TCP connections, port states, socket programming, exception handling, and pattern matching.
For F# developers, understanding how SocketException integrates with pattern matching provides a clean and expressive way to handle networking failures while building reliable network applications.