socket(tcp,udp),html,http

Posted by trellie on Mon, 07 Mar 2022 21:36:42 +0100

%config Completer.use_jedi = False

1. TCP client programming

AF_INET: IPV4 protocol is adopted

AF_INET6: adopt IPV6 protocol

SOCK_STREAM: specifies to use the stream oriented TCP protocol

80: web service standard port number

25: SMTP service standard port number

21: FTP service port number

1024: port for Internet standard services

# Import socket library
import socket

# Create a socket
s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
# Establish connection (address + port)
s.connect((('www.sina.com.cn'),80))

After establishing a TCP connection, we can send a request to Sina server to return the contents of the home page:

# Send data:
s.send(b'GET / HTTP/1.1\r\nHost: www.sina.com.cn\r\nConnection: close\r\n\r\n')

TCP connection creates a two-way channel, and both parties can send data to each other at the same time. However, who starts first, who starts later, and how to coordinate should be decided according to the specific agreement. For example, the HTTP protocol stipulates that the client must send a request to the server before the server sends data to the client.

The sent text format must comply with the HTTP standard. If the format is OK, you can then receive the data returned by Sina server:

When receiving data, call the recv(max) method to receive at most the specified number of bytes at a time. Therefore, repeat the reception in a while loop until recv() returns empty data, indicating that the reception is completed and exit the loop.

When we receive the data, we call the close() method to close the Socket, so that a complete network communication is over.

# Receive data:
buffer = []
while True:
    # Receive up to 1k bytes at a time:
    d = s.recv(1024)
    if d:
        buffer.append(d)
    else:
        break
data = b''.join(buffer)
# Close connection:
s.close()
header, html = data.split(b'\r\n\r\n', 1)
print(header.decode('utf-8'))
# Write the received data to the file:
with open('sina.html', 'wb') as f:
    f.write(html)

2. TCP programming server

Compared with client programming, server programming is more complex.

The server process first needs to bind a port and listen for connections from other clients. If a client is connected, the server establishes a Socket connection with the client, and the subsequent communication depends on the Socket connection.

Therefore, the server will open the fixed port (such as 80) to listen, and create the Socket connection for each client connection. Since the server will have a large number of connections from clients, the server should be able to distinguish which client a Socket connection is bound to. A Socket depends on four items: server address, server port, client address and client port to uniquely determine a Socket.

However, the server also needs to respond to the requests of multiple clients at the same time. Therefore, each connection needs a new process or new thread to process. Otherwise, the server can only serve one client at a time.

s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)

Then, we need to bind the listening address and port. The server may have multiple network cards, which can be bound to the IP address of a network card, 0.0.0.0 to all network addresses, or 127.0.0.1 to the local address. 127.0.0.1 is a special IP address, which indicates the local address. If bound to this address, the client must run on the local machine at the same time to connect, that is, the external computer cannot connect

The port number needs to be specified in advance. Because the service we wrote is not a standard service, we use the port number 9999. Please note that port numbers less than 1024 must have administrator privileges to bind:

# Listening port:
s.bind(('127.0.0.1', 9999))

Next, call the listen() method to start listening on the port. The parameter passed in specifies the maximum number of connections to wait for:

s.listen(5)
print('Waiting for connection...')

Next, the server program accepts the connection from the client through a permanent loop, and accept() will wait and return a client connection:

while True:
    # Accept a new connection:
    sock, addr = s.accept()
    # Create a new thread to handle TCP connections:
    t = threading.Thread(target=tcplink, args=(sock, addr))
    t.start()
    
def tcplink(sock, addr):
    print('Accept new connection from %s:%s...' % addr)
    sock.send(b'Welcome!')
    while True:
        data = sock.recv(1024)
        time.sleep(1)
        if not data or data.decode('utf-8') == 'exit':
            break
        sock.send(('Hello, %s!' % data.decode('utf-8')).encode('utf-8'))
    sock.close()
    print('Connection from %s:%s closed.' % addr)

After the connection is established, the server first sends a welcome message, then waits for the client data, adds Hello, and then sends it to the client. If the client sends the exit string, close the connection directly.

To test the server program, we also need to write a client program:

s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
# Establish connection:
s.connect(('127.0.0.1', 9999))
# Receive welcome message:
print(s.recv(1024).decode('utf-8'))
for data in [b'Michael', b'Tracy', b'Sarah']:
    # Send data:
    s.send(data)
    print(s.recv(1024).decode('utf-8'))
s.send(b'exit')
s.close()

3. UDP programming

TCP is to establish a reliable connection, and both sides of communication can send data in the form of stream. Compared with TCP, UDP is a connectionless protocol.

When using UDP protocol, you don't need to establish a connection. You only need to know the other party's IP address and port number to send data packets directly. But I don't know if I can get there.

Although using UDP to transmit data is unreliable, its advantage is that it is faster than TCP. For data that does not require reliable arrival, UDP protocol can be used.

Let's see how to transmit data through UDP protocol. Similar to TCP, the communication parties using UDP are also divided into client and server. The server needs to bind ports first:

s = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
# Binding port:
s.bind(('127.0.0.1', 9999))

When creating a Socket, SOCK_DGRAM specifies that the Socket type is UDP. The binding port is the same as TCP, but it does not need to call the listen() method, but directly receives data from any client:

print('Bind UDP on 9999...')
while True:
    # Receive data:
    data, addr = s.recvfrom(1024)
    print('Received from %s:%s.' % addr)
    s.sendto(b'Hello, %s!' % data, addr)

The recvfrom() method returns the data and the address and port of the client. In this way, after the server receives the data, it can directly call sendto() to send the data to the client with UDP.

Note that multithreading is omitted here because this example is very simple.

When the client uses UDP, it first creates a Socket based on UDP, and then sends data directly to the server through sendto() without calling connect():

s = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
for data in [b'Michael', b'Tracy', b'Sarah']:
    # Send data:
    s.sendto(data, ('127.0.0.1', 9999))
    # Receive data:
    print(s.recv(1024).decode('utf-8'))
s.close()

Operation results:

HTML

HTML defines the content of the page, CSS controls the style of page elements (bold, shadow), and JavaScript is responsible for the interaction logic of the page.

HTTP is a protocol for transmitting HTML on the network, which is used for the communication between browser and server.



After understanding the HTTP protocol and HTML documents, we actually understand the essence of a Web application:

  • 1. The browser sends an HTTP request;

  • 2. The server receives the request and generates an HTML document;

  • 3. The server sends the HTML document to the browser as the Body of the HTTP response;

  • 4. The browser receives the HTTP response, takes out the HTML document from the HTTP Body and displays it.