A tiny FTP-like system in Java.
Control channel: Java RMI for commands.
Data channel: a fresh TCP socket per file (like classic FTP).
pwd,cd,dir,ldirfor remote/local navigationgetandputwith Passive (PASV) and Active (PORT) modes- Works locally or across multiple EC2 instances
- Minimal configuration via CLI flags / properties
- Easy submission packaging (sources + jars + videos + rubric)
- RMI (control): client ⇄ server for commands (fast, tiny messages).
- TCP (data): one ephemeral socket per transfer.
Passive (PASV) Active (PORT)
----------------- -----------------
Server: listen(data port S) Client: listen(data port C)
Client: connect(S) Server: connect(C)
Direction: client→server connects Direction: server→client connects
ftpinterface/ RMI interfaces
ftpserver/ Server (builds ftpd.jar)
ftpclient/ Client (builds ftp.jar)
# from repo root
mvn clean package
# artifacts:
# ftpserver/target/ftpd.jar
# ftpclient/target/ftp.jarServer (Terminal 1):
cd ftpserver/target
# bind passive data sockets to loopback for local testing
java -jar ftpd.jar --serverIp 127.0.0.1 --serverPort 1099Client (Terminal 2):
cd ftpclient/target
java -jar ftp.jar --serverAddr localhost --serverPort 1099 --clientIp 127.0.0.1Create a test tree next to where you start the server (e.g., root/hello.txt), then use commands below.
Assumptions
- Same VPC; use private IPs (e.g., Server
172.31.25.252, Client172.31.24.120). - One security group for both is fine.
Security Group (simple demo setup)
- Inbound TCP from 172.31.24.120/32 (client) — enables PASV data + RMI.
- Inbound TCP from 172.31.25.252/32 (server) — enables PORT data.
- Or add a self-reference rule (“this security group”) so any instance using the SG can talk to any other on all TCP ports.
- Keep SSH 22 from your public IP.
Start the server (on Server VM):
java -jar ftpd.jar --serverIp 172.31.25.252 --serverPort 1099Start the client (on Client VM):
java -jar ftp.jar --serverAddr 172.31.25.252 --serverPort 1099 --clientIp 172.31.24.120Tip:
--serverIpchooses which interface the server binds for PASV.
--clientIpchooses which interface the client binds for PORT (must be reachable by the server).
| Command | Usage | Description |
|---|---|---|
help |
help |
Show commands. |
pwd |
pwd |
Print server’s current working directory. |
cd |
cd dir |
Change server directory (.. up, . stay). |
dir |
dir |
List files/dirs on server (within pwd). |
ldir |
ldir |
List files in the client’s current folder. |
pasv |
pasv |
Passive: server will listen for data; client will connect. |
port |
port |
Active: client will listen for data; server will connect back. |
get |
get filename |
Download file from server → client. |
put |
put filename |
Upload file from client → server. |
quit |
quit |
Exit the client. |
Examples
Passive (firewall/NAT-friendly):
ftp> pasv
ftp> cd root
ftp> dir
ftp> get hello.txt
ftp> put upload.binActive:
ftp> port
ftp> get big.iso
ftp> put data.tarGotcha:
get/putexpect exactly two tokens. Runpasv/porton a separate line first.
- Server
--serverIp <IP>: interface to bind passive data sockets (e.g.,127.0.0.1,172.31.x.x, or0.0.0.0).--serverPort <port>: RMI registry port (default in properties).
- Client
--serverAddr <host/IP>: where to find the server’s RMI registry (and the host to dial in PASV).--serverPort <port>: RMI registry port.--clientIp <IP>: interface to bind the client’s active-mode listener (PORT). Use client’s VPC IP or0.0.0.0.
- Navigation:
pwd,cdinto nested dirs,cd ..back up,dirat each level. - Passive transfers:
pasv,get,put, verify withldirand server listing. - Active transfers:
port,get,putround-trip. - Security groups: show inbound rules and explain:
- PASV: client connects to server data port (allow inbound on server).
- PORT: server connects to client data port (allow inbound on client).
- Integrity (optional):
# run on both ends for a transferred file shasum hello.txt # macOS # or sha1sum hello.txt # Linux
- Build clean jars:
mvn clean package
- Create a submission folder named after you (e.g.,
Aayush_Rajesh_Jadhav) and put everything inside it. - Zip all sources (exclude
target/,.git/, IDE files) intosrc.zipand place in that folder:zip -r src.zip . -x "*/target/*" ".git/*" ".idea/*" mv src.zip <Your_Name_Folder>/
- Copy jars:
cp ftpclient/target/ftp.jar <Your_Name_Folder>/ cp ftpserver/target/ftpd.jar <Your_Name_Folder>/
- Add required videos (
01-dir-nav.mp4,02-passive.mp4,03-active.mp4,04-security-groups.mp4) and Rubric.pdf.
(Optional) AddTest_Notes.txtdescribing what each video shows + IPs used. - Create the outer zip named after you that contains the folder named after you:
cd <parent-of-Your_Name_Folder> zip -r Your_Name.zip Your_Name_Folder
- “GET/PUT: No mode set” → run
pasvorportfirst. - Active mode
ConnectException: Connection refused
Client listening on wrong interface. Start client with:Then--clientIp <client-private-ip> # or 0.0.0.0
portagain and retry. - Passive mode connection refused
Start server with:Ensure SG allows inbound from client to server.--serverIp <server-private-ip> # or 0.0.0.0
- Typed
get hello.txt pasv→ won’t run;pasvmust be its own command first.
Local / Passive
$ java -jar ftpd.jar --serverIp 127.0.0.1
$ java -jar ftp.jar --serverAddr localhost --clientIp 127.0.0.1
ftp> pasv
ftp> cd root
ftp> dir
ftp> get hello.txt
ftp> ldirEC2 / Active
# on server VM
$ java -jar ftpd.jar --serverIp 172.31.25.252 --serverPort 1099
# on client VM
$ java -jar ftp.jar --serverAddr 172.31.25.252 --serverPort 1099 --clientIp 172.31.24.120
ftp> port
ftp> get server.log
ftp> put upload.binFor course use (CS549).