feat(tcp): added tcp capabilities

- Added example commands
This commit is contained in:
minhtrannhat 2023-12-11 21:36:49 -05:00
parent 81bf298cd6
commit de1e931fe9
Signed by: minhtrannhat
GPG Key ID: E13CFA85C53F8062
3 changed files with 62 additions and 15 deletions

View File

@ -10,6 +10,15 @@ Zero. Only python standard libs were used. Tested on Python 3.11
You can run `python3 src/myftp/client.py --directory <insert valid directory that you have read/write permissions>` to start the client or `python3 src/myftp/client.py --debug 1 --directory <insert valid directory that you have read/write permissions>` for debugging purposes. You can run `python3 src/myftp/client.py --directory <insert valid directory that you have read/write permissions>` to start the client or `python3 src/myftp/client.py --debug 1 --directory <insert valid directory that you have read/write permissions>` for debugging purposes.
Some example test commands:
- `get file_server.txt`
- `summary numbers.txt`
- `put file_local.txt`
- `put image_local.png`
- `change file_server.txt file_server1.txt`
- `help`
### Server ### Server
By default, the server IP address or hostname or server name will be `0.0.0.0` or `localhost` (meaning it will bind to all interfaces). The `--port_number` flag, if not specified will be by default `12000`. By default, the server IP address or hostname or server name will be `0.0.0.0` or `localhost` (meaning it will bind to all interfaces). The `--port_number` flag, if not specified will be by default `12000`.

View File

@ -3,7 +3,7 @@
# Description: FTP client (both UDP and TCP implemented) # Description: FTP client (both UDP and TCP implemented)
from socket import socket, AF_INET, SOCK_DGRAM from socket import socket, AF_INET, SOCK_DGRAM, SOCK_STREAM
from typing import Pattern, Tuple, Optional from typing import Pattern, Tuple, Optional
from argparse import ArgumentParser from argparse import ArgumentParser
import traceback import traceback
@ -58,8 +58,15 @@ class Client:
self.debug = debug self.debug = debug
def run(self): def run(self):
client_socket = socket(AF_INET, SOCK_DGRAM) self.client_socket = socket(
client_socket.settimeout(10) AF_INET, (SOCK_DGRAM if self.protocol == "UDP" else SOCK_STREAM)
)
self.client_socket.settimeout(10)
# only if using TCP
self.client_socket.connect(
(self.server_name, self.server_port)
) if self.protocol == "TCP" else None
try: try:
while True: while True:
@ -68,7 +75,7 @@ class Client:
# handling the "bye" command # handling the "bye" command
if command == "bye": if command == "bye":
client_socket.close() self.client_socket.close()
print(f"myftp> - {self.protocol} - Session is terminated") print(f"myftp> - {self.protocol} - Session is terminated")
break break
@ -160,9 +167,12 @@ class Client:
f"myftp> - {self.protocol} - sent payload {bin(int.from_bytes(payload, byteorder='big'))[2:]} to the server" # type: ignore f"myftp> - {self.protocol} - sent payload {bin(int.from_bytes(payload, byteorder='big'))[2:]} to the server" # type: ignore
) if self.debug else None ) if self.debug else None
client_socket.sendto(payload, (self.server_name, self.server_port)) # type: ignore if self.protocol == "UDP":
self.client_socket.sendto(payload, (self.server_name, self.server_port)) # type: ignore
else:
self.client_socket.sendall(payload) # type: ignore
response_payload = client_socket.recv(2048) response_payload = self.client_socket.recv(2048)
self.parse_response_payload(response_payload) self.parse_response_payload(response_payload)
@ -185,7 +195,7 @@ class Client:
print(traceback_info) print(traceback_info)
finally: finally:
client_socket.close() self.client_socket.close()
def parse_response_payload(self, response_payload: bytes): def parse_response_payload(self, response_payload: bytes):
first_byte = bytes([response_payload[0]]) first_byte = bytes([response_payload[0]])

View File

@ -3,7 +3,7 @@
# Description: FTP server (both UDP and TCP implemented) # Description: FTP server (both UDP and TCP implemented)
from socket import socket, AF_INET, SOCK_DGRAM from socket import socket, AF_INET, SOCK_DGRAM, SOCK_STREAM
from argparse import ArgumentParser from argparse import ArgumentParser
from typing import Optional, Tuple from typing import Optional, Tuple
import traceback import traceback
@ -50,8 +50,14 @@ class Server:
self.debug = debug self.debug = debug
def run(self): def run(self):
self.server_socket = socket(AF_INET, SOCK_DGRAM) server_socket = socket(
self.server_socket.bind((self.server_name, self.server_port)) AF_INET, (SOCK_DGRAM if self.protocol == "UDP" else SOCK_STREAM)
)
server_socket.bind((self.server_name, self.server_port))
# only needed for TCP
server_socket.listen(5) if self.protocol == "TCP" else None
print( print(
f"myftp> - {self.protocol} - Server is ready to receive at {self.server_name}:{self.server_port}" f"myftp> - {self.protocol} - Server is ready to receive at {self.server_name}:{self.server_port}"
@ -60,12 +66,27 @@ class Server:
shut_down = False shut_down = False
try: try:
if self.protocol == "TCP":
client_socket, clientAddress = server_socket.accept()
print(
f"myftp> - {self.protocol} Connected to TCP client at {clientAddress}"
) if self.debug else None
while not shut_down: while not shut_down:
print( print(
f"myftp> - {self.protocol} ------------------------------------------------------------------" f"myftp> - {self.protocol} ------------------------------------------------------------------"
) if self.debug else None ) if self.debug else None
req_payload, clientAddress = self.server_socket.recvfrom(2048) if self.protocol == "UDP":
req_payload, clientAddress = server_socket.recvfrom(2048)
else:
req_payload = client_socket.recv(2048) # type: ignore
# TCP client disconnected
if not req_payload:
client_socket.close() # type: ignore
return
first_byte = bytes([req_payload[0]]) first_byte = bytes([req_payload[0]])
@ -74,7 +95,7 @@ class Server:
) )
print( print(
f"myftp> - {self.protocol} - Received message from client at {clientAddress}: {req_payload}" f"myftp> - {self.protocol} - Received message from client at {clientAddress}: {req_payload}" # type: ignore
) if self.debug else None ) if self.debug else None
# help request handling # help request handling
@ -159,15 +180,22 @@ class Server:
response_data=response_data, # type:ignore response_data=response_data, # type:ignore
) )
self.server_socket.sendto(res_payload, clientAddress) if self.protocol == "UDP":
server_socket.sendto(res_payload, clientAddress) # type: ignore
else:
client_socket.sendall(res_payload) # type: ignore
print( print(
f"myftp> - {self.protocol} - Sent message to client at {clientAddress}: {res_payload}" f"myftp> - {self.protocol} - Sent message to client at {clientAddress}: {res_payload}" # type: ignore
) if self.debug else None ) if self.debug else None
except KeyboardInterrupt: except KeyboardInterrupt:
shut_down = True shut_down = True
self.server_socket.close() if self.protocol == "UDP":
server_socket.close()
else:
client_socket.close() # type: ignore
print(f"myftp> - {self.protocol} - Server shutting down") print(f"myftp> - {self.protocol} - Server shutting down")
finally: finally: