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.
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
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)
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 argparse import ArgumentParser
import traceback
@ -58,8 +58,15 @@ class Client:
self.debug = debug
def run(self):
client_socket = socket(AF_INET, SOCK_DGRAM)
client_socket.settimeout(10)
self.client_socket = socket(
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:
while True:
@ -68,7 +75,7 @@ class Client:
# handling the "bye" command
if command == "bye":
client_socket.close()
self.client_socket.close()
print(f"myftp> - {self.protocol} - Session is terminated")
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
) 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)
@ -185,7 +195,7 @@ class Client:
print(traceback_info)
finally:
client_socket.close()
self.client_socket.close()
def parse_response_payload(self, response_payload: bytes):
first_byte = bytes([response_payload[0]])

View File

@ -3,7 +3,7 @@
# 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 typing import Optional, Tuple
import traceback
@ -50,8 +50,14 @@ class Server:
self.debug = debug
def run(self):
self.server_socket = socket(AF_INET, SOCK_DGRAM)
self.server_socket.bind((self.server_name, self.server_port))
server_socket = socket(
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(
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
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:
print(
f"myftp> - {self.protocol} ------------------------------------------------------------------"
) 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]])
@ -74,7 +95,7 @@ class Server:
)
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
# help request handling
@ -159,15 +180,22 @@ class Server:
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(
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
except KeyboardInterrupt:
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")
finally: