TCP (Transmission Control Protocol):
- TCP provides a reliable, connection-oriented communication stream.
- It ensures that data sent from one end is received correctly at the other end.
- It handles issues like packet loss, out-of-order packets, and retransmission.
UDP (User Datagram Protocol):
- UDP is a connectionless protocol that sends datagrams without establishing a connection.
- It is faster than TCP but does not guarantee delivery or order of packets.
- It is suitable for scenarios where low latency and real-time communication are more critical than reliability.
TCP is suitable for applications that require a reliable and ordered data stream, while UDP is suitable for real-time applications where speed is more crucial than guaranteed delivery.
TCP Client
import socket
target_host = "www.google.com"
target_port = 80
# create a socket object
client = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
# connect the client
client.connect((target_host, target_port))
# send some data
client.send(b"GET / HTTP/1.1\r\nHost: google.com\r\n\r\n")
# receive data
response = client.recv(4096)
client.close()
print(response)Explanation:
-
Setting Target Host and Port:
target_hostis set to “www.google.com”, which is the domain of the target server.target_portis set to 80, which is the standard port for HTTP.
-
Creating a Socket:
socket.socket(socket.AF_INET, socket.SOCK_STREAM)creates a socket object.AF_INETspecifies the address family as IPv4, andSOCK_STREAMspecifies a TCP socket.
-
Connecting to the Server:
client.connect((target_host, target_port))establishes a connection to the specified target host and port.
-
Sending an HTTP GET Request:
client.send(b"GET / HTTP/1.1\r\nHost: google.com\r\n\r\n")sends an HTTP GET request to the server.- The request is composed of the HTTP method (“GET”), the requested resource (“/”), and the HTTP version (“HTTP/1.1”).
- The “Host” header indicates the host for which the request is intended.
-
Receiving Data from the Server:
client.recv(4096)receives up to 4096 bytes of data from the server in response to the HTTP request.- This data is typically the HTML content of the home page.
-
Closing the Connection:
client.close()closes the socket connection to the server.
-
Printing the Response:
print(response)prints the received response, which typically contains the HTML content of the Google home page.
UDP Client
import socket
target_host = "127.0.0.1"
target_port = 80
# create a socket object
client = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
# send some data
client.sendto(b"AAABBBCCC", (target_host, target_port))
# receive some data
data, addr = client.recvfrom(4096)
client.close()
print(data)It sends a UDP datagram to a target server at the specified IP address and port and then waits to receive a response.
Explanation:
-
Setting Target Host and Port:
target_hostis set to “127.0.0.1”, which is the loopback address (localhost).target_portis set to 80, which is an arbitrary port number.
-
Creating a UDP Socket:
socket.socket(socket.AF_INET, socket.SOCK_DGRAM)creates a socket object for UDP communication.AF_INETspecifies the address family as IPv4, andSOCK_DGRAMspecifies a UDP socket.
-
Sending a UDP Datagram:
client.sendto(b"AAABBBCCC", (target_host, target_port))sends a UDP datagram containing the bytes “AAABBBCCC” to the specified target host and port.- Unlike TCP, UDP is a connectionless protocol, so there is no need to establish a connection before sending data.
-
Receiving Data from the Server:
client.recvfrom(4096)receives up to 4096 bytes of data from the server.- The received data is stored in the
datavariable, and the address of the sender is stored in theaddrvariable.
-
Closing the UDP Socket:
client.close()closes the UDP socket. Unlike TCP, there is no need to explicitly close connections in UDP since it is connectionless.
-
Printing the Received Data:
print(data)prints the received data, which, in this case, is the response from the server.
The basic principles of UDP communication: sending datagrams without establishing a connection and receiving datagrams from a specified target. Note that UDP does not guarantee the order of delivery or that the datagram will reach its destination, so additional mechanisms may be needed for reliability if required for a specific application.
TCP Server
import socket
import threading
bind_ip = "0.0.0.0"
bind_port = 9999
server = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
server.bind((bind_ip, bind_port))
server.listen(5)
print("[*] Listening on %s:%d" % (bind_ip, bind_port))
# this is our client handling thread
def handle_client(client_socket):
# just print out what the client sends
request = client_socket.recv(1024)
print("[*] Received: %s" % request)
# send back a packet
client_socket.send(b"ACK!")
print(client_socket.getpeername())
client_socket.close()
while True:
client, addr = server.accept()
print("[*] Accepted connection from: %s:%d" % (addr[0], addr[1]))
# spin up our client thread to handle incoming data
client_handler = threading.Thread(target=handle_client, args=(client,))
client_handler.start()The server listens for incoming connections on a specified IP address and port, and for each connection, it creates a new thread to handle the communication with the connected client.
Explanation:
-
Socket Creation and Binding:
- The server creates a TCP socket using
socket.socket(socket.AF_INET, socket.SOCK_STREAM). - The socket is bound to the specified IP address (
0.0.0.0, which means it listens on all available interfaces) and port (9999) usingserver.bind((bind_ip, bind_port)).
- The server creates a TCP socket using
-
Listening for Incoming Connections:
- The server listens for incoming connections with a backlog of 5 using
server.listen(5).
- The server listens for incoming connections with a backlog of 5 using
-
Handling Client Connections:
- In an infinite loop (
while True), the server accepts incoming connections withserver.accept(). - For each accepted connection, it prints a message and creates a new thread (
client_handler) to handle communication with the connected client.
- In an infinite loop (
-
Handling Client Data in a Thread:
- The
handle_clientfunction is responsible for handling communication with a connected client. - It receives data from the client using
client_socket.recv(1024). - It prints the received data and sends a simple acknowledgment back to the client using
client_socket.send(b"ACK!"). - It prints the peer’s address (client’s address) using
client_socket.getpeername(). - It closes the client socket.
- The
-
Thread Creation:
- Each time a connection is accepted, a new thread (
client_handler) is created to handle that specific client usingthreading.Thread(target=handle_client, args=(client,)). - The thread is started with
client_handler.start().
- Each time a connection is accepted, a new thread (
This server is a simple demonstration and lacks error handling and additional features that might be necessary in a production environment. The use of threading allows the server to handle multiple clients concurrently. Keep in mind that for production use, more sophisticated mechanisms like a thread pool or an asynchronous approach may be considered.