Ổ cắm và API ổ cắm được sử dụng để gửi tin nhắn qua mạng. They provide a form of inter-process communication [IPC]. The network can be a logical, local network to the computer, or one that’s physically connected to an external network, with its own connections to other networks. The obvious example is the Internet, which you connect to via your ISP
In this tutorial, you’ll create
- A simple socket server and client
- An improved version that handles multiple connections simultaneously
- A server-client application that functions like a full-fledged socket application, complete with its own custom header and content
By the end of this tutorial, you’ll understand how to use the main functions and methods in Python’s socket module to write your own client-server applications. You’ll know how to use a custom class to send messages and data between endpoints, which you can build upon and utilize for your own applications
The examples in this tutorial require Python 3. 6 or above, and have been tested using Python 3. 10. To get the most out of this tutorial, it’s best to download the source code and have it on hand for reference while reading
Get Source Code. Click here to get the source code you’ll use for the examples in this tutorial
Networking and sockets are large subjects. Literal volumes have been written about them. If you’re new to sockets or networking, it’s completely normal if you feel overwhelmed with all of the terms and pieces
Don’t be discouraged though. This tutorial is for you. As with anything Python-related, you can learn a little bit at a time. Bookmark this article and come back when you’re ready for the next section
Background
Sockets have a long history. Their use originated with ARPANET in 1971 and later became an API in the Berkeley Software Distribution [BSD] operating system released in 1983 called Berkeley sockets
When the Internet took off in the 1990s with the World Wide Web, so did network programming. Web servers and browsers weren’t the only applications taking advantage of newly connected networks and using sockets. Client-server applications of all types and sizes came into widespread use
Today, although the underlying protocols used by the socket API have evolved over the years, and new ones have developed, the low-level API has remained the same
The most common type of socket applications are client-server applications, where one side acts as the server and waits for connections from clients. This is the type of application that you’ll be creating in this tutorial. More specifically, you’ll focus on the socket API for Internet sockets, sometimes called Berkeley or BSD sockets. There are also Unix domain sockets, which can only be used to communicate between processes on the same host
Remove adsSocket API Overview
Python’s socket module provides an interface to the Berkeley sockets API. This is the module that you’ll use in this tutorial
The primary socket API functions and methods in this module are
8$ python echo-server.py
9$ python echo-server.py
0# echo-server.py # ... with socket.socket[socket.AF_INET, socket.SOCK_STREAM] as s: s.bind[[HOST, PORT]] s.listen[] conn, addr = s.accept[] with conn: print[f"Connected by {addr}"] while True: data = conn.recv[1024] if not data: break conn.sendall[data]
1# echo-server.py # ... with socket.socket[socket.AF_INET, socket.SOCK_STREAM] as s: s.bind[[HOST, PORT]] s.listen[] conn, addr = s.accept[] with conn: print[f"Connected by {addr}"] while True: data = conn.recv[1024] if not data: break conn.sendall[data]
2# echo-server.py # ... with socket.socket[socket.AF_INET, socket.SOCK_STREAM] as s: s.bind[[HOST, PORT]] s.listen[] conn, addr = s.accept[] with conn: print[f"Connected by {addr}"] while True: data = conn.recv[1024] if not data: break conn.sendall[data]
3# echo-server.py # ... with socket.socket[socket.AF_INET, socket.SOCK_STREAM] as s: s.bind[[HOST, PORT]] s.listen[] conn, addr = s.accept[] with conn: print[f"Connected by {addr}"] while True: data = conn.recv[1024] if not data: break conn.sendall[data]
4# echo-server.py # ... with socket.socket[socket.AF_INET, socket.SOCK_STREAM] as s: s.bind[[HOST, PORT]] s.listen[] conn, addr = s.accept[] with conn: print[f"Connected by {addr}"] while True: data = conn.recv[1024] if not data: break conn.sendall[data]
5# echo-server.py # ... with socket.socket[socket.AF_INET, socket.SOCK_STREAM] as s: s.bind[[HOST, PORT]] s.listen[] conn, addr = s.accept[] with conn: print[f"Connected by {addr}"] while True: data = conn.recv[1024] if not data: break conn.sendall[data]
6# echo-server.py # ... with socket.socket[socket.AF_INET, socket.SOCK_STREAM] as s: s.bind[[HOST, PORT]] s.listen[] conn, addr = s.accept[] with conn: print[f"Connected by {addr}"] while True: data = conn.recv[1024] if not data: break conn.sendall[data]
Python provides a convenient and consistent API that maps directly to system calls, their C counterparts. In the next section, you’ll learn how these are used together
As part of its standard library, Python also has classes that make using these low-level socket functions easier. Although it’s not covered in this tutorial, you can check out the socketserver module, a framework for network servers. There are also many modules available that implement higher-level Internet protocols like HTTP and SMTP. For an overview, see Internet Protocols and Support
TCP Sockets
You’re going to create a socket object using
# echo-server.py
# ...
with socket.socket[socket.AF_INET, socket.SOCK_STREAM] as s:
s.bind[[HOST, PORT]]
s.listen[]
conn, addr = s.accept[]
with conn:
print[f"Connected by {addr}"]
while True:
data = conn.recv[1024]
if not data:
break
conn.sendall[data]
7, specifying the socket type as # echo-server.py
# ...
with socket.socket[socket.AF_INET, socket.SOCK_STREAM] as s:
s.bind[[HOST, PORT]]
s.listen[]
conn, addr = s.accept[]
with conn:
print[f"Connected by {addr}"]
while True:
data = conn.recv[1024]
if not data:
break
conn.sendall[data]
8. When you do that, the default protocol that’s used is the Transmission Control Protocol [TCP]. This is a good default and probably what you wantWhy should you use TCP? The Transmission Control Protocol [TCP]
- Đáng tin cậy. Packets dropped in the network are detected and retransmitted by the sender
- Has in-order data delivery. Data is read by your application in the order it was written by the sender
In contrast, User Datagram Protocol [UDP] sockets created with
# echo-server.py
# ...
with socket.socket[socket.AF_INET, socket.SOCK_STREAM] as s:
s.bind[[HOST, PORT]]
s.listen[]
conn, addr = s.accept[]
with conn:
print[f"Connected by {addr}"]
while True:
data = conn.recv[1024]
if not data:
break
conn.sendall[data]
9 aren’t reliable, and data read by the receiver can be out-of-order from the sender’s writesWhy is this important? Networks are a best-effort delivery system. There’s no guarantee that your data will reach its destination or that you’ll receive what’s been sent to you
Network devices, such as routers and switches, have finite bandwidth available and come with their own inherent system limitations. They have CPUs, memory, buses, and interface packet buffers, just like your clients and servers. TCP relieves you from having to worry about packet loss, out-of-order data arrival, and other pitfalls that invariably happen when you’re communicating across a network
To better understand this, check out the sequence of socket API calls and data flow for TCP
The left-hand column represents the server. On the right-hand side is the client
Starting in the top left-hand column, note the API calls that the server makes to set up a “listening” socket
8$ python echo-server.py
9$ python echo-server.py
0# echo-server.py # ... with socket.socket[socket.AF_INET, socket.SOCK_STREAM] as s: s.bind[[HOST, PORT]] s.listen[] conn, addr = s.accept[] with conn: print[f"Connected by {addr}"] while True: data = conn.recv[1024] if not data: break conn.sendall[data]
1# echo-server.py # ... with socket.socket[socket.AF_INET, socket.SOCK_STREAM] as s: s.bind[[HOST, PORT]] s.listen[] conn, addr = s.accept[] with conn: print[f"Connected by {addr}"] while True: data = conn.recv[1024] if not data: break conn.sendall[data]
A listening socket does just what its name suggests. It listens for connections from clients. When a client connects, the server calls
# echo-server.py
# ...
with socket.socket[socket.AF_INET, socket.SOCK_STREAM] as s:
s.bind[[HOST, PORT]]
s.listen[]
conn, addr = s.accept[]
with conn:
print[f"Connected by {addr}"]
while True:
data = conn.recv[1024]
if not data:
break
conn.sendall[data]
1 to accept, or complete, the connectionThe client calls
# echo-server.py
# ...
with socket.socket[socket.AF_INET, socket.SOCK_STREAM] as s:
s.bind[[HOST, PORT]]
s.listen[]
conn, addr = s.accept[]
with conn:
print[f"Connected by {addr}"]
while True:
data = conn.recv[1024]
if not data:
break
conn.sendall[data]
2 to establish a connection to the server and initiate the three-way handshake. The handshake step is important because it ensures that each side of the connection is reachable in the network, in other words that the client can reach the server and vice-versa. It may be that only one host, client, or server can reach the otherIn the middle is the round-trip section, where data is exchanged between the client and server using calls to
# echo-server.py
# ...
with socket.socket[socket.AF_INET, socket.SOCK_STREAM] as s:
s.bind[[HOST, PORT]]
s.listen[]
conn, addr = s.accept[]
with conn:
print[f"Connected by {addr}"]
while True:
data = conn.recv[1024]
if not data:
break
conn.sendall[data]
4 and # echo-server.py
# ...
with socket.socket[socket.AF_INET, socket.SOCK_STREAM] as s:
s.bind[[HOST, PORT]]
s.listen[]
conn, addr = s.accept[]
with conn:
print[f"Connected by {addr}"]
while True:
data = conn.recv[1024]
if not data:
break
conn.sendall[data]
5At the bottom, the client and server close their respective sockets
Remove adsEcho Client and Server
Now that you’ve gotten an overview of the socket API and how the client and server communicate, you’re ready to create your first client and server. You’ll begin with a simple implementation. The server will simply echo whatever it receives back to the client
Echo Server
Here’s the server
# echo-server.py
# ...
with socket.socket[socket.AF_INET, socket.SOCK_STREAM] as s:
s.bind[[HOST, PORT]]
s.listen[]
conn, addr = s.accept[]
with conn:
print[f"Connected by {addr}"]
while True:
data = conn.recv[1024]
if not data:
break
conn.sendall[data]
0Note. Don’t worry about understanding everything above right now. There’s a lot going on in these few lines of code. This is just a starting point so you can see a basic server in action
There’s a reference section at the end of this tutorial that has more information and links to additional resources. You’ll also find these and other useful links throughout the tutorial
Okay, so what exactly is happening in the API call?
# echo-server.py
# ...
with socket.socket[socket.AF_INET, socket.SOCK_STREAM] as s:
s.bind[[HOST, PORT]]
s.listen[]
conn, addr = s.accept[]
with conn:
print[f"Connected by {addr}"]
while True:
data = conn.recv[1024]
if not data:
break
conn.sendall[data]
7 creates a socket object that supports the context manager type, so you can use it in a # echo-server.py
# ...
with socket.socket[socket.AF_INET, socket.SOCK_STREAM] as s:
s.bind[[HOST, PORT]]
s.listen[]
conn, addr = s.accept[]
with conn:
print[f"Connected by {addr}"]
while True:
data = conn.recv[1024]
if not data:
break
conn.sendall[data]
29 statement. There’s no need to call # echo-server.py
# ...
with socket.socket[socket.AF_INET, socket.SOCK_STREAM] as s:
s.bind[[HOST, PORT]]
s.listen[]
conn, addr = s.accept[]
with conn:
print[f"Connected by {addr}"]
while True:
data = conn.recv[1024]
if not data:
break
conn.sendall[data]
30# echo-server.py
# ...
with socket.socket[socket.AF_INET, socket.SOCK_STREAM] as s:
s.bind[[HOST, PORT]]
s.listen[]
conn, addr = s.accept[]
with conn:
print[f"Connected by {addr}"]
while True:
data = conn.recv[1024]
if not data:
break
conn.sendall[data]
4The arguments passed to
$ python echo-server.py
8 are constants used to specify the address family and socket type. # echo-server.py
# ...
with socket.socket[socket.AF_INET, socket.SOCK_STREAM] as s:
s.bind[[HOST, PORT]]
s.listen[]
conn, addr = s.accept[]
with conn:
print[f"Connected by {addr}"]
while True:
data = conn.recv[1024]
if not data:
break
conn.sendall[data]
32 is the Internet address family for IPv4. # echo-server.py
# ...
with socket.socket[socket.AF_INET, socket.SOCK_STREAM] as s:
s.bind[[HOST, PORT]]
s.listen[]
conn, addr = s.accept[]
with conn:
print[f"Connected by {addr}"]
while True:
data = conn.recv[1024]
if not data:
break
conn.sendall[data]
33 is the socket type for TCP, the protocol that will be used to transport messages in the networkThe
$ python echo-server.py
9 method is used to associate the socket with a specific network interface and port number# echo-server.py
# ...
with socket.socket[socket.AF_INET, socket.SOCK_STREAM] as s:
s.bind[[HOST, PORT]]
s.listen[]
conn, addr = s.accept[]
with conn:
print[f"Connected by {addr}"]
while True:
data = conn.recv[1024]
if not data:
break
conn.sendall[data]
9The values passed to
$ python echo-server.py
9 depend on the address family of the socket. In this example, you’re using # echo-server.py
# ...
with socket.socket[socket.AF_INET, socket.SOCK_STREAM] as s:
s.bind[[HOST, PORT]]
s.listen[]
conn, addr = s.accept[]
with conn:
print[f"Connected by {addr}"]
while True:
data = conn.recv[1024]
if not data:
break
conn.sendall[data]
36 [IPv4]. So it expects a two-tuple. # echo-server.py
# ...
with socket.socket[socket.AF_INET, socket.SOCK_STREAM] as s:
s.bind[[HOST, PORT]]
s.listen[]
conn, addr = s.accept[]
with conn:
print[f"Connected by {addr}"]
while True:
data = conn.recv[1024]
if not data:
break
conn.sendall[data]
37# echo-server.py
# ...
with socket.socket[socket.AF_INET, socket.SOCK_STREAM] as s:
s.bind[[HOST, PORT]]
s.listen[]
conn, addr = s.accept[]
with conn:
print[f"Connected by {addr}"]
while True:
data = conn.recv[1024]
if not data:
break
conn.sendall[data]
38 có thể là tên máy chủ, địa chỉ IP hoặc chuỗi rỗng. If an IP address is used, # echo-server.py
# ...
with socket.socket[socket.AF_INET, socket.SOCK_STREAM] as s:
s.bind[[HOST, PORT]]
s.listen[]
conn, addr = s.accept[]
with conn:
print[f"Connected by {addr}"]
while True:
data = conn.recv[1024]
if not data:
break
conn.sendall[data]
38 should be an IPv4-formatted address string. The IP address # echo-server.py
# ...
with socket.socket[socket.AF_INET, socket.SOCK_STREAM] as s:
s.bind[[HOST, PORT]]
s.listen[]
conn, addr = s.accept[]
with conn:
print[f"Connected by {addr}"]
while True:
data = conn.recv[1024]
if not data:
break
conn.sendall[data]
400 is the standard IPv4 address for the loopback interface, so only processes on the host will be able to connect to the server. If you pass an empty string, the server will accept connections on all available IPv4 interfaces# echo-server.py
# ...
with socket.socket[socket.AF_INET, socket.SOCK_STREAM] as s:
s.bind[[HOST, PORT]]
s.listen[]
conn, addr = s.accept[]
with conn:
print[f"Connected by {addr}"]
while True:
data = conn.recv[1024]
if not data:
break
conn.sendall[data]
401 represents the TCP port number to accept connections on from clients. It should be an integer from # echo-server.py
# ...
with socket.socket[socket.AF_INET, socket.SOCK_STREAM] as s:
s.bind[[HOST, PORT]]
s.listen[]
conn, addr = s.accept[]
with conn:
print[f"Connected by {addr}"]
while True:
data = conn.recv[1024]
if not data:
break
conn.sendall[data]
402 to # echo-server.py
# ...
with socket.socket[socket.AF_INET, socket.SOCK_STREAM] as s:
s.bind[[HOST, PORT]]
s.listen[]
conn, addr = s.accept[]
with conn:
print[f"Connected by {addr}"]
while True:
data = conn.recv[1024]
if not data:
break
conn.sendall[data]
403, as # echo-server.py
# ...
with socket.socket[socket.AF_INET, socket.SOCK_STREAM] as s:
s.bind[[HOST, PORT]]
s.listen[]
conn, addr = s.accept[]
with conn:
print[f"Connected by {addr}"]
while True:
data = conn.recv[1024]
if not data:
break
conn.sendall[data]
404 is reserved. Some systems may require superuser privileges if the port number is less than # echo-server.py
# ...
with socket.socket[socket.AF_INET, socket.SOCK_STREAM] as s:
s.bind[[HOST, PORT]]
s.listen[]
conn, addr = s.accept[]
with conn:
print[f"Connected by {addr}"]
while True:
data = conn.recv[1024]
if not data:
break
conn.sendall[data]
405Đây là một lưu ý về việc sử dụng tên máy chủ với
$ python echo-server.py
9“If you use a hostname in the host portion of IPv4/v6 socket address, the program may show a non-deterministic behavior, as Python uses the first address returned from the DNS resolution. The socket address will be resolved differently into an actual IPv4/v6 address, depending on the results from DNS resolution and/or the host configuration. For deterministic behavior use a numeric address in host portion. ” [Source]
You’ll learn more about this later, in Using Hostnames. For now, just understand that when using a hostname, you could see different results depending on what’s returned from the name resolution process. These results could be anything. The first time you run your application, you might get the address
# echo-server.py
# ...
with socket.socket[socket.AF_INET, socket.SOCK_STREAM] as s:
s.bind[[HOST, PORT]]
s.listen[]
conn, addr = s.accept[]
with conn:
print[f"Connected by {addr}"]
while True:
data = conn.recv[1024]
if not data:
break
conn.sendall[data]
407. The next time, you get a different address, # echo-server.py
# ...
with socket.socket[socket.AF_INET, socket.SOCK_STREAM] as s:
s.bind[[HOST, PORT]]
s.listen[]
conn, addr = s.accept[]
with conn:
print[f"Connected by {addr}"]
while True:
data = conn.recv[1024]
if not data:
break
conn.sendall[data]
408. The third time, you could get # echo-server.py
# ...
with socket.socket[socket.AF_INET, socket.SOCK_STREAM] as s:
s.bind[[HOST, PORT]]
s.listen[]
conn, addr = s.accept[]
with conn:
print[f"Connected by {addr}"]
while True:
data = conn.recv[1024]
if not data:
break
conn.sendall[data]
409, and so onIn the server example,
# echo-server.py
# ...
with socket.socket[socket.AF_INET, socket.SOCK_STREAM] as s:
s.bind[[HOST, PORT]]
s.listen[]
conn, addr = s.accept[]
with conn:
print[f"Connected by {addr}"]
while True:
data = conn.recv[1024]
if not data:
break
conn.sendall[data]
0 enables a server to accept connections. It makes the server a “listening” socket# echo-server.py
# ...
with socket.socket[socket.AF_INET, socket.SOCK_STREAM] as s:
s.bind[[HOST, PORT]]
s.listen[]
conn, addr = s.accept[]
with conn:
print[f"Connected by {addr}"]
while True:
data = conn.recv[1024]
if not data:
break
conn.sendall[data]
6The
# echo-server.py
# ...
with socket.socket[socket.AF_INET, socket.SOCK_STREAM] as s:
s.bind[[HOST, PORT]]
s.listen[]
conn, addr = s.accept[]
with conn:
print[f"Connected by {addr}"]
while True:
data = conn.recv[1024]
if not data:
break
conn.sendall[data]
0 method has a # echo-server.py
# ...
with socket.socket[socket.AF_INET, socket.SOCK_STREAM] as s:
s.bind[[HOST, PORT]]
s.listen[]
conn, addr = s.accept[]
with conn:
print[f"Connected by {addr}"]
while True:
data = conn.recv[1024]
if not data:
break
conn.sendall[data]
412 parameter. It specifies the number of unaccepted connections that the system will allow before refusing new connections. Starting in Python 3. 5, it’s optional. If not specified, a default # echo-server.py
# ...
with socket.socket[socket.AF_INET, socket.SOCK_STREAM] as s:
s.bind[[HOST, PORT]]
s.listen[]
conn, addr = s.accept[]
with conn:
print[f"Connected by {addr}"]
while True:
data = conn.recv[1024]
if not data:
break
conn.sendall[data]
412 value is chosenIf your server receives a lot of connection requests simultaneously, increasing the
# echo-server.py
# ...
with socket.socket[socket.AF_INET, socket.SOCK_STREAM] as s:
s.bind[[HOST, PORT]]
s.listen[]
conn, addr = s.accept[]
with conn:
print[f"Connected by {addr}"]
while True:
data = conn.recv[1024]
if not data:
break
conn.sendall[data]
412 value may help by setting the maximum length of the queue for pending connections. The maximum value is system dependent. For example, on Linux, see # echo-server.py
# ...
with socket.socket[socket.AF_INET, socket.SOCK_STREAM] as s:
s.bind[[HOST, PORT]]
s.listen[]
conn, addr = s.accept[]
with conn:
print[f"Connected by {addr}"]
while True:
data = conn.recv[1024]
if not data:
break
conn.sendall[data]
415The
# echo-server.py
# ...
with socket.socket[socket.AF_INET, socket.SOCK_STREAM] as s:
s.bind[[HOST, PORT]]
s.listen[]
conn, addr = s.accept[]
with conn:
print[f"Connected by {addr}"]
while True:
data = conn.recv[1024]
if not data:
break
conn.sendall[data]
1 method blocks execution and waits for an incoming connection. When a client connects, it returns a new socket object representing the connection and a tuple holding the address of the client. The tuple will contain # echo-server.py
# ...
with socket.socket[socket.AF_INET, socket.SOCK_STREAM] as s:
s.bind[[HOST, PORT]]
s.listen[]
conn, addr = s.accept[]
with conn:
print[f"Connected by {addr}"]
while True:
data = conn.recv[1024]
if not data:
break
conn.sendall[data]
37 for IPv4 connections or # echo-server.py
# ...
with socket.socket[socket.AF_INET, socket.SOCK_STREAM] as s:
s.bind[[HOST, PORT]]
s.listen[]
conn, addr = s.accept[]
with conn:
print[f"Connected by {addr}"]
while True:
data = conn.recv[1024]
if not data:
break
conn.sendall[data]
418 for IPv6. See Socket Address Families in the reference section for details on the tuple valuesOne thing that’s imperative to understand is that you now have a new socket object from
# echo-server.py
# ...
with socket.socket[socket.AF_INET, socket.SOCK_STREAM] as s:
s.bind[[HOST, PORT]]
s.listen[]
conn, addr = s.accept[]
with conn:
print[f"Connected by {addr}"]
while True:
data = conn.recv[1024]
if not data:
break
conn.sendall[data]
1. This is important because it’s the socket that you’ll use to communicate with the client. It’s distinct from the listening socket that the server is using to accept new connections# echo-server.py
# ...
with socket.socket[socket.AF_INET, socket.SOCK_STREAM] as s:
s.bind[[HOST, PORT]]
s.listen[]
conn, addr = s.accept[]
with conn:
print[f"Connected by {addr}"]
while True:
data = conn.recv[1024]
if not data:
break
conn.sendall[data]
6After
# echo-server.py
# ...
with socket.socket[socket.AF_INET, socket.SOCK_STREAM] as s:
s.bind[[HOST, PORT]]
s.listen[]
conn, addr = s.accept[]
with conn:
print[f"Connected by {addr}"]
while True:
data = conn.recv[1024]
if not data:
break
conn.sendall[data]
1 provides the client socket object # echo-server.py
# ...
with socket.socket[socket.AF_INET, socket.SOCK_STREAM] as s:
s.bind[[HOST, PORT]]
s.listen[]
conn, addr = s.accept[]
with conn:
print[f"Connected by {addr}"]
while True:
data = conn.recv[1024]
if not data:
break
conn.sendall[data]
421, an infinite # echo-server.py
# ...
with socket.socket[socket.AF_INET, socket.SOCK_STREAM] as s:
s.bind[[HOST, PORT]]
s.listen[]
conn, addr = s.accept[]
with conn:
print[f"Connected by {addr}"]
while True:
data = conn.recv[1024]
if not data:
break
conn.sendall[data]
422 loop is used to loop over blocking calls to # echo-server.py
# ...
with socket.socket[socket.AF_INET, socket.SOCK_STREAM] as s:
s.bind[[HOST, PORT]]
s.listen[]
conn, addr = s.accept[]
with conn:
print[f"Connected by {addr}"]
while True:
data = conn.recv[1024]
if not data:
break
conn.sendall[data]
423. This reads whatever data the client sends and echoes it back using # echo-server.py
# ...
with socket.socket[socket.AF_INET, socket.SOCK_STREAM] as s:
s.bind[[HOST, PORT]]
s.listen[]
conn, addr = s.accept[]
with conn:
print[f"Connected by {addr}"]
while True:
data = conn.recv[1024]
if not data:
break
conn.sendall[data]
424If
# echo-server.py
# ...
with socket.socket[socket.AF_INET, socket.SOCK_STREAM] as s:
s.bind[[HOST, PORT]]
s.listen[]
conn, addr = s.accept[]
with conn:
print[f"Connected by {addr}"]
while True:
data = conn.recv[1024]
if not data:
break
conn.sendall[data]
423 returns an empty # echo-server.py
# ...
with socket.socket[socket.AF_INET, socket.SOCK_STREAM] as s:
s.bind[[HOST, PORT]]
s.listen[]
conn, addr = s.accept[]
with conn:
print[f"Connected by {addr}"]
while True:
data = conn.recv[1024]
if not data:
break
conn.sendall[data]
426 object, # echo-server.py
# ...
with socket.socket[socket.AF_INET, socket.SOCK_STREAM] as s:
s.bind[[HOST, PORT]]
s.listen[]
conn, addr = s.accept[]
with conn:
print[f"Connected by {addr}"]
while True:
data = conn.recv[1024]
if not data:
break
conn.sendall[data]
427, that signals that the client closed the connection and the loop is terminated. The # echo-server.py
# ...
with socket.socket[socket.AF_INET, socket.SOCK_STREAM] as s:
s.bind[[HOST, PORT]]
s.listen[]
conn, addr = s.accept[]
with conn:
print[f"Connected by {addr}"]
while True:
data = conn.recv[1024]
if not data:
break
conn.sendall[data]
29 statement is used with # echo-server.py
# ...
with socket.socket[socket.AF_INET, socket.SOCK_STREAM] as s:
s.bind[[HOST, PORT]]
s.listen[]
conn, addr = s.accept[]
with conn:
print[f"Connected by {addr}"]
while True:
data = conn.recv[1024]
if not data:
break
conn.sendall[data]
421 to automatically close the socket at the end of the blockRemove adsEcho Client
Now let’s look at the client
# echo-server.py
# ...
with socket.socket[socket.AF_INET, socket.SOCK_STREAM] as s:
s.bind[[HOST, PORT]]
s.listen[]
conn, addr = s.accept[]
with conn:
print[f"Connected by {addr}"]
while True:
data = conn.recv[1024]
if not data:
break
conn.sendall[data]
7In comparison to the server, the client is pretty simple. It creates a socket object, uses
# echo-server.py
# ...
with socket.socket[socket.AF_INET, socket.SOCK_STREAM] as s:
s.bind[[HOST, PORT]]
s.listen[]
conn, addr = s.accept[]
with conn:
print[f"Connected by {addr}"]
while True:
data = conn.recv[1024]
if not data:
break
conn.sendall[data]
2 to connect to the server and calls # echo-server.py
# ...
with socket.socket[socket.AF_INET, socket.SOCK_STREAM] as s:
s.bind[[HOST, PORT]]
s.listen[]
conn, addr = s.accept[]
with conn:
print[f"Connected by {addr}"]
while True:
data = conn.recv[1024]
if not data:
break
conn.sendall[data]
431 to send its message. Lastly, it calls # echo-server.py
# ...
with socket.socket[socket.AF_INET, socket.SOCK_STREAM] as s:
s.bind[[HOST, PORT]]
s.listen[]
conn, addr = s.accept[]
with conn:
print[f"Connected by {addr}"]
while True:
data = conn.recv[1024]
if not data:
break
conn.sendall[data]
432 to read the server’s reply and then prints itRunning the Echo Client and Server
In this section, you’ll run the client and server to see how they behave and inspect what’s happening
Note. If you’re having trouble getting the examples or your own code to run from the command line, read How Do I Make My Own Command-Line Commands Using Python? or How to Run Your Python Scripts. If you’re on Windows, check the Python Windows FAQ
Open a terminal or command prompt, navigate to the directory that contains your scripts, ensure that you have Python 3. 6 or above installed and on your path, then run the server
$ python echo-server.py
Your terminal will appear to hang. That’s because the server is blocked, or suspended, on
# echo-server.py
# ...
with socket.socket[socket.AF_INET, socket.SOCK_STREAM] as s:
s.bind[[HOST, PORT]]
s.listen[]
conn, addr = s.accept[]
with conn:
print[f"Connected by {addr}"]
while True:
data = conn.recv[1024]
if not data:
break
conn.sendall[data]
1# echo-server.py
# ...
with socket.socket[socket.AF_INET, socket.SOCK_STREAM] as s:
s.bind[[HOST, PORT]]
s.listen[]
conn, addr = s.accept[]
with conn:
print[f"Connected by {addr}"]
while True:
data = conn.recv[1024]
if not data:
break
conn.sendall[data]
It’s waiting for a client connection. Now, open another terminal window or command prompt and run the client
# echo-server.py
# ...
with socket.socket[socket.AF_INET, socket.SOCK_STREAM] as s:
s.bind[[HOST, PORT]]
s.listen[]
conn, addr = s.accept[]
with conn:
print[f"Connected by {addr}"]
while True:
data = conn.recv[1024]
if not data:
break
conn.sendall[data]
2In the server window, you should notice something like this
# echo-server.py
# ...
with socket.socket[socket.AF_INET, socket.SOCK_STREAM] as s:
s.bind[[HOST, PORT]]
s.listen[]
conn, addr = s.accept[]
with conn:
print[f"Connected by {addr}"]
while True:
data = conn.recv[1024]
if not data:
break
conn.sendall[data]
3In the output above, the server printed the
# echo-server.py
# ...
with socket.socket[socket.AF_INET, socket.SOCK_STREAM] as s:
s.bind[[HOST, PORT]]
s.listen[]
conn, addr = s.accept[]
with conn:
print[f"Connected by {addr}"]
while True:
data = conn.recv[1024]
if not data:
break
conn.sendall[data]
434 tuple returned from # echo-server.py
# ...
with socket.socket[socket.AF_INET, socket.SOCK_STREAM] as s:
s.bind[[HOST, PORT]]
s.listen[]
conn, addr = s.accept[]
with conn:
print[f"Connected by {addr}"]
while True:
data = conn.recv[1024]
if not data:
break
conn.sendall[data]
435. Đây là địa chỉ IP và số cổng TCP của máy khách. The port number, # echo-server.py
# ...
with socket.socket[socket.AF_INET, socket.SOCK_STREAM] as s:
s.bind[[HOST, PORT]]
s.listen[]
conn, addr = s.accept[]
with conn:
print[f"Connected by {addr}"]
while True:
data = conn.recv[1024]
if not data:
break
conn.sendall[data]
436, will most likely be different when you run it on your machineViewing Socket State
Để xem trạng thái hiện tại của ổ cắm trên máy chủ của bạn, hãy sử dụng
# echo-server.py
# ...
with socket.socket[socket.AF_INET, socket.SOCK_STREAM] as s:
s.bind[[HOST, PORT]]
s.listen[]
conn, addr = s.accept[]
with conn:
print[f"Connected by {addr}"]
while True:
data = conn.recv[1024]
if not data:
break
conn.sendall[data]
437. Nó có sẵn theo mặc định trên macOS, Linux và WindowsĐây là đầu ra netstat từ macOS sau khi khởi động máy chủ
# echo-server.py
# ...
with socket.socket[socket.AF_INET, socket.SOCK_STREAM] as s:
s.bind[[HOST, PORT]]
s.listen[]
conn, addr = s.accept[]
with conn:
print[f"Connected by {addr}"]
while True:
data = conn.recv[1024]
if not data:
break
conn.sendall[data]
40Notice that
# echo-server.py
# ...
with socket.socket[socket.AF_INET, socket.SOCK_STREAM] as s:
s.bind[[HOST, PORT]]
s.listen[]
conn, addr = s.accept[]
with conn:
print[f"Connected by {addr}"]
while True:
data = conn.recv[1024]
if not data:
break
conn.sendall[data]
438 is # echo-server.py
# ...
with socket.socket[socket.AF_INET, socket.SOCK_STREAM] as s:
s.bind[[HOST, PORT]]
s.listen[]
conn, addr = s.accept[]
with conn:
print[f"Connected by {addr}"]
while True:
data = conn.recv[1024]
if not data:
break
conn.sendall[data]
439. If # echo-server.py
# ...
with socket.socket[socket.AF_INET, socket.SOCK_STREAM] as s:
s.bind[[HOST, PORT]]
s.listen[]
conn, addr = s.accept[]
with conn:
print[f"Connected by {addr}"]
while True:
data = conn.recv[1024]
if not data:
break
conn.sendall[data]
440 had used # echo-server.py
# ...
with socket.socket[socket.AF_INET, socket.SOCK_STREAM] as s:
s.bind[[HOST, PORT]]
s.listen[]
conn, addr = s.accept[]
with conn:
print[f"Connected by {addr}"]
while True:
data = conn.recv[1024]
if not data:
break
conn.sendall[data]
441 instead of # echo-server.py
# ...
with socket.socket[socket.AF_INET, socket.SOCK_STREAM] as s:
s.bind[[HOST, PORT]]
s.listen[]
conn, addr = s.accept[]
with conn:
print[f"Connected by {addr}"]
while True:
data = conn.recv[1024]
if not data:
break
conn.sendall[data]
442, netstat would show this# echo-server.py
# ...
with socket.socket[socket.AF_INET, socket.SOCK_STREAM] as s:
s.bind[[HOST, PORT]]
s.listen[]
conn, addr = s.accept[]
with conn:
print[f"Connected by {addr}"]
while True:
data = conn.recv[1024]
if not data:
break
conn.sendall[data]
41# echo-server.py
# ...
with socket.socket[socket.AF_INET, socket.SOCK_STREAM] as s:
s.bind[[HOST, PORT]]
s.listen[]
conn, addr = s.accept[]
with conn:
print[f"Connected by {addr}"]
while True:
data = conn.recv[1024]
if not data:
break
conn.sendall[data]
438 là # echo-server.py
# ...
with socket.socket[socket.AF_INET, socket.SOCK_STREAM] as s:
s.bind[[HOST, PORT]]
s.listen[]
conn, addr = s.accept[]
with conn:
print[f"Connected by {addr}"]
while True:
data = conn.recv[1024]
if not data:
break
conn.sendall[data]
444, có nghĩa là tất cả các giao diện máy chủ có sẵn hỗ trợ họ địa chỉ sẽ được sử dụng để chấp nhận các kết nối đến. Trong ví dụ này, # echo-server.py
# ...
with socket.socket[socket.AF_INET, socket.SOCK_STREAM] as s:
s.bind[[HOST, PORT]]
s.listen[]
conn, addr = s.accept[]
with conn:
print[f"Connected by {addr}"]
while True:
data = conn.recv[1024]
if not data:
break
conn.sendall[data]
36 đã được sử dụng [IPv4] trong lệnh gọi tới $ python echo-server.py
8. Bạn có thể thấy điều này trong cột # echo-server.py
# ...
with socket.socket[socket.AF_INET, socket.SOCK_STREAM] as s:
s.bind[[HOST, PORT]]
s.listen[]
conn, addr = s.accept[]
with conn:
print[f"Connected by {addr}"]
while True:
data = conn.recv[1024]
if not data:
break
conn.sendall[data]
447. # echo-server.py
# ...
with socket.socket[socket.AF_INET, socket.SOCK_STREAM] as s:
s.bind[[HOST, PORT]]
s.listen[]
conn, addr = s.accept[]
with conn:
print[f"Connected by {addr}"]
while True:
data = conn.recv[1024]
if not data:
break
conn.sendall[data]
448Đầu ra ở trên được cắt bớt để chỉ hiển thị máy chủ tiếng vang. Bạn có thể sẽ thấy nhiều đầu ra hơn, tùy thuộc vào hệ thống mà bạn đang chạy nó. Những điều cần chú ý là các cột
# echo-server.py
# ...
with socket.socket[socket.AF_INET, socket.SOCK_STREAM] as s:
s.bind[[HOST, PORT]]
s.listen[]
conn, addr = s.accept[]
with conn:
print[f"Connected by {addr}"]
while True:
data = conn.recv[1024]
if not data:
break
conn.sendall[data]
447, # echo-server.py
# ...
with socket.socket[socket.AF_INET, socket.SOCK_STREAM] as s:
s.bind[[HOST, PORT]]
s.listen[]
conn, addr = s.accept[]
with conn:
print[f"Connected by {addr}"]
while True:
data = conn.recv[1024]
if not data:
break
conn.sendall[data]
438 và # echo-server.py
# ...
with socket.socket[socket.AF_INET, socket.SOCK_STREAM] as s:
s.bind[[HOST, PORT]]
s.listen[]
conn, addr = s.accept[]
with conn:
print[f"Connected by {addr}"]
while True:
data = conn.recv[1024]
if not data:
break
conn.sendall[data]
451. Trong ví dụ cuối cùng ở trên, netstat cho thấy máy chủ echo đang sử dụng ổ cắm IPv4 TCP [# echo-server.py
# ...
with socket.socket[socket.AF_INET, socket.SOCK_STREAM] as s:
s.bind[[HOST, PORT]]
s.listen[]
conn, addr = s.accept[]
with conn:
print[f"Connected by {addr}"]
while True:
data = conn.recv[1024]
if not data:
break
conn.sendall[data]
448], trên cổng 65432 trên tất cả các giao diện [# echo-server.py
# ...
with socket.socket[socket.AF_INET, socket.SOCK_STREAM] as s:
s.bind[[HOST, PORT]]
s.listen[]
conn, addr = s.accept[]
with conn:
print[f"Connected by {addr}"]
while True:
data = conn.recv[1024]
if not data:
break
conn.sendall[data]
444] và nó đang ở trạng thái lắng nghe [# echo-server.py
# ...
with socket.socket[socket.AF_INET, socket.SOCK_STREAM] as s:
s.bind[[HOST, PORT]]
s.listen[]
conn, addr = s.accept[]
with conn:
print[f"Connected by {addr}"]
while True:
data = conn.recv[1024]
if not data:
break
conn.sendall[data]
454]Một cách khác để truy cập điều này, cùng với thông tin hữu ích bổ sung, là sử dụng
# echo-server.py
# ...
with socket.socket[socket.AF_INET, socket.SOCK_STREAM] as s:
s.bind[[HOST, PORT]]
s.listen[]
conn, addr = s.accept[]
with conn:
print[f"Connected by {addr}"]
while True:
data = conn.recv[1024]
if not data:
break
conn.sendall[data]
455 [liệt kê các tệp đang mở]. Nó có sẵn theo mặc định trên macOS và có thể được cài đặt trên Linux bằng trình quản lý gói của bạn, nếu nó chưa có# echo-server.py
# ...
with socket.socket[socket.AF_INET, socket.SOCK_STREAM] as s:
s.bind[[HOST, PORT]]
s.listen[]
conn, addr = s.accept[]
with conn:
print[f"Connected by {addr}"]
while True:
data = conn.recv[1024]
if not data:
break
conn.sendall[data]
42# echo-server.py
# ...
with socket.socket[socket.AF_INET, socket.SOCK_STREAM] as s:
s.bind[[HOST, PORT]]
s.listen[]
conn, addr = s.accept[]
with conn:
print[f"Connected by {addr}"]
while True:
data = conn.recv[1024]
if not data:
break
conn.sendall[data]
455 cung cấp cho bạn # echo-server.py
# ...
with socket.socket[socket.AF_INET, socket.SOCK_STREAM] as s:
s.bind[[HOST, PORT]]
s.listen[]
conn, addr = s.accept[]
with conn:
print[f"Connected by {addr}"]
while True:
data = conn.recv[1024]
if not data:
break
conn.sendall[data]
457, # echo-server.py
# ...
with socket.socket[socket.AF_INET, socket.SOCK_STREAM] as s:
s.bind[[HOST, PORT]]
s.listen[]
conn, addr = s.accept[]
with conn:
print[f"Connected by {addr}"]
while True:
data = conn.recv[1024]
if not data:
break
conn.sendall[data]
458 [ID quy trình] và # echo-server.py
# ...
with socket.socket[socket.AF_INET, socket.SOCK_STREAM] as s:
s.bind[[HOST, PORT]]
s.listen[]
conn, addr = s.accept[]
with conn:
print[f"Connected by {addr}"]
while True:
data = conn.recv[1024]
if not data:
break
conn.sendall[data]
459 [ID người dùng] của ổ cắm Internet đang mở khi được sử dụng với tùy chọn # echo-server.py
# ...
with socket.socket[socket.AF_INET, socket.SOCK_STREAM] as s:
s.bind[[HOST, PORT]]
s.listen[]
conn, addr = s.accept[]
with conn:
print[f"Connected by {addr}"]
while True:
data = conn.recv[1024]
if not data:
break
conn.sendall[data]
460. Trên đây là quá trình echo server# echo-server.py
# ...
with socket.socket[socket.AF_INET, socket.SOCK_STREAM] as s:
s.bind[[HOST, PORT]]
s.listen[]
conn, addr = s.accept[]
with conn:
print[f"Connected by {addr}"]
while True:
data = conn.recv[1024]
if not data:
break
conn.sendall[data]
437 và # echo-server.py
# ...
with socket.socket[socket.AF_INET, socket.SOCK_STREAM] as s:
s.bind[[HOST, PORT]]
s.listen[]
conn, addr = s.accept[]
with conn:
print[f"Connected by {addr}"]
while True:
data = conn.recv[1024]
if not data:
break
conn.sendall[data]
455 có rất nhiều tùy chọn khả dụng và khác nhau tùy thuộc vào hệ điều hành mà bạn đang chạy chúng. Kiểm tra trang # echo-server.py
# ...
with socket.socket[socket.AF_INET, socket.SOCK_STREAM] as s:
s.bind[[HOST, PORT]]
s.listen[]
conn, addr = s.accept[]
with conn:
print[f"Connected by {addr}"]
while True:
data = conn.recv[1024]
if not data:
break
conn.sendall[data]
463 hoặc tài liệu cho cả hai. Họ chắc chắn đáng để dành một chút thời gian và tìm hiểu. Bạn sẽ được thưởng. Trên macOS và Linux, hãy sử dụng # echo-server.py
# ...
with socket.socket[socket.AF_INET, socket.SOCK_STREAM] as s:
s.bind[[HOST, PORT]]
s.listen[]
conn, addr = s.accept[]
with conn:
print[f"Connected by {addr}"]
while True:
data = conn.recv[1024]
if not data:
break
conn.sendall[data]
464 và # echo-server.py
# ...
with socket.socket[socket.AF_INET, socket.SOCK_STREAM] as s:
s.bind[[HOST, PORT]]
s.listen[]
conn, addr = s.accept[]
with conn:
print[f"Connected by {addr}"]
while True:
data = conn.recv[1024]
if not data:
break
conn.sendall[data]
465. Đối với Windows, hãy sử dụng # echo-server.py
# ...
with socket.socket[socket.AF_INET, socket.SOCK_STREAM] as s:
s.bind[[HOST, PORT]]
s.listen[]
conn, addr = s.accept[]
with conn:
print[f"Connected by {addr}"]
while True:
data = conn.recv[1024]
if not data:
break
conn.sendall[data]
466Đây là một lỗi phổ biến mà bạn sẽ gặp phải khi thử kết nối với một cổng không có ổ cắm nghe
# echo-server.py
# ...
with socket.socket[socket.AF_INET, socket.SOCK_STREAM] as s:
s.bind[[HOST, PORT]]
s.listen[]
conn, addr = s.accept[]
with conn:
print[f"Connected by {addr}"]
while True:
data = conn.recv[1024]
if not data:
break
conn.sendall[data]
43Số cổng được chỉ định sai hoặc máy chủ không chạy. Hoặc có thể có tường lửa trong đường dẫn đang chặn kết nối, điều này có thể dễ dàng bị quên. You may also see the error
# echo-server.py
# ...
with socket.socket[socket.AF_INET, socket.SOCK_STREAM] as s:
s.bind[[HOST, PORT]]
s.listen[]
conn, addr = s.accept[]
with conn:
print[f"Connected by {addr}"]
while True:
data = conn.recv[1024]
if not data:
break
conn.sendall[data]
467. Get a firewall rule added that allows the client to connect to the TCP portCó một danh sách các lỗi phổ biến trong phần tham khảo
Remove adssự cố truyền thông
Bây giờ bạn sẽ xem xét kỹ hơn cách máy khách và máy chủ giao tiếp với nhau
Khi sử dụng giao diện loopback [địa chỉ IPv4
# echo-server.py
# ...
with socket.socket[socket.AF_INET, socket.SOCK_STREAM] as s:
s.bind[[HOST, PORT]]
s.listen[]
conn, addr = s.accept[]
with conn:
print[f"Connected by {addr}"]
while True:
data = conn.recv[1024]
if not data:
break
conn.sendall[data]
400 hoặc địa chỉ IPv6 # echo-server.py
# ...
with socket.socket[socket.AF_INET, socket.SOCK_STREAM] as s:
s.bind[[HOST, PORT]]
s.listen[]
conn, addr = s.accept[]
with conn:
print[f"Connected by {addr}"]
while True:
data = conn.recv[1024]
if not data:
break
conn.sendall[data]
469], dữ liệu không bao giờ rời khỏi máy chủ hoặc chạm vào mạng bên ngoài. Trong sơ đồ trên, giao diện loopback được chứa bên trong máy chủ. This represents the internal nature of the loopback interface and shows that connections and data that transit it are local to the host. This is why you’ll also hear the loopback interface and IP address # echo-server.py
# ...
with socket.socket[socket.AF_INET, socket.SOCK_STREAM] as s:
s.bind[[HOST, PORT]]
s.listen[]
conn, addr = s.accept[]
with conn:
print[f"Connected by {addr}"]
while True:
data = conn.recv[1024]
if not data:
break
conn.sendall[data]
400 or # echo-server.py
# ...
with socket.socket[socket.AF_INET, socket.SOCK_STREAM] as s:
s.bind[[HOST, PORT]]
s.listen[]
conn, addr = s.accept[]
with conn:
print[f"Connected by {addr}"]
while True:
data = conn.recv[1024]
if not data:
break
conn.sendall[data]
469 referred to as “localhost. ”Các ứng dụng sử dụng giao diện loopback để liên lạc với các quy trình khác đang chạy trên máy chủ và để bảo mật và cách ly với mạng bên ngoài. Bởi vì nó là nội bộ và chỉ có thể truy cập từ bên trong máy chủ nên nó không bị lộ
You can see this in action if you have an application server that uses its own private database. Nếu nó không phải là cơ sở dữ liệu được sử dụng bởi các máy chủ khác, thì nó có thể được định cấu hình để chỉ lắng nghe các kết nối trên giao diện loopback. Nếu đây là trường hợp, các máy chủ khác trên mạng không thể kết nối với nó
Khi bạn sử dụng địa chỉ IP khác với
# echo-server.py
# ...
with socket.socket[socket.AF_INET, socket.SOCK_STREAM] as s:
s.bind[[HOST, PORT]]
s.listen[]
conn, addr = s.accept[]
with conn:
print[f"Connected by {addr}"]
while True:
data = conn.recv[1024]
if not data:
break
conn.sendall[data]
400 hoặc # echo-server.py
# ...
with socket.socket[socket.AF_INET, socket.SOCK_STREAM] as s:
s.bind[[HOST, PORT]]
s.listen[]
conn, addr = s.accept[]
with conn:
print[f"Connected by {addr}"]
while True:
data = conn.recv[1024]
if not data:
break
conn.sendall[data]
469 trong các ứng dụng của mình, địa chỉ đó có thể bị ràng buộc với giao diện Ethernet được kết nối với mạng bên ngoài. This is your gateway to other hosts outside of your “localhost” kingdomHãy cẩn thận ở ngoài đó. Đó là một thế giới khó chịu, tàn nhẫn. Be sure to read the section Using Hostnames before venturing from the safe confines of “localhost. ” Có một lưu ý bảo mật áp dụng ngay cả khi bạn không sử dụng tên máy chủ mà chỉ sử dụng địa chỉ IP
Xử lý nhiều kết nối
Máy chủ echo chắc chắn có những hạn chế của nó. Cái lớn nhất là nó chỉ phục vụ một khách hàng và sau đó thoát ra. Ứng dụng khách echo cũng có giới hạn này, nhưng có một vấn đề khác. Khi máy khách sử dụng
# echo-server.py
# ...
with socket.socket[socket.AF_INET, socket.SOCK_STREAM] as s:
s.bind[[HOST, PORT]]
s.listen[]
conn, addr = s.accept[]
with conn:
print[f"Connected by {addr}"]
while True:
data = conn.recv[1024]
if not data:
break
conn.sendall[data]
432, có thể nó sẽ chỉ trả về một byte, # echo-server.py
# ...
with socket.socket[socket.AF_INET, socket.SOCK_STREAM] as s:
s.bind[[HOST, PORT]]
s.listen[]
conn, addr = s.accept[]
with conn:
print[f"Connected by {addr}"]
while True:
data = conn.recv[1024]
if not data:
break
conn.sendall[data]
475 từ # echo-server.py
# ...
with socket.socket[socket.AF_INET, socket.SOCK_STREAM] as s:
s.bind[[HOST, PORT]]
s.listen[]
conn, addr = s.accept[]
with conn:
print[f"Connected by {addr}"]
while True:
data = conn.recv[1024]
if not data:
break
conn.sendall[data]
476# echo-server.py
# ...
with socket.socket[socket.AF_INET, socket.SOCK_STREAM] as s:
s.bind[[HOST, PORT]]
s.listen[]
conn, addr = s.accept[]
with conn:
print[f"Connected by {addr}"]
while True:
data = conn.recv[1024]
if not data:
break
conn.sendall[data]
44Đối số
# echo-server.py
# ...
with socket.socket[socket.AF_INET, socket.SOCK_STREAM] as s:
s.bind[[HOST, PORT]]
s.listen[]
conn, addr = s.accept[]
with conn:
print[f"Connected by {addr}"]
while True:
data = conn.recv[1024]
if not data:
break
conn.sendall[data]
477 của # echo-server.py
# ...
with socket.socket[socket.AF_INET, socket.SOCK_STREAM] as s:
s.bind[[HOST, PORT]]
s.listen[]
conn, addr = s.accept[]
with conn:
print[f"Connected by {addr}"]
while True:
data = conn.recv[1024]
if not data:
break
conn.sendall[data]
405 được sử dụng ở trên là lượng dữ liệu tối đa được nhận cùng một lúc. Điều đó không có nghĩa là # echo-server.py
# ...
with socket.socket[socket.AF_INET, socket.SOCK_STREAM] as s:
s.bind[[HOST, PORT]]
s.listen[]
conn, addr = s.accept[]
with conn:
print[f"Connected by {addr}"]
while True:
data = conn.recv[1024]
if not data:
break
conn.sendall[data]
5 sẽ trả về # echo-server.py
# ...
with socket.socket[socket.AF_INET, socket.SOCK_STREAM] as s:
s.bind[[HOST, PORT]]
s.listen[]
conn, addr = s.accept[]
with conn:
print[f"Connected by {addr}"]
while True:
data = conn.recv[1024]
if not data:
break
conn.sendall[data]
405 bytePhương thức
# echo-server.py
# ...
with socket.socket[socket.AF_INET, socket.SOCK_STREAM] as s:
s.bind[[HOST, PORT]]
s.listen[]
conn, addr = s.accept[]
with conn:
print[f"Connected by {addr}"]
while True:
data = conn.recv[1024]
if not data:
break
conn.sendall[data]
4 cũng hoạt động theo cách này. Nó trả về số byte đã gửi, có thể nhỏ hơn kích thước của dữ liệu được truyền vào. Bạn chịu trách nhiệm kiểm tra điều này và gọi cho # echo-server.py
# ...
with socket.socket[socket.AF_INET, socket.SOCK_STREAM] as s:
s.bind[[HOST, PORT]]
s.listen[]
conn, addr = s.accept[]
with conn:
print[f"Connected by {addr}"]
while True:
data = conn.recv[1024]
if not data:
break
conn.sendall[data]
4 nhiều lần nếu cần để gửi tất cả dữ liệu“Các ứng dụng có trách nhiệm kiểm tra xem tất cả dữ liệu đã được gửi chưa; . " [Nguồn]
Trong ví dụ trên, bạn tránh phải làm điều này bằng cách sử dụng
# echo-server.py
# ...
with socket.socket[socket.AF_INET, socket.SOCK_STREAM] as s:
s.bind[[HOST, PORT]]
s.listen[]
conn, addr = s.accept[]
with conn:
print[f"Connected by {addr}"]
while True:
data = conn.recv[1024]
if not data:
break
conn.sendall[data]
483“Không giống như send[], phương thức này tiếp tục gửi dữ liệu từ byte cho đến khi tất cả dữ liệu đã được gửi hoặc xảy ra lỗi.
484 được trả lại khi thành công. " [Nguồn]# echo-server.py # ... with socket.socket[socket.AF_INET, socket.SOCK_STREAM] as s: s.bind[[HOST, PORT]] s.listen[] conn, addr = s.accept[] with conn: print[f"Connected by {addr}"] while True: data = conn.recv[1024] if not data: break conn.sendall[data]
Bạn có hai vấn đề tại thời điểm này
- Làm thế nào để bạn xử lý nhiều kết nối đồng thời?
- Bạn cần gọi
4 và# echo-server.py # ... with socket.socket[socket.AF_INET, socket.SOCK_STREAM] as s: s.bind[[HOST, PORT]] s.listen[] conn, addr = s.accept[] with conn: print[f"Connected by {addr}"] while True: data = conn.recv[1024] if not data: break conn.sendall[data]
5 cho đến khi tất cả dữ liệu được gửi hoặc nhận# echo-server.py # ... with socket.socket[socket.AF_INET, socket.SOCK_STREAM] as s: s.bind[[HOST, PORT]] s.listen[] conn, addr = s.accept[] with conn: print[f"Connected by {addr}"] while True: data = conn.recv[1024] if not data: break conn.sendall[data]
Bạn có thể làm gì? . Một cách tiếp cận phổ biến là sử dụng I/O không đồng bộ.
# echo-server.py
# ...
with socket.socket[socket.AF_INET, socket.SOCK_STREAM] as s:
s.bind[[HOST, PORT]]
s.listen[]
conn, addr = s.accept[]
with conn:
print[f"Connected by {addr}"]
while True:
data = conn.recv[1024]
if not data:
break
conn.sendall[data]
487 was introduced into the standard library in Python 3. 4. Sự lựa chọn truyền thống là sử dụng chủ đềRắc rối với đồng thời là rất khó để hiểu đúng. Có nhiều điều tế nhị để xem xét và đề phòng. All it takes is for one of these to manifest itself and your application may suddenly fail in not-so-subtle ways
Điều này không có nghĩa là làm bạn sợ hãi khi học và sử dụng lập trình đồng thời. Nếu ứng dụng của bạn cần mở rộng quy mô, thì đó là điều cần thiết nếu bạn muốn sử dụng nhiều bộ xử lý hoặc một lõi. Tuy nhiên, đối với hướng dẫn này, bạn sẽ sử dụng thứ gì đó thậm chí còn truyền thống hơn các chủ đề và dễ suy luận hơn. Bạn sẽ sử dụng các cuộc gọi hệ thống.
# echo-server.py
# ...
with socket.socket[socket.AF_INET, socket.SOCK_STREAM] as s:
s.bind[[HOST, PORT]]
s.listen[]
conn, addr = s.accept[]
with conn:
print[f"Connected by {addr}"]
while True:
data = conn.recv[1024]
if not data:
break
conn.sendall[data]
488Phương pháp
# echo-server.py
# ...
with socket.socket[socket.AF_INET, socket.SOCK_STREAM] as s:
s.bind[[HOST, PORT]]
s.listen[]
conn, addr = s.accept[]
with conn:
print[f"Connected by {addr}"]
while True:
data = conn.recv[1024]
if not data:
break
conn.sendall[data]
488 cho phép bạn kiểm tra việc hoàn thành I/O trên nhiều ổ cắm. Vì vậy, bạn có thể gọi # echo-server.py
# ...
with socket.socket[socket.AF_INET, socket.SOCK_STREAM] as s:
s.bind[[HOST, PORT]]
s.listen[]
conn, addr = s.accept[]
with conn:
print[f"Connected by {addr}"]
while True:
data = conn.recv[1024]
if not data:
break
conn.sendall[data]
488 để xem ổ cắm nào có sẵn I/O để đọc và/hoặc ghi. Nhưng đây là Python, vì vậy có nhiều hơn nữa. Bạn sẽ sử dụng mô-đun bộ chọn trong thư viện chuẩn để triển khai hiệu quả nhất được sử dụng, bất kể hệ điều hành bạn đang chạy trên đó là gì“Mô-đun này cho phép ghép kênh I/O ở mức độ cao và hiệu quả, được xây dựng dựa trên các nguyên mẫu mô-đun đã chọn. Thay vào đó, người dùng được khuyến khích sử dụng mô-đun này, trừ khi họ muốn kiểm soát chính xác các nguyên mẫu cấp hệ điều hành được sử dụng. " [Nguồn]
Tuy nhiên, bằng cách sử dụng
# echo-server.py
# ...
with socket.socket[socket.AF_INET, socket.SOCK_STREAM] as s:
s.bind[[HOST, PORT]]
s.listen[]
conn, addr = s.accept[]
with conn:
print[f"Connected by {addr}"]
while True:
data = conn.recv[1024]
if not data:
break
conn.sendall[data]
488, bạn không thể chạy đồng thời. Điều đó nói rằng, tùy thuộc vào khối lượng công việc của bạn, phương pháp này có thể vẫn còn rất nhanh. It depends on what your application needs to do when it services a request, and the number of clients it needs to support# echo-server.py
# ...
with socket.socket[socket.AF_INET, socket.SOCK_STREAM] as s:
s.bind[[HOST, PORT]]
s.listen[]
conn, addr = s.accept[]
with conn:
print[f"Connected by {addr}"]
while True:
data = conn.recv[1024]
if not data:
break
conn.sendall[data]
487 sử dụng đa nhiệm hợp tác đơn luồng và vòng lặp sự kiện để quản lý tác vụ. Với # echo-server.py
# ...
with socket.socket[socket.AF_INET, socket.SOCK_STREAM] as s:
s.bind[[HOST, PORT]]
s.listen[]
conn, addr = s.accept[]
with conn:
print[f"Connected by {addr}"]
while True:
data = conn.recv[1024]
if not data:
break
conn.sendall[data]
488, bạn sẽ viết phiên bản vòng lặp sự kiện của riêng mình, mặc dù đơn giản và đồng bộ hơn. Khi sử dụng nhiều luồng, mặc dù bạn có đồng thời, nhưng hiện tại bạn phải sử dụng GIL [Khóa phiên dịch toàn cầu] với CPython và PyPy. Điều này hạn chế hiệu quả số lượng công việc bạn có thể làm song songĐây là tất cả để nói rằng sử dụng
# echo-server.py
# ...
with socket.socket[socket.AF_INET, socket.SOCK_STREAM] as s:
s.bind[[HOST, PORT]]
s.listen[]
conn, addr = s.accept[]
with conn:
print[f"Connected by {addr}"]
while True:
data = conn.recv[1024]
if not data:
break
conn.sendall[data]
488 có thể là một lựa chọn hoàn toàn tốt. Đừng cảm thấy như bạn phải sử dụng # echo-server.py
# ...
with socket.socket[socket.AF_INET, socket.SOCK_STREAM] as s:
s.bind[[HOST, PORT]]
s.listen[]
conn, addr = s.accept[]
with conn:
print[f"Connected by {addr}"]
while True:
data = conn.recv[1024]
if not data:
break
conn.sendall[data]
487, chủ đề hoặc thư viện không đồng bộ mới nhất. Thông thường, trong ứng dụng mạng, ứng dụng của bạn vẫn bị ràng buộc I/O. nó có thể đang đợi trên mạng cục bộ, các điểm cuối ở phía bên kia của mạng, để ghi đĩa, v.v.If you’re getting requests from clients that initiate CPU bound work, look at the concurrent. mô-đun tương lai. Nó chứa lớp ProcessPoolExecutor, sử dụng một nhóm các quy trình để thực hiện các lệnh gọi không đồng bộ
Nếu bạn sử dụng nhiều quy trình, hệ điều hành có thể lên lịch mã Python của bạn để chạy song song trên nhiều bộ xử lý hoặc lõi mà không cần GIL. Để có ý tưởng và cảm hứng, hãy xem buổi nói chuyện về PyCon John Reese - Tư duy bên ngoài GIL với AsyncIO và Đa xử lý - PyCon 2018
Trong phần tiếp theo, bạn sẽ xem xét các ví dụ về máy chủ và máy khách giải quyết những vấn đề này. Họ sử dụng
# echo-server.py
# ...
with socket.socket[socket.AF_INET, socket.SOCK_STREAM] as s:
s.bind[[HOST, PORT]]
s.listen[]
conn, addr = s.accept[]
with conn:
print[f"Connected by {addr}"]
while True:
data = conn.recv[1024]
if not data:
break
conn.sendall[data]
488 để xử lý đồng thời nhiều kết nối và gọi # echo-server.py
# ...
with socket.socket[socket.AF_INET, socket.SOCK_STREAM] as s:
s.bind[[HOST, PORT]]
s.listen[]
conn, addr = s.accept[]
with conn:
print[f"Connected by {addr}"]
while True:
data = conn.recv[1024]
if not data:
break
conn.sendall[data]
4 và # echo-server.py
# ...
with socket.socket[socket.AF_INET, socket.SOCK_STREAM] as s:
s.bind[[HOST, PORT]]
s.listen[]
conn, addr = s.accept[]
with conn:
print[f"Connected by {addr}"]
while True:
data = conn.recv[1024]
if not data:
break
conn.sendall[data]
5 nhiều lần nếu cầnRemove adsMáy khách và máy chủ đa kết nối
Trong hai phần tiếp theo, bạn sẽ tạo một máy chủ và máy khách xử lý nhiều kết nối bằng cách sử dụng đối tượng
# echo-server.py
# ...
with socket.socket[socket.AF_INET, socket.SOCK_STREAM] as s:
s.bind[[HOST, PORT]]
s.listen[]
conn, addr = s.accept[]
with conn:
print[f"Connected by {addr}"]
while True:
data = conn.recv[1024]
if not data:
break
conn.sendall[data]
499 được tạo từ mô-đun bộ chọnMulti-Connection Server
Đầu tiên, hướng sự chú ý của bạn đến máy chủ đa kết nối. Phần đầu tiên thiết lập ổ cắm nghe
# echo-server.py
# ...
with socket.socket[socket.AF_INET, socket.SOCK_STREAM] as s:
s.bind[[HOST, PORT]]
s.listen[]
conn, addr = s.accept[]
with conn:
print[f"Connected by {addr}"]
while True:
data = conn.recv[1024]
if not data:
break
conn.sendall[data]
45Sự khác biệt lớn nhất giữa máy chủ này và máy chủ echo là lệnh gọi tới
# echo-server.py
# ...
with socket.socket[socket.AF_INET, socket.SOCK_STREAM] as s:
s.bind[[HOST, PORT]]
s.listen[]
conn, addr = s.accept[]
with conn:
print[f"Connected by {addr}"]
while True:
data = conn.recv[1024]
if not data:
break
conn.sendall[data]
900 để định cấu hình ổ cắm ở chế độ không chặn. Các cuộc gọi đến ổ cắm này sẽ không còn bị chặn. Khi nó được sử dụng với # echo-server.py
# ...
with socket.socket[socket.AF_INET, socket.SOCK_STREAM] as s:
s.bind[[HOST, PORT]]
s.listen[]
conn, addr = s.accept[]
with conn:
print[f"Connected by {addr}"]
while True:
data = conn.recv[1024]
if not data:
break
conn.sendall[data]
901, như bạn sẽ thấy bên dưới, bạn có thể đợi các sự kiện trên một hoặc nhiều ổ cắm, sau đó đọc và ghi dữ liệu khi sẵn sàng# echo-server.py
# ...
with socket.socket[socket.AF_INET, socket.SOCK_STREAM] as s:
s.bind[[HOST, PORT]]
s.listen[]
conn, addr = s.accept[]
with conn:
print[f"Connected by {addr}"]
while True:
data = conn.recv[1024]
if not data:
break
conn.sendall[data]
902 đăng ký ổ cắm sẽ được giám sát với # echo-server.py
# ...
with socket.socket[socket.AF_INET, socket.SOCK_STREAM] as s:
s.bind[[HOST, PORT]]
s.listen[]
conn, addr = s.accept[]
with conn:
print[f"Connected by {addr}"]
while True:
data = conn.recv[1024]
if not data:
break
conn.sendall[data]
901 cho các sự kiện mà bạn quan tâm. Đối với ổ cắm nghe, bạn muốn đọc các sự kiện. # echo-server.py
# ...
with socket.socket[socket.AF_INET, socket.SOCK_STREAM] as s:
s.bind[[HOST, PORT]]
s.listen[]
conn, addr = s.accept[]
with conn:
print[f"Connected by {addr}"]
while True:
data = conn.recv[1024]
if not data:
break
conn.sendall[data]
904Để lưu trữ bất kỳ dữ liệu tùy ý nào bạn muốn cùng với ổ cắm, bạn sẽ sử dụng
# echo-server.py
# ...
with socket.socket[socket.AF_INET, socket.SOCK_STREAM] as s:
s.bind[[HOST, PORT]]
s.listen[]
conn, addr = s.accept[]
with conn:
print[f"Connected by {addr}"]
while True:
data = conn.recv[1024]
if not data:
break
conn.sendall[data]
905. Nó được trả lại khi # echo-server.py
# ...
with socket.socket[socket.AF_INET, socket.SOCK_STREAM] as s:
s.bind[[HOST, PORT]]
s.listen[]
conn, addr = s.accept[]
with conn:
print[f"Connected by {addr}"]
while True:
data = conn.recv[1024]
if not data:
break
conn.sendall[data]
488 trả về. Bạn sẽ sử dụng # echo-server.py
# ...
with socket.socket[socket.AF_INET, socket.SOCK_STREAM] as s:
s.bind[[HOST, PORT]]
s.listen[]
conn, addr = s.accept[]
with conn:
print[f"Connected by {addr}"]
while True:
data = conn.recv[1024]
if not data:
break
conn.sendall[data]
905 để theo dõi những gì đã được gửi và nhận trên ổ cắmTiếp theo là vòng lặp sự kiện
# echo-server.py
# ...
with socket.socket[socket.AF_INET, socket.SOCK_STREAM] as s:
s.bind[[HOST, PORT]]
s.listen[]
conn, addr = s.accept[]
with conn:
print[f"Connected by {addr}"]
while True:
data = conn.recv[1024]
if not data:
break
conn.sendall[data]
46# echo-server.py
# ...
with socket.socket[socket.AF_INET, socket.SOCK_STREAM] as s:
s.bind[[HOST, PORT]]
s.listen[]
conn, addr = s.accept[]
with conn:
print[f"Connected by {addr}"]
while True:
data = conn.recv[1024]
if not data:
break
conn.sendall[data]
908 blocks until there are sockets ready for I/O. Nó trả về một danh sách các bộ dữ liệu, một bộ cho mỗi ổ cắm. Mỗi bộ dữ liệu chứa một # echo-server.py
# ...
with socket.socket[socket.AF_INET, socket.SOCK_STREAM] as s:
s.bind[[HOST, PORT]]
s.listen[]
conn, addr = s.accept[]
with conn:
print[f"Connected by {addr}"]
while True:
data = conn.recv[1024]
if not data:
break
conn.sendall[data]
909 và một # echo-server.py
# ...
with socket.socket[socket.AF_INET, socket.SOCK_STREAM] as s:
s.bind[[HOST, PORT]]
s.listen[]
conn, addr = s.accept[]
with conn:
print[f"Connected by {addr}"]
while True:
data = conn.recv[1024]
if not data:
break
conn.sendall[data]
910. # echo-server.py
# ...
with socket.socket[socket.AF_INET, socket.SOCK_STREAM] as s:
s.bind[[HOST, PORT]]
s.listen[]
conn, addr = s.accept[]
with conn:
print[f"Connected by {addr}"]
while True:
data = conn.recv[1024]
if not data:
break
conn.sendall[data]
909 là SelectorKey # echo-server.py
# ...
with socket.socket[socket.AF_INET, socket.SOCK_STREAM] as s:
s.bind[[HOST, PORT]]
s.listen[]
conn, addr = s.accept[]
with conn:
print[f"Connected by {addr}"]
while True:
data = conn.recv[1024]
if not data:
break
conn.sendall[data]
912 có chứa thuộc tính # echo-server.py
# ...
with socket.socket[socket.AF_INET, socket.SOCK_STREAM] as s:
s.bind[[HOST, PORT]]
s.listen[]
conn, addr = s.accept[]
with conn:
print[f"Connected by {addr}"]
while True:
data = conn.recv[1024]
if not data:
break
conn.sendall[data]
913. # echo-server.py
# ...
with socket.socket[socket.AF_INET, socket.SOCK_STREAM] as s:
s.bind[[HOST, PORT]]
s.listen[]
conn, addr = s.accept[]
with conn:
print[f"Connected by {addr}"]
while True:
data = conn.recv[1024]
if not data:
break
conn.sendall[data]
914 là đối tượng ổ cắm và # echo-server.py
# ...
with socket.socket[socket.AF_INET, socket.SOCK_STREAM] as s:
s.bind[[HOST, PORT]]
s.listen[]
conn, addr = s.accept[]
with conn:
print[f"Connected by {addr}"]
while True:
data = conn.recv[1024]
if not data:
break
conn.sendall[data]
910 là mặt nạ sự kiện của các hoạt động đã sẵn sàngNếu
# echo-server.py
# ...
with socket.socket[socket.AF_INET, socket.SOCK_STREAM] as s:
s.bind[[HOST, PORT]]
s.listen[]
conn, addr = s.accept[]
with conn:
print[f"Connected by {addr}"]
while True:
data = conn.recv[1024]
if not data:
break
conn.sendall[data]
916 là # echo-server.py
# ...
with socket.socket[socket.AF_INET, socket.SOCK_STREAM] as s:
s.bind[[HOST, PORT]]
s.listen[]
conn, addr = s.accept[]
with conn:
print[f"Connected by {addr}"]
while True:
data = conn.recv[1024]
if not data:
break
conn.sendall[data]
484, thì bạn biết đó là từ ổ cắm đang nghe và bạn cần chấp nhận kết nối. Bạn sẽ gọi hàm # echo-server.py
# ...
with socket.socket[socket.AF_INET, socket.SOCK_STREAM] as s:
s.bind[[HOST, PORT]]
s.listen[]
conn, addr = s.accept[]
with conn:
print[f"Connected by {addr}"]
while True:
data = conn.recv[1024]
if not data:
break
conn.sendall[data]
918 của riêng mình để lấy đối tượng ổ cắm mới và đăng ký nó với bộ chọn. Bạn sẽ nhìn vào đó trong giây látNếu
# echo-server.py
# ...
with socket.socket[socket.AF_INET, socket.SOCK_STREAM] as s:
s.bind[[HOST, PORT]]
s.listen[]
conn, addr = s.accept[]
with conn:
print[f"Connected by {addr}"]
while True:
data = conn.recv[1024]
if not data:
break
conn.sendall[data]
916 không phải là # echo-server.py
# ...
with socket.socket[socket.AF_INET, socket.SOCK_STREAM] as s:
s.bind[[HOST, PORT]]
s.listen[]
conn, addr = s.accept[]
with conn:
print[f"Connected by {addr}"]
while True:
data = conn.recv[1024]
if not data:
break
conn.sendall[data]
484, thì bạn biết đó là ổ cắm máy khách đã được chấp nhận và bạn cần bảo dưỡng nó. Sau đó, # echo-server.py
# ...
with socket.socket[socket.AF_INET, socket.SOCK_STREAM] as s:
s.bind[[HOST, PORT]]
s.listen[]
conn, addr = s.accept[]
with conn:
print[f"Connected by {addr}"]
while True:
data = conn.recv[1024]
if not data:
break
conn.sendall[data]
921 được gọi với # echo-server.py
# ...
with socket.socket[socket.AF_INET, socket.SOCK_STREAM] as s:
s.bind[[HOST, PORT]]
s.listen[]
conn, addr = s.accept[]
with conn:
print[f"Connected by {addr}"]
while True:
data = conn.recv[1024]
if not data:
break
conn.sendall[data]
909 và # echo-server.py
# ...
with socket.socket[socket.AF_INET, socket.SOCK_STREAM] as s:
s.bind[[HOST, PORT]]
s.listen[]
conn, addr = s.accept[]
with conn:
print[f"Connected by {addr}"]
while True:
data = conn.recv[1024]
if not data:
break
conn.sendall[data]
910 làm đối số và đó là mọi thứ bạn cần để vận hành trên ổ cắmĐây là chức năng của hàm
# echo-server.py
# ...
with socket.socket[socket.AF_INET, socket.SOCK_STREAM] as s:
s.bind[[HOST, PORT]]
s.listen[]
conn, addr = s.accept[]
with conn:
print[f"Connected by {addr}"]
while True:
data = conn.recv[1024]
if not data:
break
conn.sendall[data]
918 của bạn# echo-server.py
# ...
with socket.socket[socket.AF_INET, socket.SOCK_STREAM] as s:
s.bind[[HOST, PORT]]
s.listen[]
conn, addr = s.accept[]
with conn:
print[f"Connected by {addr}"]
while True:
data = conn.recv[1024]
if not data:
break
conn.sendall[data]
47Bởi vì ổ cắm nghe đã được đăng ký cho sự kiện
# echo-server.py
# ...
with socket.socket[socket.AF_INET, socket.SOCK_STREAM] as s:
s.bind[[HOST, PORT]]
s.listen[]
conn, addr = s.accept[]
with conn:
print[f"Connected by {addr}"]
while True:
data = conn.recv[1024]
if not data:
break
conn.sendall[data]
904, nó sẽ sẵn sàng để đọc. Bạn gọi # echo-server.py
# ...
with socket.socket[socket.AF_INET, socket.SOCK_STREAM] as s:
s.bind[[HOST, PORT]]
s.listen[]
conn, addr = s.accept[]
with conn:
print[f"Connected by {addr}"]
while True:
data = conn.recv[1024]
if not data:
break
conn.sendall[data]
926 rồi gọi # echo-server.py
# ...
with socket.socket[socket.AF_INET, socket.SOCK_STREAM] as s:
s.bind[[HOST, PORT]]
s.listen[]
conn, addr = s.accept[]
with conn:
print[f"Connected by {addr}"]
while True:
data = conn.recv[1024]
if not data:
break
conn.sendall[data]
927 để đặt ổ cắm ở chế độ non-blockingHãy nhớ rằng, đây là mục tiêu chính trong phiên bản máy chủ này vì bạn không muốn nó bị chặn. Nếu nó chặn, thì toàn bộ máy chủ sẽ bị đình trệ cho đến khi nó hoạt động trở lại. Điều đó có nghĩa là các ổ cắm khác đang chờ mặc dù máy chủ không hoạt động tích cực. Đây là trạng thái “treo” đáng sợ mà bạn không muốn máy chủ của mình gặp phải
Tiếp theo, bạn tạo một đối tượng để chứa dữ liệu mà bạn muốn đưa vào cùng với ổ cắm bằng cách sử dụng
# echo-server.py
# ...
with socket.socket[socket.AF_INET, socket.SOCK_STREAM] as s:
s.bind[[HOST, PORT]]
s.listen[]
conn, addr = s.accept[]
with conn:
print[f"Connected by {addr}"]
while True:
data = conn.recv[1024]
if not data:
break
conn.sendall[data]
928. Bởi vì bạn muốn biết khi nào kết nối máy khách sẵn sàng để đọc và ghi, cả hai sự kiện đó đều được đặt bằng toán tử OR theo bit# echo-server.py
# ...
with socket.socket[socket.AF_INET, socket.SOCK_STREAM] as s:
s.bind[[HOST, PORT]]
s.listen[]
conn, addr = s.accept[]
with conn:
print[f"Connected by {addr}"]
while True:
data = conn.recv[1024]
if not data:
break
conn.sendall[data]
48Sau đó, các đối tượng mặt nạ, ổ cắm và dữ liệu của
# echo-server.py
# ...
with socket.socket[socket.AF_INET, socket.SOCK_STREAM] as s:
s.bind[[HOST, PORT]]
s.listen[]
conn, addr = s.accept[]
with conn:
print[f"Connected by {addr}"]
while True:
data = conn.recv[1024]
if not data:
break
conn.sendall[data]
929 được chuyển đến # echo-server.py
# ...
with socket.socket[socket.AF_INET, socket.SOCK_STREAM] as s:
s.bind[[HOST, PORT]]
s.listen[]
conn, addr = s.accept[]
with conn:
print[f"Connected by {addr}"]
while True:
data = conn.recv[1024]
if not data:
break
conn.sendall[data]
902Bây giờ hãy xem
# echo-server.py
# ...
with socket.socket[socket.AF_INET, socket.SOCK_STREAM] as s:
s.bind[[HOST, PORT]]
s.listen[]
conn, addr = s.accept[]
with conn:
print[f"Connected by {addr}"]
while True:
data = conn.recv[1024]
if not data:
break
conn.sendall[data]
921 để xem kết nối máy khách được xử lý như thế nào khi sẵn sàng# echo-server.py
# ...
with socket.socket[socket.AF_INET, socket.SOCK_STREAM] as s:
s.bind[[HOST, PORT]]
s.listen[]
conn, addr = s.accept[]
with conn:
print[f"Connected by {addr}"]
while True:
data = conn.recv[1024]
if not data:
break
conn.sendall[data]
49Đây là trái tim của máy chủ đa kết nối đơn giản.
# echo-server.py
# ...
with socket.socket[socket.AF_INET, socket.SOCK_STREAM] as s:
s.bind[[HOST, PORT]]
s.listen[]
conn, addr = s.accept[]
with conn:
print[f"Connected by {addr}"]
while True:
data = conn.recv[1024]
if not data:
break
conn.sendall[data]
909 là # echo-server.py
# ...
with socket.socket[socket.AF_INET, socket.SOCK_STREAM] as s:
s.bind[[HOST, PORT]]
s.listen[]
conn, addr = s.accept[]
with conn:
print[f"Connected by {addr}"]
while True:
data = conn.recv[1024]
if not data:
break
conn.sendall[data]
912 được trả về từ # echo-server.py
# ...
with socket.socket[socket.AF_INET, socket.SOCK_STREAM] as s:
s.bind[[HOST, PORT]]
s.listen[]
conn, addr = s.accept[]
with conn:
print[f"Connected by {addr}"]
while True:
data = conn.recv[1024]
if not data:
break
conn.sendall[data]
488 có chứa đối tượng ổ cắm [# echo-server.py
# ...
with socket.socket[socket.AF_INET, socket.SOCK_STREAM] as s:
s.bind[[HOST, PORT]]
s.listen[]
conn, addr = s.accept[]
with conn:
print[f"Connected by {addr}"]
while True:
data = conn.recv[1024]
if not data:
break
conn.sendall[data]
913] và đối tượng dữ liệu. # echo-server.py
# ...
with socket.socket[socket.AF_INET, socket.SOCK_STREAM] as s:
s.bind[[HOST, PORT]]
s.listen[]
conn, addr = s.accept[]
with conn:
print[f"Connected by {addr}"]
while True:
data = conn.recv[1024]
if not data:
break
conn.sendall[data]
910 chứa các sự kiện đã sẵn sàngNếu ổ cắm đã sẵn sàng để đọc, thì
# echo-server.py
# ...
with socket.socket[socket.AF_INET, socket.SOCK_STREAM] as s:
s.bind[[HOST, PORT]]
s.listen[]
conn, addr = s.accept[]
with conn:
print[f"Connected by {addr}"]
while True:
data = conn.recv[1024]
if not data:
break
conn.sendall[data]
937 sẽ đánh giá thành # echo-server.py
# ...
with socket.socket[socket.AF_INET, socket.SOCK_STREAM] as s:
s.bind[[HOST, PORT]]
s.listen[]
conn, addr = s.accept[]
with conn:
print[f"Connected by {addr}"]
while True:
data = conn.recv[1024]
if not data:
break
conn.sendall[data]
938, do đó, # echo-server.py
# ...
with socket.socket[socket.AF_INET, socket.SOCK_STREAM] as s:
s.bind[[HOST, PORT]]
s.listen[]
conn, addr = s.accept[]
with conn:
print[f"Connected by {addr}"]
while True:
data = conn.recv[1024]
if not data:
break
conn.sendall[data]
939 được gọi là. Bất kỳ dữ liệu nào được đọc đều được thêm vào _______ 2940 để có thể gửi sauLưu ý khối
# echo-server.py
# ...
with socket.socket[socket.AF_INET, socket.SOCK_STREAM] as s:
s.bind[[HOST, PORT]]
s.listen[]
conn, addr = s.accept[]
with conn:
print[f"Connected by {addr}"]
while True:
data = conn.recv[1024]
if not data:
break
conn.sendall[data]
941 để kiểm tra nếu không nhận được dữ liệu# echo-server.py
# ...
with socket.socket[socket.AF_INET, socket.SOCK_STREAM] as s:
s.bind[[HOST, PORT]]
s.listen[]
conn, addr = s.accept[]
with conn:
print[f"Connected by {addr}"]
while True:
data = conn.recv[1024]
if not data:
break
conn.sendall[data]
90Nếu không nhận được dữ liệu, điều này có nghĩa là máy khách đã đóng ổ cắm của họ, vì vậy máy chủ cũng vậy. Nhưng đừng quên gọi cho
# echo-server.py
# ...
with socket.socket[socket.AF_INET, socket.SOCK_STREAM] as s:
s.bind[[HOST, PORT]]
s.listen[]
conn, addr = s.accept[]
with conn:
print[f"Connected by {addr}"]
while True:
data = conn.recv[1024]
if not data:
break
conn.sendall[data]
942 trước khi đóng cửa, để nó không còn bị giám sát bởi # echo-server.py
# ...
with socket.socket[socket.AF_INET, socket.SOCK_STREAM] as s:
s.bind[[HOST, PORT]]
s.listen[]
conn, addr = s.accept[]
with conn:
print[f"Connected by {addr}"]
while True:
data = conn.recv[1024]
if not data:
break
conn.sendall[data]
488Khi ổ cắm đã sẵn sàng để ghi, đây luôn là trường hợp đối với ổ cắm khỏe mạnh, mọi dữ liệu đã nhận được lưu trữ trong
# echo-server.py
# ...
with socket.socket[socket.AF_INET, socket.SOCK_STREAM] as s:
s.bind[[HOST, PORT]]
s.listen[]
conn, addr = s.accept[]
with conn:
print[f"Connected by {addr}"]
while True:
data = conn.recv[1024]
if not data:
break
conn.sendall[data]
940 sẽ được gửi lại cho máy khách bằng cách sử dụng # echo-server.py
# ...
with socket.socket[socket.AF_INET, socket.SOCK_STREAM] as s:
s.bind[[HOST, PORT]]
s.listen[]
conn, addr = s.accept[]
with conn:
print[f"Connected by {addr}"]
while True:
data = conn.recv[1024]
if not data:
break
conn.sendall[data]
945. Các byte được gửi sau đó được xóa khỏi bộ đệm gửi# echo-server.py
# ...
with socket.socket[socket.AF_INET, socket.SOCK_STREAM] as s:
s.bind[[HOST, PORT]]
s.listen[]
conn, addr = s.accept[]
with conn:
print[f"Connected by {addr}"]
while True:
data = conn.recv[1024]
if not data:
break
conn.sendall[data]
91Phương thức
# echo-server.py
# ...
with socket.socket[socket.AF_INET, socket.SOCK_STREAM] as s:
s.bind[[HOST, PORT]]
s.listen[]
conn, addr = s.accept[]
with conn:
print[f"Connected by {addr}"]
while True:
data = conn.recv[1024]
if not data:
break
conn.sendall[data]
4 trả về số byte đã gửi. Số này sau đó có thể được sử dụng với ký hiệu lát cắt trên bộ đệm # echo-server.py
# ...
with socket.socket[socket.AF_INET, socket.SOCK_STREAM] as s:
s.bind[[HOST, PORT]]
s.listen[]
conn, addr = s.accept[]
with conn:
print[f"Connected by {addr}"]
while True:
data = conn.recv[1024]
if not data:
break
conn.sendall[data]
947 để loại bỏ các byte đã gửiRemove adsMáy khách đa kết nối
Bây giờ hãy xem ứng dụng khách đa kết nối,
# echo-server.py
# ...
with socket.socket[socket.AF_INET, socket.SOCK_STREAM] as s:
s.bind[[HOST, PORT]]
s.listen[]
conn, addr = s.accept[]
with conn:
print[f"Connected by {addr}"]
while True:
data = conn.recv[1024]
if not data:
break
conn.sendall[data]
948. Nó rất giống với máy chủ, nhưng thay vì lắng nghe kết nối, nó bắt đầu bằng cách bắt đầu kết nối qua # echo-server.py
# ...
with socket.socket[socket.AF_INET, socket.SOCK_STREAM] as s:
s.bind[[HOST, PORT]]
s.listen[]
conn, addr = s.accept[]
with conn:
print[f"Connected by {addr}"]
while True:
data = conn.recv[1024]
if not data:
break
conn.sendall[data]
949# echo-server.py
# ...
with socket.socket[socket.AF_INET, socket.SOCK_STREAM] as s:
s.bind[[HOST, PORT]]
s.listen[]
conn, addr = s.accept[]
with conn:
print[f"Connected by {addr}"]
while True:
data = conn.recv[1024]
if not data:
break
conn.sendall[data]
92# echo-server.py
# ...
with socket.socket[socket.AF_INET, socket.SOCK_STREAM] as s:
s.bind[[HOST, PORT]]
s.listen[]
conn, addr = s.accept[]
with conn:
print[f"Connected by {addr}"]
while True:
data = conn.recv[1024]
if not data:
break
conn.sendall[data]
950 được đọc từ dòng lệnh và là số lượng kết nối cần tạo tới máy chủ. Giống như máy chủ, mỗi ổ cắm được đặt ở chế độ không chặnBạn sử dụng
# echo-server.py
# ...
with socket.socket[socket.AF_INET, socket.SOCK_STREAM] as s:
s.bind[[HOST, PORT]]
s.listen[]
conn, addr = s.accept[]
with conn:
print[f"Connected by {addr}"]
while True:
data = conn.recv[1024]
if not data:
break
conn.sendall[data]
3 thay vì # echo-server.py
# ...
with socket.socket[socket.AF_INET, socket.SOCK_STREAM] as s:
s.bind[[HOST, PORT]]
s.listen[]
conn, addr = s.accept[]
with conn:
print[f"Connected by {addr}"]
while True:
data = conn.recv[1024]
if not data:
break
conn.sendall[data]
2 vì # echo-server.py
# ...
with socket.socket[socket.AF_INET, socket.SOCK_STREAM] as s:
s.bind[[HOST, PORT]]
s.listen[]
conn, addr = s.accept[]
with conn:
print[f"Connected by {addr}"]
while True:
data = conn.recv[1024]
if not data:
break
conn.sendall[data]
2 sẽ ngay lập tức đưa ra một ngoại lệ # echo-server.py
# ...
with socket.socket[socket.AF_INET, socket.SOCK_STREAM] as s:
s.bind[[HOST, PORT]]
s.listen[]
conn, addr = s.accept[]
with conn:
print[f"Connected by {addr}"]
while True:
data = conn.recv[1024]
if not data:
break
conn.sendall[data]
954. Phương pháp # echo-server.py
# ...
with socket.socket[socket.AF_INET, socket.SOCK_STREAM] as s:
s.bind[[HOST, PORT]]
s.listen[]
conn, addr = s.accept[]
with conn:
print[f"Connected by {addr}"]
while True:
data = conn.recv[1024]
if not data:
break
conn.sendall[data]
3 ban đầu trả về một chỉ báo lỗi, # echo-server.py
# ...
with socket.socket[socket.AF_INET, socket.SOCK_STREAM] as s:
s.bind[[HOST, PORT]]
s.listen[]
conn, addr = s.accept[]
with conn:
print[f"Connected by {addr}"]
while True:
data = conn.recv[1024]
if not data:
break
conn.sendall[data]
956, thay vì đưa ra một ngoại lệ có thể cản trở kết nối đang diễn ra. Sau khi kết nối hoàn tất, ổ cắm đã sẵn sàng để đọc và ghi và được trả về bởi # echo-server.py
# ...
with socket.socket[socket.AF_INET, socket.SOCK_STREAM] as s:
s.bind[[HOST, PORT]]
s.listen[]
conn, addr = s.accept[]
with conn:
print[f"Connected by {addr}"]
while True:
data = conn.recv[1024]
if not data:
break
conn.sendall[data]
488Sau khi ổ cắm được thiết lập, dữ liệu bạn muốn lưu trữ với ổ cắm được tạo bằng cách sử dụng
# echo-server.py
# ...
with socket.socket[socket.AF_INET, socket.SOCK_STREAM] as s:
s.bind[[HOST, PORT]]
s.listen[]
conn, addr = s.accept[]
with conn:
print[f"Connected by {addr}"]
while True:
data = conn.recv[1024]
if not data:
break
conn.sendall[data]
928. Các tin nhắn mà máy khách sẽ gửi đến máy chủ được sao chép bằng cách sử dụng # echo-server.py
# ...
with socket.socket[socket.AF_INET, socket.SOCK_STREAM] as s:
s.bind[[HOST, PORT]]
s.listen[]
conn, addr = s.accept[]
with conn:
print[f"Connected by {addr}"]
while True:
data = conn.recv[1024]
if not data:
break
conn.sendall[data]
959 vì mỗi kết nối sẽ gọi # echo-server.py
# ...
with socket.socket[socket.AF_INET, socket.SOCK_STREAM] as s:
s.bind[[HOST, PORT]]
s.listen[]
conn, addr = s.accept[]
with conn:
print[f"Connected by {addr}"]
while True:
data = conn.recv[1024]
if not data:
break
conn.sendall[data]
960 và sửa đổi danh sách. Mọi thứ cần thiết để theo dõi những gì khách hàng cần gửi, đã gửi và đã nhận, bao gồm tổng số byte trong tin nhắn, được lưu trữ trong đối tượng # echo-server.py
# ...
with socket.socket[socket.AF_INET, socket.SOCK_STREAM] as s:
s.bind[[HOST, PORT]]
s.listen[]
conn, addr = s.accept[]
with conn:
print[f"Connected by {addr}"]
while True:
data = conn.recv[1024]
if not data:
break
conn.sendall[data]
905Kiểm tra các thay đổi được thực hiện từ
# echo-server.py
# ...
with socket.socket[socket.AF_INET, socket.SOCK_STREAM] as s:
s.bind[[HOST, PORT]]
s.listen[]
conn, addr = s.accept[]
with conn:
print[f"Connected by {addr}"]
while True:
data = conn.recv[1024]
if not data:
break
conn.sendall[data]
921 của máy chủ đối với phiên bản của máy khách# echo-server.py
# ...
with socket.socket[socket.AF_INET, socket.SOCK_STREAM] as s:
s.bind[[HOST, PORT]]
s.listen[]
conn, addr = s.accept[]
with conn:
print[f"Connected by {addr}"]
while True:
data = conn.recv[1024]
if not data:
break
conn.sendall[data]
93Về cơ bản là giống nhau nhưng có một điểm khác biệt quan trọng. Máy khách theo dõi số byte mà nó nhận được từ máy chủ để có thể đóng phần kết nối của nó. Khi máy chủ phát hiện ra điều này, nó cũng sẽ đóng phần kết nối của nó
Lưu ý rằng bằng cách này, máy chủ phụ thuộc vào máy khách có hoạt động tốt không. máy chủ yêu cầu máy khách đóng phía kết nối của nó khi gửi tin nhắn xong. Nếu máy khách không đóng, máy chủ sẽ để kết nối mở. Trong một ứng dụng thực tế, bạn có thể muốn bảo vệ chống lại điều này trong máy chủ của mình bằng cách triển khai thời gian chờ để ngăn các kết nối máy khách tích lũy nếu chúng không gửi yêu cầu sau một khoảng thời gian nhất định
Chạy máy khách và máy chủ đa kết nối
Bây giờ là lúc để chạy
# echo-server.py
# ...
with socket.socket[socket.AF_INET, socket.SOCK_STREAM] as s:
s.bind[[HOST, PORT]]
s.listen[]
conn, addr = s.accept[]
with conn:
print[f"Connected by {addr}"]
while True:
data = conn.recv[1024]
if not data:
break
conn.sendall[data]
963 và # echo-server.py
# ...
with socket.socket[socket.AF_INET, socket.SOCK_STREAM] as s:
s.bind[[HOST, PORT]]
s.listen[]
conn, addr = s.accept[]
with conn:
print[f"Connected by {addr}"]
while True:
data = conn.recv[1024]
if not data:
break
conn.sendall[data]
948. Cả hai đều sử dụng đối số dòng lệnh. Bạn có thể chạy chúng mà không cần đối số để xem các tùy chọnĐối với máy chủ, hãy chuyển số
# echo-server.py
# ...
with socket.socket[socket.AF_INET, socket.SOCK_STREAM] as s:
s.bind[[HOST, PORT]]
s.listen[]
conn, addr = s.accept[]
with conn:
print[f"Connected by {addr}"]
while True:
data = conn.recv[1024]
if not data:
break
conn.sendall[data]
38 và # echo-server.py
# ...
with socket.socket[socket.AF_INET, socket.SOCK_STREAM] as s:
s.bind[[HOST, PORT]]
s.listen[]
conn, addr = s.accept[]
with conn:
print[f"Connected by {addr}"]
while True:
data = conn.recv[1024]
if not data:
break
conn.sendall[data]
401# echo-server.py
# ...
with socket.socket[socket.AF_INET, socket.SOCK_STREAM] as s:
s.bind[[HOST, PORT]]
s.listen[]
conn, addr = s.accept[]
with conn:
print[f"Connected by {addr}"]
while True:
data = conn.recv[1024]
if not data:
break
conn.sendall[data]
94Đối với máy khách, cũng chuyển số lượng kết nối cần tạo tới máy chủ,
# echo-server.py
# ...
with socket.socket[socket.AF_INET, socket.SOCK_STREAM] as s:
s.bind[[HOST, PORT]]
s.listen[]
conn, addr = s.accept[]
with conn:
print[f"Connected by {addr}"]
while True:
data = conn.recv[1024]
if not data:
break
conn.sendall[data]
967# echo-server.py
# ...
with socket.socket[socket.AF_INET, socket.SOCK_STREAM] as s:
s.bind[[HOST, PORT]]
s.listen[]
conn, addr = s.accept[]
with conn:
print[f"Connected by {addr}"]
while True:
data = conn.recv[1024]
if not data:
break
conn.sendall[data]
95Dưới đây là đầu ra của máy chủ khi nghe trên giao diện loopback trên cổng 65432
# echo-server.py
# ...
with socket.socket[socket.AF_INET, socket.SOCK_STREAM] as s:
s.bind[[HOST, PORT]]
s.listen[]
conn, addr = s.accept[]
with conn:
print[f"Connected by {addr}"]
while True:
data = conn.recv[1024]
if not data:
break
conn.sendall[data]
96Dưới đây là đầu ra của máy khách khi nó tạo hai kết nối đến máy chủ ở trên
# echo-server.py
# ...
with socket.socket[socket.AF_INET, socket.SOCK_STREAM] as s:
s.bind[[HOST, PORT]]
s.listen[]
conn, addr = s.accept[]
with conn:
print[f"Connected by {addr}"]
while True:
data = conn.recv[1024]
if not data:
break
conn.sendall[data]
97Tuyệt quá. Bây giờ bạn đã chạy máy khách và máy chủ đa kết nối. Trong phần tiếp theo, bạn sẽ sử dụng ví dụ này nhiều hơn nữa
Remove adsMáy khách và máy chủ ứng dụng
Ví dụ về máy khách và máy chủ đa kết nối chắc chắn là một cải tiến so với nơi bạn bắt đầu. Tuy nhiên, bây giờ bạn có thể thực hiện thêm một bước nữa và giải quyết những thiếu sót của ví dụ
# echo-server.py
# ...
with socket.socket[socket.AF_INET, socket.SOCK_STREAM] as s:
s.bind[[HOST, PORT]]
s.listen[]
conn, addr = s.accept[]
with conn:
print[f"Connected by {addr}"]
while True:
data = conn.recv[1024]
if not data:
break
conn.sendall[data]
968 trước đó trong lần triển khai cuối cùng. the application client and serverBạn muốn có một máy khách và máy chủ xử lý lỗi một cách thích hợp để các kết nối khác không bị ảnh hưởng. Rõ ràng, máy khách hoặc máy chủ của bạn sẽ không bị sập trong cơn thịnh nộ nếu một ngoại lệ không bị phát hiện. Đây là điều mà bạn không phải lo lắng cho đến bây giờ, bởi vì các ví dụ đã cố tình bỏ qua việc xử lý lỗi để cho ngắn gọn và rõ ràng.
Bây giờ bạn đã quen thuộc với API cơ bản, ổ cắm không chặn và
# echo-server.py
# ...
with socket.socket[socket.AF_INET, socket.SOCK_STREAM] as s:
s.bind[[HOST, PORT]]
s.listen[]
conn, addr = s.accept[]
with conn:
print[f"Connected by {addr}"]
while True:
data = conn.recv[1024]
if not data:
break
conn.sendall[data]
488, bạn có thể thêm một số cách xử lý lỗi và xử lý con voi trong phòng, mà các ví dụ đã giấu bạn đằng sau bức màn lớn đằng kia. Hãy nhớ rằng lớp tùy chỉnh đã được đề cập trở lại trong phần giới thiệu? Đầu tiên, bạn sẽ giải quyết các lỗi
“Tất cả các lỗi đều có ngoại lệ. Các ngoại lệ thông thường đối với các loại đối số không hợp lệ và các điều kiện hết bộ nhớ có thể được nêu ra; . 3, các lỗi liên quan đến ngữ nghĩa ổ cắm hoặc địa chỉ nâng cao
970 hoặc một trong các lớp con của nó. " [Nguồn]# echo-server.py # ... with socket.socket[socket.AF_INET, socket.SOCK_STREAM] as s: s.bind[[HOST, PORT]] s.listen[] conn, addr = s.accept[] with conn: print[f"Connected by {addr}"] while True: data = conn.recv[1024] if not data: break conn.sendall[data]
Vì vậy, một điều bạn cần làm là bắt
# echo-server.py
# ...
with socket.socket[socket.AF_INET, socket.SOCK_STREAM] as s:
s.bind[[HOST, PORT]]
s.listen[]
conn, addr = s.accept[]
with conn:
print[f"Connected by {addr}"]
while True:
data = conn.recv[1024]
if not data:
break
conn.sendall[data]
970. Một cân nhắc quan trọng khác liên quan đến lỗi là thời gian chờ. Bạn sẽ thấy chúng được thảo luận ở nhiều nơi trong tài liệu. Hết thời gian chờ xảy ra và được gọi là lỗi bình thường. Máy chủ và bộ định tuyến được khởi động lại, cổng chuyển đổi bị hỏng, cáp bị hỏng, cáp bị rút phích cắm, bạn đặt tên cho nó. Bạn nên chuẩn bị cho những lỗi này và các lỗi khác, xử lý chúng trong mã của bạnCòn con voi trong phòng thì sao? . Nó giống như đọc từ một tệp trên đĩa, nhưng thay vào đó bạn đang đọc các byte từ mạng. Tuy nhiên, không giống như đọc tệp, không có
# echo-server.py
# ...
with socket.socket[socket.AF_INET, socket.SOCK_STREAM] as s:
s.bind[[HOST, PORT]]
s.listen[]
conn, addr = s.accept[]
with conn:
print[f"Connected by {addr}"]
while True:
data = conn.recv[1024]
if not data:
break
conn.sendall[data]
973Nói cách khác, bạn không thể định vị lại con trỏ ổ cắm, nếu có và di chuyển xung quanh dữ liệu
Khi byte đến ổ cắm của bạn, có bộ đệm mạng liên quan. Sau khi bạn đã đọc chúng, chúng cần được lưu ở đâu đó, nếu không bạn sẽ đánh rơi chúng. Gọi lại
# echo-server.py
# ...
with socket.socket[socket.AF_INET, socket.SOCK_STREAM] as s:
s.bind[[HOST, PORT]]
s.listen[]
conn, addr = s.accept[]
with conn:
print[f"Connected by {addr}"]
while True:
data = conn.recv[1024]
if not data:
break
conn.sendall[data]
5 để đọc luồng byte tiếp theo có sẵn từ ổ cắmBạn sẽ đọc từ ổ cắm theo khối. Vì vậy, bạn cần gọi
# echo-server.py
# ...
with socket.socket[socket.AF_INET, socket.SOCK_STREAM] as s:
s.bind[[HOST, PORT]]
s.listen[]
conn, addr = s.accept[]
with conn:
print[f"Connected by {addr}"]
while True:
data = conn.recv[1024]
if not data:
break
conn.sendall[data]
5 và lưu dữ liệu vào bộ đệm cho đến khi bạn đọc đủ byte để có một thông báo hoàn chỉnh có ý nghĩa đối với ứng dụng của bạnTùy thuộc vào bạn để xác định và theo dõi vị trí của ranh giới tin nhắn. Đối với ổ cắm TCP, nó chỉ gửi và nhận các byte thô đến và từ mạng. Nó không biết gì về ý nghĩa của những byte thô đó
Đây là lý do tại sao bạn cần xác định giao thức tầng ứng dụng. Giao thức tầng ứng dụng là gì? . Định dạng của những thông báo này là giao thức của ứng dụng của bạn
Nói cách khác, độ dài và định dạng mà bạn chọn cho các thông báo này sẽ xác định ngữ nghĩa và hành vi của ứng dụng của bạn. Điều này liên quan trực tiếp đến những gì bạn đã học trong đoạn trước về việc đọc byte từ ổ cắm. Khi bạn đang đọc các byte bằng
# echo-server.py
# ...
with socket.socket[socket.AF_INET, socket.SOCK_STREAM] as s:
s.bind[[HOST, PORT]]
s.listen[]
conn, addr = s.accept[]
with conn:
print[f"Connected by {addr}"]
while True:
data = conn.recv[1024]
if not data:
break
conn.sendall[data]
5, bạn cần theo dõi số lượng byte đã được đọc và tìm ra ranh giới của thông báo nằm ở đâuLàm thế nào bạn có thể làm điều này? . Nếu chúng luôn có cùng kích thước, thì thật dễ dàng. Khi bạn đã đọc số byte đó vào bộ đệm, thì bạn biết mình có một thông báo hoàn chỉnh
Tuy nhiên, việc sử dụng các tin nhắn có độ dài cố định sẽ không hiệu quả đối với các tin nhắn nhỏ mà bạn cần sử dụng phần đệm để điền vào chúng. Ngoài ra, bạn vẫn gặp phải vấn đề phải làm gì với dữ liệu không phù hợp với một tin nhắn
Trong hướng dẫn này, bạn sẽ học một cách tiếp cận chung, một cách tiếp cận được sử dụng bởi nhiều giao thức, bao gồm cả HTTP. Bạn sẽ thêm tiền tố vào thư với tiêu đề bao gồm độ dài nội dung cũng như bất kỳ trường nào khác mà bạn cần. Bằng cách này, bạn sẽ chỉ cần theo kịp tiêu đề. Khi bạn đã đọc tiêu đề, bạn có thể xử lý nó để xác định độ dài của nội dung thư. Với độ dài nội dung, bạn có thể đọc số byte đó để sử dụng nó
Bạn sẽ thực hiện điều này bằng cách tạo một lớp tùy chỉnh có thể gửi và nhận tin nhắn chứa dữ liệu văn bản hoặc nhị phân. Bạn có thể cải thiện và mở rộng lớp này cho các ứng dụng của riêng mình. Điều quan trọng nhất là bạn sẽ có thể xem một ví dụ về cách thực hiện điều này
Trước khi bắt đầu, có một số điều bạn cần biết về socket và byte. Như bạn đã biết trước đó, khi gửi và nhận dữ liệu qua socket, bạn đang gửi và nhận các byte thô
Nếu bạn nhận được dữ liệu và muốn sử dụng dữ liệu đó trong ngữ cảnh mà dữ liệu đó được hiểu là nhiều byte, chẳng hạn như số nguyên 4 byte, bạn sẽ cần tính đến việc dữ liệu đó có thể ở định dạng không có nguồn gốc từ CPU của máy bạn. Máy khách hoặc máy chủ ở đầu bên kia có thể có CPU sử dụng thứ tự byte khác với thứ tự byte của bạn. Nếu trường hợp này xảy ra, thì bạn sẽ cần chuyển đổi nó thành thứ tự byte gốc của máy chủ trước khi sử dụng
Thứ tự byte này được gọi là tuổi thọ của CPU. Xem Byte Endianness trong phần tham khảo để biết chi tiết. Bạn sẽ tránh được vấn đề này bằng cách tận dụng Unicode cho tiêu đề thư của mình và sử dụng mã hóa UTF-8. Vì UTF-8 sử dụng mã hóa 8 bit nên không có vấn đề về thứ tự byte
You can find an explanation in Python’s Encodings and Unicode documentation. Lưu ý rằng điều này chỉ áp dụng cho tiêu đề văn bản. Bạn sẽ sử dụng một loại rõ ràng và mã hóa được xác định trong tiêu đề cho nội dung đang được gửi, trọng tải tin nhắn. Điều này sẽ cho phép bạn chuyển bất kỳ dữ liệu nào bạn muốn [văn bản hoặc nhị phân], ở bất kỳ định dạng nào
You can easily determine the byte order of your machine by using
# echo-server.py
# ...
with socket.socket[socket.AF_INET, socket.SOCK_STREAM] as s:
s.bind[[HOST, PORT]]
s.listen[]
conn, addr = s.accept[]
with conn:
print[f"Connected by {addr}"]
while True:
data = conn.recv[1024]
if not data:
break
conn.sendall[data]
977. Ví dụ, bạn có thể thấy một cái gì đó như thế này# echo-server.py
# ...
with socket.socket[socket.AF_INET, socket.SOCK_STREAM] as s:
s.bind[[HOST, PORT]]
s.listen[]
conn, addr = s.accept[]
with conn:
print[f"Connected by {addr}"]
while True:
data = conn.recv[1024]
if not data:
break
conn.sendall[data]
98Nếu bạn chạy cái này trong một máy ảo mô phỏng CPU big-endian [PowerPC], thì điều tương tự sẽ xảy ra
# echo-server.py
# ...
with socket.socket[socket.AF_INET, socket.SOCK_STREAM] as s:
s.bind[[HOST, PORT]]
s.listen[]
conn, addr = s.accept[]
with conn:
print[f"Connected by {addr}"]
while True:
data = conn.recv[1024]
if not data:
break
conn.sendall[data]
99Trong ứng dụng ví dụ này, giao thức lớp ứng dụng của bạn xác định tiêu đề là văn bản Unicode với mã hóa UTF-8. Đối với nội dung thực tế trong tin nhắn, trọng tải tin nhắn, bạn sẽ vẫn phải hoán đổi thứ tự byte theo cách thủ công nếu cần
Điều này sẽ phụ thuộc vào ứng dụng của bạn và liệu nó có cần xử lý dữ liệu nhị phân nhiều byte từ một máy có độ bền khác hay không. Bạn có thể giúp máy khách hoặc máy chủ của mình triển khai hỗ trợ nhị phân bằng cách thêm các tiêu đề bổ sung và sử dụng chúng để truyền tham số, tương tự như HTTP
Đừng lo lắng nếu điều này chưa có ý nghĩa. Trong phần tiếp theo, bạn sẽ thấy tất cả những thứ này hoạt động và ăn khớp với nhau như thế nào
Remove adsTiêu đề giao thức ứng dụng
Bây giờ bạn sẽ xác định đầy đủ tiêu đề giao thức. Tiêu đề giao thức là
- Variable-length text
- Unicode với bảng mã UTF-8
- Một từ điển Python được tuần tự hóa bằng JSON
Các tiêu đề hoặc tiêu đề phụ bắt buộc trong từ điển của tiêu đề giao thức như sau
TênMô tả
# echo-server.py
# ...
with socket.socket[socket.AF_INET, socket.SOCK_STREAM] as s:
s.bind[[HOST, PORT]]
s.listen[]
conn, addr = s.accept[]
with conn:
print[f"Connected by {addr}"]
while True:
data = conn.recv[1024]
if not data:
break
conn.sendall[data]
978 Thứ tự byte của máy [sử dụng # echo-server.py
# ...
with socket.socket[socket.AF_INET, socket.SOCK_STREAM] as s:
s.bind[[HOST, PORT]]
s.listen[]
conn, addr = s.accept[]
with conn:
print[f"Connected by {addr}"]
while True:
data = conn.recv[1024]
if not data:
break
conn.sendall[data]
977]. Điều này có thể không cần thiết cho ứng dụng của bạn. # echo-server.py
# ...
with socket.socket[socket.AF_INET, socket.SOCK_STREAM] as s:
s.bind[[HOST, PORT]]
s.listen[]
conn, addr = s.accept[]
with conn:
print[f"Connected by {addr}"]
while True:
data = conn.recv[1024]
if not data:
break
conn.sendall[data]
980Độ dài của nội dung tính bằng byte. # echo-server.py
# ...
with socket.socket[socket.AF_INET, socket.SOCK_STREAM] as s:
s.bind[[HOST, PORT]]
s.listen[]
conn, addr = s.accept[]
with conn:
print[f"Connected by {addr}"]
while True:
data = conn.recv[1024]
if not data:
break
conn.sendall[data]
981Loại nội dung trong tải trọng, ví dụ: # echo-server.py
# ...
with socket.socket[socket.AF_INET, socket.SOCK_STREAM] as s:
s.bind[[HOST, PORT]]
s.listen[]
conn, addr = s.accept[]
with conn:
print[f"Connected by {addr}"]
while True:
data = conn.recv[1024]
if not data:
break
conn.sendall[data]
982 hoặc # echo-server.py
# ...
with socket.socket[socket.AF_INET, socket.SOCK_STREAM] as s:
s.bind[[HOST, PORT]]
s.listen[]
conn, addr = s.accept[]
with conn:
print[f"Connected by {addr}"]
while True:
data = conn.recv[1024]
if not data:
break
conn.sendall[data]
983. # echo-server.py
# ...
with socket.socket[socket.AF_INET, socket.SOCK_STREAM] as s:
s.bind[[HOST, PORT]]
s.listen[]
conn, addr = s.accept[]
with conn:
print[f"Connected by {addr}"]
while True:
data = conn.recv[1024]
if not data:
break
conn.sendall[data]
984Mã hóa mà nội dung sử dụng, ví dụ: # echo-server.py
# ...
with socket.socket[socket.AF_INET, socket.SOCK_STREAM] as s:
s.bind[[HOST, PORT]]
s.listen[]
conn, addr = s.accept[]
with conn:
print[f"Connected by {addr}"]
while True:
data = conn.recv[1024]
if not data:
break
conn.sendall[data]
985 cho văn bản Unicode hoặc # echo-server.py
# ...
with socket.socket[socket.AF_INET, socket.SOCK_STREAM] as s:
s.bind[[HOST, PORT]]
s.listen[]
conn, addr = s.accept[]
with conn:
print[f"Connected by {addr}"]
while True:
data = conn.recv[1024]
if not data:
break
conn.sendall[data]
986 cho dữ liệu nhị phânCác tiêu đề này thông báo cho người nhận về nội dung trong tải trọng của tin nhắn. Điều này cho phép bạn gửi dữ liệu tùy ý trong khi cung cấp đủ thông tin để người nhận có thể giải mã và diễn giải chính xác nội dung. Vì các tiêu đề nằm trong từ điển nên bạn có thể dễ dàng thêm các tiêu đề bổ sung bằng cách chèn các cặp khóa-giá trị nếu cần
Gửi tin nhắn ứng dụng
Vẫn còn một chút vấn đề. Bạn có một tiêu đề có độ dài thay đổi, rất đẹp và linh hoạt, nhưng làm thế nào để bạn biết độ dài của tiêu đề khi đọc nó bằng
# echo-server.py
# ...
with socket.socket[socket.AF_INET, socket.SOCK_STREAM] as s:
s.bind[[HOST, PORT]]
s.listen[]
conn, addr = s.accept[]
with conn:
print[f"Connected by {addr}"]
while True:
data = conn.recv[1024]
if not data:
break
conn.sendall[data]
5?Trước đây, khi bạn đã học về cách sử dụng
# echo-server.py
# ...
with socket.socket[socket.AF_INET, socket.SOCK_STREAM] as s:
s.bind[[HOST, PORT]]
s.listen[]
conn, addr = s.accept[]
with conn:
print[f"Connected by {addr}"]
while True:
data = conn.recv[1024]
if not data:
break
conn.sendall[data]
5 và ranh giới thư, bạn cũng đã biết rằng các tiêu đề có độ dài cố định có thể không hiệu quả. Điều đó đúng, nhưng bạn sẽ sử dụng một tiêu đề nhỏ, 2 byte, có độ dài cố định để làm tiền tố cho tiêu đề JSON chứa độ dài của nóBạn có thể coi đây là một cách tiếp cận hỗn hợp để gửi tin nhắn. Trên thực tế, bạn đang khởi động quá trình nhận tin nhắn bằng cách gửi độ dài của tiêu đề trước. Điều này giúp người nhận của bạn dễ dàng giải cấu trúc tin nhắn
Để giúp bạn hiểu rõ hơn về định dạng thư, hãy xem toàn bộ thư
Một thông báo bắt đầu với tiêu đề có độ dài cố định gồm hai byte, là một số nguyên theo thứ tự byte mạng. Đây là độ dài của tiêu đề tiếp theo, tiêu đề JSON có độ dài thay đổi. Khi bạn đã đọc hai byte bằng
# echo-server.py
# ...
with socket.socket[socket.AF_INET, socket.SOCK_STREAM] as s:
s.bind[[HOST, PORT]]
s.listen[]
conn, addr = s.accept[]
with conn:
print[f"Connected by {addr}"]
while True:
data = conn.recv[1024]
if not data:
break
conn.sendall[data]
5, thì bạn biết rằng bạn có thể xử lý hai byte dưới dạng số nguyên rồi đọc số byte đó trước khi giải mã tiêu đề JSON UTF-8Tiêu đề JSON chứa một từ điển các tiêu đề bổ sung. Một trong số đó là
# echo-server.py
# ...
with socket.socket[socket.AF_INET, socket.SOCK_STREAM] as s:
s.bind[[HOST, PORT]]
s.listen[]
conn, addr = s.accept[]
with conn:
print[f"Connected by {addr}"]
while True:
data = conn.recv[1024]
if not data:
break
conn.sendall[data]
980, là số byte nội dung của tin nhắn [không bao gồm tiêu đề JSON]. Khi bạn đã gọi # echo-server.py
# ...
with socket.socket[socket.AF_INET, socket.SOCK_STREAM] as s:
s.bind[[HOST, PORT]]
s.listen[]
conn, addr = s.accept[]
with conn:
print[f"Connected by {addr}"]
while True:
data = conn.recv[1024]
if not data:
break
conn.sendall[data]
5 và đọc # echo-server.py
# ...
with socket.socket[socket.AF_INET, socket.SOCK_STREAM] as s:
s.bind[[HOST, PORT]]
s.listen[]
conn, addr = s.accept[]
with conn:
print[f"Connected by {addr}"]
while True:
data = conn.recv[1024]
if not data:
break
conn.sendall[data]
980 byte, thì bạn đã đạt đến ranh giới tin nhắn, nghĩa là bạn đã đọc toàn bộ tin nhắnLớp tin nhắn ứng dụng
Cuối cùng, phần thưởng. Trong phần này, bạn sẽ nghiên cứu về lớp
# echo-server.py
# ...
with socket.socket[socket.AF_INET, socket.SOCK_STREAM] as s:
s.bind[[HOST, PORT]]
s.listen[]
conn, addr = s.accept[]
with conn:
print[f"Connected by {addr}"]
while True:
data = conn.recv[1024]
if not data:
break
conn.sendall[data]
993 và xem nó được sử dụng như thế nào với # echo-server.py
# ...
with socket.socket[socket.AF_INET, socket.SOCK_STREAM] as s:
s.bind[[HOST, PORT]]
s.listen[]
conn, addr = s.accept[]
with conn:
print[f"Connected by {addr}"]
while True:
data = conn.recv[1024]
if not data:
break
conn.sendall[data]
488 khi các sự kiện đọc và ghi xảy ra trên ổ cắmỨng dụng ví dụ này phản ánh loại thông báo nào mà máy khách và máy chủ có thể sử dụng một cách hợp lý. Tại thời điểm này, bạn vượt xa các máy khách và máy chủ đồ chơi
Để giữ cho mọi thứ đơn giản và vẫn chứng minh cách mọi thứ sẽ hoạt động trong một ứng dụng thực, ví dụ này sử dụng một giao thức ứng dụng triển khai tính năng tìm kiếm cơ bản. Máy khách gửi yêu cầu tìm kiếm và máy chủ thực hiện tìm kiếm kết quả khớp. Nếu yêu cầu do khách hàng gửi không được công nhận là tìm kiếm, thì máy chủ sẽ cho rằng đó là yêu cầu nhị phân và trả về phản hồi nhị phân
Sau khi đọc các phần sau, chạy các ví dụ và thử nghiệm mã, bạn sẽ thấy mọi thứ hoạt động như thế nào. Sau đó, bạn có thể sử dụng lớp
# echo-server.py
# ...
with socket.socket[socket.AF_INET, socket.SOCK_STREAM] as s:
s.bind[[HOST, PORT]]
s.listen[]
conn, addr = s.accept[]
with conn:
print[f"Connected by {addr}"]
while True:
data = conn.recv[1024]
if not data:
break
conn.sendall[data]
993 làm điểm bắt đầu và sửa đổi nó để sử dụng cho riêng mìnhThe application is not that far off from the
# echo-server.py
# ...
with socket.socket[socket.AF_INET, socket.SOCK_STREAM] as s:
s.bind[[HOST, PORT]]
s.listen[]
conn, addr = s.accept[]
with conn:
print[f"Connected by {addr}"]
while True:
data = conn.recv[1024]
if not data:
break
conn.sendall[data]
968 client and server example. Mã vòng lặp sự kiện giữ nguyên trong # echo-server.py
# ...
with socket.socket[socket.AF_INET, socket.SOCK_STREAM] as s:
s.bind[[HOST, PORT]]
s.listen[]
conn, addr = s.accept[]
with conn:
print[f"Connected by {addr}"]
while True:
data = conn.recv[1024]
if not data:
break
conn.sendall[data]
997 và # echo-server.py
# ...
with socket.socket[socket.AF_INET, socket.SOCK_STREAM] as s:
s.bind[[HOST, PORT]]
s.listen[]
conn, addr = s.accept[]
with conn:
print[f"Connected by {addr}"]
while True:
data = conn.recv[1024]
if not data:
break
conn.sendall[data]
998. Những gì bạn sẽ làm là di chuyển mã tin nhắn vào một lớp có tên là # echo-server.py
# ...
with socket.socket[socket.AF_INET, socket.SOCK_STREAM] as s:
s.bind[[HOST, PORT]]
s.listen[]
conn, addr = s.accept[]
with conn:
print[f"Connected by {addr}"]
while True:
data = conn.recv[1024]
if not data:
break
conn.sendall[data]
993 và thêm các phương thức để hỗ trợ đọc, viết và xử lý các tiêu đề và nội dung. Đây là một ví dụ tuyệt vời cho việc sử dụng một lớpNhư bạn đã học trước đây và bạn sẽ thấy bên dưới, làm việc với socket liên quan đến việc giữ trạng thái. Bằng cách sử dụng một lớp, bạn giữ tất cả trạng thái, dữ liệu và mã được nhóm lại với nhau trong một đơn vị có tổ chức. Một phiên bản của lớp được tạo cho mỗi ổ cắm trong máy khách và máy chủ khi kết nối được bắt đầu hoặc được chấp nhận
Lớp này hầu như giống nhau cho cả máy khách và máy chủ đối với các phương thức tiện ích và trình bao bọc. Chúng bắt đầu bằng dấu gạch dưới, chẳng hạn như
# echo-server.py
# ...
with socket.socket[socket.AF_INET, socket.SOCK_STREAM] as s:
s.bind[[HOST, PORT]]
s.listen[]
conn, addr = s.accept[]
with conn:
print[f"Connected by {addr}"]
while True:
data = conn.recv[1024]
if not data:
break
conn.sendall[data]
600. Các phương thức này đơn giản hóa việc làm việc với lớp. Chúng hỗ trợ các phương pháp khác bằng cách cho phép chúng ở lại ngắn hơn và hỗ trợ nguyên tắc DRYLớp
# echo-server.py
# ...
with socket.socket[socket.AF_INET, socket.SOCK_STREAM] as s:
s.bind[[HOST, PORT]]
s.listen[]
conn, addr = s.accept[]
with conn:
print[f"Connected by {addr}"]
while True:
data = conn.recv[1024]
if not data:
break
conn.sendall[data]
993 của máy chủ về cơ bản hoạt động giống như của máy khách và ngược lại. Sự khác biệt là máy khách bắt đầu kết nối và gửi thông báo yêu cầu, sau đó xử lý thông báo phản hồi của máy chủ. Ngược lại, máy chủ chờ kết nối, xử lý thông báo yêu cầu của máy khách, sau đó gửi thông báo phản hồiNó trông như thế này
StepEndpointAction / Nội dung tin nhắn1ClientGửi một
# echo-server.py
# ...
with socket.socket[socket.AF_INET, socket.SOCK_STREAM] as s:
s.bind[[HOST, PORT]]
s.listen[]
conn, addr = s.accept[]
with conn:
print[f"Connected by {addr}"]
while True:
data = conn.recv[1024]
if not data:
break
conn.sendall[data]
993 có chứa nội dung yêu cầu2ServerNhận và xử lý yêu cầu của máy khách # echo-server.py
# ...
with socket.socket[socket.AF_INET, socket.SOCK_STREAM] as s:
s.bind[[HOST, PORT]]
s.listen[]
conn, addr = s.accept[]
with conn:
print[f"Connected by {addr}"]
while True:
data = conn.recv[1024]
if not data:
break
conn.sendall[data]
9933ServerGửi một # echo-server.py
# ...
with socket.socket[socket.AF_INET, socket.SOCK_STREAM] as s:
s.bind[[HOST, PORT]]
s.listen[]
conn, addr = s.accept[]
with conn:
print[f"Connected by {addr}"]
while True:
data = conn.recv[1024]
if not data:
break
conn.sendall[data]
993 chứa nội dung phản hồi4ClientNhận và xử lý phản hồi của máy chủ # echo-server.py
# ...
with socket.socket[socket.AF_INET, socket.SOCK_STREAM] as s:
s.bind[[HOST, PORT]]
s.listen[]
conn, addr = s.accept[]
with conn:
print[f"Connected by {addr}"]
while True:
data = conn.recv[1024]
if not data:
break
conn.sendall[data]
993Đây là bố cục tệp và mã
ApplicationFileCodeServer
# echo-server.py
# ...
with socket.socket[socket.AF_INET, socket.SOCK_STREAM] as s:
s.bind[[HOST, PORT]]
s.listen[]
conn, addr = s.accept[]
with conn:
print[f"Connected by {addr}"]
while True:
data = conn.recv[1024]
if not data:
break
conn.sendall[data]
998Kịch bản chính của máy chủServer# echo-server.py
# ...
with socket.socket[socket.AF_INET, socket.SOCK_STREAM] as s:
s.bind[[HOST, PORT]]
s.listen[]
conn, addr = s.accept[]
with conn:
print[f"Connected by {addr}"]
while True:
data = conn.recv[1024]
if not data:
break
conn.sendall[data]
607Lớp # echo-server.py
# ...
with socket.socket[socket.AF_INET, socket.SOCK_STREAM] as s:
s.bind[[HOST, PORT]]
s.listen[]
conn, addr = s.accept[]
with conn:
print[f"Connected by {addr}"]
while True:
data = conn.recv[1024]
if not data:
break
conn.sendall[data]
993 của máy chủClient# echo-server.py
# ...
with socket.socket[socket.AF_INET, socket.SOCK_STREAM] as s:
s.bind[[HOST, PORT]]
s.listen[]
conn, addr = s.accept[]
with conn:
print[f"Connected by {addr}"]
while True:
data = conn.recv[1024]
if not data:
break
conn.sendall[data]
997Kịch bản chính của máy kháchClient# echo-server.py
# ...
with socket.socket[socket.AF_INET, socket.SOCK_STREAM] as s:
s.bind[[HOST, PORT]]
s.listen[]
conn, addr = s.accept[]
with conn:
print[f"Connected by {addr}"]
while True:
data = conn.recv[1024]
if not data:
break
conn.sendall[data]
610Lớp # echo-server.py
# ...
with socket.socket[socket.AF_INET, socket.SOCK_STREAM] as s:
s.bind[[HOST, PORT]]
s.listen[]
conn, addr = s.accept[]
with conn:
print[f"Connected by {addr}"]
while True:
data = conn.recv[1024]
if not data:
break
conn.sendall[data]
993 của khách hàngĐiểm nhập tin nhắn
Hiểu cách hoạt động của lớp
# echo-server.py
# ...
with socket.socket[socket.AF_INET, socket.SOCK_STREAM] as s:
s.bind[[HOST, PORT]]
s.listen[]
conn, addr = s.accept[]
with conn:
print[f"Connected by {addr}"]
while True:
data = conn.recv[1024]
if not data:
break
conn.sendall[data]
993 có thể là một thách thức vì có một khía cạnh trong thiết kế của nó có thể không rõ ràng ngay lập tức. Tại sao? Sau khi một đối tượng
# echo-server.py
# ...
with socket.socket[socket.AF_INET, socket.SOCK_STREAM] as s:
s.bind[[HOST, PORT]]
s.listen[]
conn, addr = s.accept[]
with conn:
print[f"Connected by {addr}"]
while True:
data = conn.recv[1024]
if not data:
break
conn.sendall[data]
993 được tạo, nó được liên kết với một ổ cắm được theo dõi các sự kiện bằng cách sử dụng # echo-server.py
# ...
with socket.socket[socket.AF_INET, socket.SOCK_STREAM] as s:
s.bind[[HOST, PORT]]
s.listen[]
conn, addr = s.accept[]
with conn:
print[f"Connected by {addr}"]
while True:
data = conn.recv[1024]
if not data:
break
conn.sendall[data]
614# echo-server.py
# ...
with socket.socket[socket.AF_INET, socket.SOCK_STREAM] as s:
s.bind[[HOST, PORT]]
s.listen[]
conn, addr = s.accept[]
with conn:
print[f"Connected by {addr}"]
while True:
data = conn.recv[1024]
if not data:
break
conn.sendall[data]
60Ghi chú. Một số ví dụ mã trong phần này là từ tập lệnh chính của máy chủ và lớp
# echo-server.py
# ...
with socket.socket[socket.AF_INET, socket.SOCK_STREAM] as s:
s.bind[[HOST, PORT]]
s.listen[]
conn, addr = s.accept[]
with conn:
print[f"Connected by {addr}"]
while True:
data = conn.recv[1024]
if not data:
break
conn.sendall[data]
993, nhưng phần này và cuộc thảo luận cũng áp dụng như nhau cho máy khách. Bạn sẽ được cảnh báo khi phiên bản của khách hàng khácKhi các sự kiện đã sẵn sàng trên ổ cắm, chúng sẽ được trả về bởi
# echo-server.py
# ...
with socket.socket[socket.AF_INET, socket.SOCK_STREAM] as s:
s.bind[[HOST, PORT]]
s.listen[]
conn, addr = s.accept[]
with conn:
print[f"Connected by {addr}"]
while True:
data = conn.recv[1024]
if not data:
break
conn.sendall[data]
616. Sau đó, bạn có thể lấy tham chiếu trở lại đối tượng thông báo bằng cách sử dụng thuộc tính # echo-server.py
# ...
with socket.socket[socket.AF_INET, socket.SOCK_STREAM] as s:
s.bind[[HOST, PORT]]
s.listen[]
conn, addr = s.accept[]
with conn:
print[f"Connected by {addr}"]
while True:
data = conn.recv[1024]
if not data:
break
conn.sendall[data]
905 trên đối tượng # echo-server.py
# ...
with socket.socket[socket.AF_INET, socket.SOCK_STREAM] as s:
s.bind[[HOST, PORT]]
s.listen[]
conn, addr = s.accept[]
with conn:
print[f"Connected by {addr}"]
while True:
data = conn.recv[1024]
if not data:
break
conn.sendall[data]
909 và gọi một phương thức trong # echo-server.py
# ...
with socket.socket[socket.AF_INET, socket.SOCK_STREAM] as s:
s.bind[[HOST, PORT]]
s.listen[]
conn, addr = s.accept[]
with conn:
print[f"Connected by {addr}"]
while True:
data = conn.recv[1024]
if not data:
break
conn.sendall[data]
993# echo-server.py
# ...
with socket.socket[socket.AF_INET, socket.SOCK_STREAM] as s:
s.bind[[HOST, PORT]]
s.listen[]
conn, addr = s.accept[]
with conn:
print[f"Connected by {addr}"]
while True:
data = conn.recv[1024]
if not data:
break
conn.sendall[data]
61Nhìn vào vòng lặp sự kiện ở trên, bạn sẽ thấy rằng
# echo-server.py
# ...
with socket.socket[socket.AF_INET, socket.SOCK_STREAM] as s:
s.bind[[HOST, PORT]]
s.listen[]
conn, addr = s.accept[]
with conn:
print[f"Connected by {addr}"]
while True:
data = conn.recv[1024]
if not data:
break
conn.sendall[data]
901 đang ngồi ở ghế lái. Nó đang chặn, chờ sự kiện ở đầu vòng lặp. Nó chịu trách nhiệm đánh thức khi các sự kiện đọc và ghi đã sẵn sàng để được xử lý trên ổ cắm. Điều đó có nghĩa là, một cách gián tiếp, nó cũng chịu trách nhiệm gọi phương thức # echo-server.py
# ...
with socket.socket[socket.AF_INET, socket.SOCK_STREAM] as s:
s.bind[[HOST, PORT]]
s.listen[]
conn, addr = s.accept[]
with conn:
print[f"Connected by {addr}"]
while True:
data = conn.recv[1024]
if not data:
break
conn.sendall[data]
621. Đó là lý do tại sao # echo-server.py
# ...
with socket.socket[socket.AF_INET, socket.SOCK_STREAM] as s:
s.bind[[HOST, PORT]]
s.listen[]
conn, addr = s.accept[]
with conn:
print[f"Connected by {addr}"]
while True:
data = conn.recv[1024]
if not data:
break
conn.sendall[data]
621 là điểm vàoĐây là những gì phương thức
# echo-server.py
# ...
with socket.socket[socket.AF_INET, socket.SOCK_STREAM] as s:
s.bind[[HOST, PORT]]
s.listen[]
conn, addr = s.accept[]
with conn:
print[f"Connected by {addr}"]
while True:
data = conn.recv[1024]
if not data:
break
conn.sendall[data]
621 làm# echo-server.py
# ...
with socket.socket[socket.AF_INET, socket.SOCK_STREAM] as s:
s.bind[[HOST, PORT]]
s.listen[]
conn, addr = s.accept[]
with conn:
print[f"Connected by {addr}"]
while True:
data = conn.recv[1024]
if not data:
break
conn.sendall[data]
62Tốt đấy.
# echo-server.py
# ...
with socket.socket[socket.AF_INET, socket.SOCK_STREAM] as s:
s.bind[[HOST, PORT]]
s.listen[]
conn, addr = s.accept[]
with conn:
print[f"Connected by {addr}"]
while True:
data = conn.recv[1024]
if not data:
break
conn.sendall[data]
621 thật đơn giản. Nó chỉ có thể làm hai việc. gọi # echo-server.py
# ...
with socket.socket[socket.AF_INET, socket.SOCK_STREAM] as s:
s.bind[[HOST, PORT]]
s.listen[]
conn, addr = s.accept[]
with conn:
print[f"Connected by {addr}"]
while True:
data = conn.recv[1024]
if not data:
break
conn.sendall[data]
625 và # echo-server.py
# ...
with socket.socket[socket.AF_INET, socket.SOCK_STREAM] as s:
s.bind[[HOST, PORT]]
s.listen[]
conn, addr = s.accept[]
with conn:
print[f"Connected by {addr}"]
while True:
data = conn.recv[1024]
if not data:
break
conn.sendall[data]
626Đây là nơi quản lý nhà nước đến. Nếu một phương thức khác phụ thuộc vào các biến trạng thái có một giá trị nhất định, thì chúng sẽ chỉ được gọi từ
# echo-server.py
# ...
with socket.socket[socket.AF_INET, socket.SOCK_STREAM] as s:
s.bind[[HOST, PORT]]
s.listen[]
conn, addr = s.accept[]
with conn:
print[f"Connected by {addr}"]
while True:
data = conn.recv[1024]
if not data:
break
conn.sendall[data]
625 và # echo-server.py
# ...
with socket.socket[socket.AF_INET, socket.SOCK_STREAM] as s:
s.bind[[HOST, PORT]]
s.listen[]
conn, addr = s.accept[]
with conn:
print[f"Connected by {addr}"]
while True:
data = conn.recv[1024]
if not data:
break
conn.sendall[data]
626. Điều này giữ cho logic càng đơn giản càng tốt khi các sự kiện xuất hiện trên ổ cắm để xử lýBạn có thể muốn sử dụng kết hợp một số phương thức để kiểm tra các biến trạng thái hiện tại và tùy thuộc vào giá trị của chúng, gọi các phương thức khác để xử lý dữ liệu bên ngoài
# echo-server.py
# ...
with socket.socket[socket.AF_INET, socket.SOCK_STREAM] as s:
s.bind[[HOST, PORT]]
s.listen[]
conn, addr = s.accept[]
with conn:
print[f"Connected by {addr}"]
while True:
data = conn.recv[1024]
if not data:
break
conn.sendall[data]
625 hoặc # echo-server.py
# ...
with socket.socket[socket.AF_INET, socket.SOCK_STREAM] as s:
s.bind[[HOST, PORT]]
s.listen[]
conn, addr = s.accept[]
with conn:
print[f"Connected by {addr}"]
while True:
data = conn.recv[1024]
if not data:
break
conn.sendall[data]
626. Cuối cùng, điều này có thể sẽ tỏ ra quá phức tạp để quản lý và theo kịpBạn chắc chắn nên sửa đổi lớp cho phù hợp với nhu cầu của riêng mình để nó hoạt động tốt nhất cho bạn, nhưng bạn có thể sẽ có kết quả tốt nhất nếu bạn giữ kiểm tra trạng thái và gọi các phương thức phụ thuộc vào trạng thái đó đối với các phương thức
# echo-server.py
# ...
with socket.socket[socket.AF_INET, socket.SOCK_STREAM] as s:
s.bind[[HOST, PORT]]
s.listen[]
conn, addr = s.accept[]
with conn:
print[f"Connected by {addr}"]
while True:
data = conn.recv[1024]
if not data:
break
conn.sendall[data]
625 và # echo-server.py
# ...
with socket.socket[socket.AF_INET, socket.SOCK_STREAM] as s:
s.bind[[HOST, PORT]]
s.listen[]
conn, addr = s.accept[]
with conn:
print[f"Connected by {addr}"]
while True:
data = conn.recv[1024]
if not data:
break
conn.sendall[data]
626 Bây giờ hãy nhìn vào
# echo-server.py
# ...
with socket.socket[socket.AF_INET, socket.SOCK_STREAM] as s:
s.bind[[HOST, PORT]]
s.listen[]
conn, addr = s.accept[]
with conn:
print[f"Connected by {addr}"]
while True:
data = conn.recv[1024]
if not data:
break
conn.sendall[data]
625. Đây là phiên bản của máy chủ, nhưng của khách hàng là như nhau. Nó chỉ sử dụng một tên phương thức khác, # echo-server.py
# ...
with socket.socket[socket.AF_INET, socket.SOCK_STREAM] as s:
s.bind[[HOST, PORT]]
s.listen[]
conn, addr = s.accept[]
with conn:
print[f"Connected by {addr}"]
while True:
data = conn.recv[1024]
if not data:
break
conn.sendall[data]
634 thay vì # echo-server.py
# ...
with socket.socket[socket.AF_INET, socket.SOCK_STREAM] as s:
s.bind[[HOST, PORT]]
s.listen[]
conn, addr = s.accept[]
with conn:
print[f"Connected by {addr}"]
while True:
data = conn.recv[1024]
if not data:
break
conn.sendall[data]
635# echo-server.py
# ...
with socket.socket[socket.AF_INET, socket.SOCK_STREAM] as s:
s.bind[[HOST, PORT]]
s.listen[]
conn, addr = s.accept[]
with conn:
print[f"Connected by {addr}"]
while True:
data = conn.recv[1024]
if not data:
break
conn.sendall[data]
63Phương thức
# echo-server.py
# ...
with socket.socket[socket.AF_INET, socket.SOCK_STREAM] as s:
s.bind[[HOST, PORT]]
s.listen[]
conn, addr = s.accept[]
with conn:
print[f"Connected by {addr}"]
while True:
data = conn.recv[1024]
if not data:
break
conn.sendall[data]
636 được gọi đầu tiên. Nó gọi # echo-server.py
# ...
with socket.socket[socket.AF_INET, socket.SOCK_STREAM] as s:
s.bind[[HOST, PORT]]
s.listen[]
conn, addr = s.accept[]
with conn:
print[f"Connected by {addr}"]
while True:
data = conn.recv[1024]
if not data:
break
conn.sendall[data]
637 để đọc dữ liệu từ ổ cắm và lưu trữ trong bộ đệm nhậnHãy nhớ rằng khi
# echo-server.py
# ...
with socket.socket[socket.AF_INET, socket.SOCK_STREAM] as s:
s.bind[[HOST, PORT]]
s.listen[]
conn, addr = s.accept[]
with conn:
print[f"Connected by {addr}"]
while True:
data = conn.recv[1024]
if not data:
break
conn.sendall[data]
637 được gọi, tất cả dữ liệu tạo thành một thông báo hoàn chỉnh có thể chưa đến. # echo-server.py
# ...
with socket.socket[socket.AF_INET, socket.SOCK_STREAM] as s:
s.bind[[HOST, PORT]]
s.listen[]
conn, addr = s.accept[]
with conn:
print[f"Connected by {addr}"]
while True:
data = conn.recv[1024]
if not data:
break
conn.sendall[data]
637 có thể cần được gọi lại. Đây là lý do tại sao có các kiểm tra trạng thái cho từng phần của thông báo trước khi phương thức thích hợp để xử lý nó được gọi làTrước khi một phương thức xử lý một phần thông báo của nó, trước tiên, nó sẽ kiểm tra để đảm bảo rằng đã đọc đủ byte vào bộ đệm nhận. If they have, it processes its respective bytes, removes them from the buffer and writes its output to a variable that’s used by the next processing stage. Vì có ba thành phần trong một thông báo nên có ba lần kiểm tra trạng thái và gọi phương thức
# echo-server.py
# ...
with socket.socket[socket.AF_INET, socket.SOCK_STREAM] as s:
s.bind[[HOST, PORT]]
s.listen[]
conn, addr = s.accept[]
with conn:
print[f"Connected by {addr}"]
while True:
data = conn.recv[1024]
if not data:
break
conn.sendall[data]
640Message ComponentMethodOutputTiêu đề có độ dài cố định
# echo-server.py
# ...
with socket.socket[socket.AF_INET, socket.SOCK_STREAM] as s:
s.bind[[HOST, PORT]]
s.listen[]
conn, addr = s.accept[]
with conn:
print[f"Connected by {addr}"]
while True:
data = conn.recv[1024]
if not data:
break
conn.sendall[data]
641# echo-server.py
# ...
with socket.socket[socket.AF_INET, socket.SOCK_STREAM] as s:
s.bind[[HOST, PORT]]
s.listen[]
conn, addr = s.accept[]
with conn:
print[f"Connected by {addr}"]
while True:
data = conn.recv[1024]
if not data:
break
conn.sendall[data]
642JSON header# echo-server.py
# ...
with socket.socket[socket.AF_INET, socket.SOCK_STREAM] as s:
s.bind[[HOST, PORT]]
s.listen[]
conn, addr = s.accept[]
with conn:
print[f"Connected by {addr}"]
while True:
data = conn.recv[1024]
if not data:
break
conn.sendall[data]
643# echo-server.py
# ...
with socket.socket[socket.AF_INET, socket.SOCK_STREAM] as s:
s.bind[[HOST, PORT]]
s.listen[]
conn, addr = s.accept[]
with conn:
print[f"Connected by {addr}"]
while True:
data = conn.recv[1024]
if not data:
break
conn.sendall[data]
644Content# echo-server.py
# ...
with socket.socket[socket.AF_INET, socket.SOCK_STREAM] as s:
s.bind[[HOST, PORT]]
s.listen[]
conn, addr = s.accept[]
with conn:
print[f"Connected by {addr}"]
while True:
data = conn.recv[1024]
if not data:
break
conn.sendall[data]
645# echo-server.py
# ...
with socket.socket[socket.AF_INET, socket.SOCK_STREAM] as s:
s.bind[[HOST, PORT]]
s.listen[]
conn, addr = s.accept[]
with conn:
print[f"Connected by {addr}"]
while True:
data = conn.recv[1024]
if not data:
break
conn.sendall[data]
646Tiếp theo, hãy xem
# echo-server.py
# ...
with socket.socket[socket.AF_INET, socket.SOCK_STREAM] as s:
s.bind[[HOST, PORT]]
s.listen[]
conn, addr = s.accept[]
with conn:
print[f"Connected by {addr}"]
while True:
data = conn.recv[1024]
if not data:
break
conn.sendall[data]
626. Đây là phiên bản của máy chủ# echo-server.py
# ...
with socket.socket[socket.AF_INET, socket.SOCK_STREAM] as s:
s.bind[[HOST, PORT]]
s.listen[]
conn, addr = s.accept[]
with conn:
print[f"Connected by {addr}"]
while True:
data = conn.recv[1024]
if not data:
break
conn.sendall[data]
64Phương pháp
# echo-server.py
# ...
with socket.socket[socket.AF_INET, socket.SOCK_STREAM] as s:
s.bind[[HOST, PORT]]
s.listen[]
conn, addr = s.accept[]
with conn:
print[f"Connected by {addr}"]
while True:
data = conn.recv[1024]
if not data:
break
conn.sendall[data]
626 trước tiên kiểm tra một # echo-server.py
# ...
with socket.socket[socket.AF_INET, socket.SOCK_STREAM] as s:
s.bind[[HOST, PORT]]
s.listen[]
conn, addr = s.accept[]
with conn:
print[f"Connected by {addr}"]
while True:
data = conn.recv[1024]
if not data:
break
conn.sendall[data]
649. Nếu một cái tồn tại và một phản hồi chưa được tạo, thì # echo-server.py
# ...
with socket.socket[socket.AF_INET, socket.SOCK_STREAM] as s:
s.bind[[HOST, PORT]]
s.listen[]
conn, addr = s.accept[]
with conn:
print[f"Connected by {addr}"]
while True:
data = conn.recv[1024]
if not data:
break
conn.sendall[data]
650 được gọi là. Phương thức # echo-server.py
# ...
with socket.socket[socket.AF_INET, socket.SOCK_STREAM] as s:
s.bind[[HOST, PORT]]
s.listen[]
conn, addr = s.accept[]
with conn:
print[f"Connected by {addr}"]
while True:
data = conn.recv[1024]
if not data:
break
conn.sendall[data]
650 đặt biến trạng thái # echo-server.py
# ...
with socket.socket[socket.AF_INET, socket.SOCK_STREAM] as s:
s.bind[[HOST, PORT]]
s.listen[]
conn, addr = s.accept[]
with conn:
print[f"Connected by {addr}"]
while True:
data = conn.recv[1024]
if not data:
break
conn.sendall[data]
652 và ghi phản hồi vào bộ đệm gửiPhương thức
# echo-server.py
# ...
with socket.socket[socket.AF_INET, socket.SOCK_STREAM] as s:
s.bind[[HOST, PORT]]
s.listen[]
conn, addr = s.accept[]
with conn:
print[f"Connected by {addr}"]
while True:
data = conn.recv[1024]
if not data:
break
conn.sendall[data]
653 gọi # echo-server.py
# ...
with socket.socket[socket.AF_INET, socket.SOCK_STREAM] as s:
s.bind[[HOST, PORT]]
s.listen[]
conn, addr = s.accept[]
with conn:
print[f"Connected by {addr}"]
while True:
data = conn.recv[1024]
if not data:
break
conn.sendall[data]
960 nếu có dữ liệu trong bộ đệm gửiHãy nhớ rằng khi
# echo-server.py
# ...
with socket.socket[socket.AF_INET, socket.SOCK_STREAM] as s:
s.bind[[HOST, PORT]]
s.listen[]
conn, addr = s.accept[]
with conn:
print[f"Connected by {addr}"]
while True:
data = conn.recv[1024]
if not data:
break
conn.sendall[data]
960 được gọi, tất cả dữ liệu trong bộ đệm gửi có thể chưa được xếp hàng đợi để truyền. Bộ đệm mạng cho ổ cắm có thể đầy và có thể cần gọi lại # echo-server.py
# ...
with socket.socket[socket.AF_INET, socket.SOCK_STREAM] as s:
s.bind[[HOST, PORT]]
s.listen[]
conn, addr = s.accept[]
with conn:
print[f"Connected by {addr}"]
while True:
data = conn.recv[1024]
if not data:
break
conn.sendall[data]
960. Đây là lý do tại sao có kiểm tra nhà nước. Phương thức # echo-server.py
# ...
with socket.socket[socket.AF_INET, socket.SOCK_STREAM] as s:
s.bind[[HOST, PORT]]
s.listen[]
conn, addr = s.accept[]
with conn:
print[f"Connected by {addr}"]
while True:
data = conn.recv[1024]
if not data:
break
conn.sendall[data]
650 chỉ nên được gọi một lần, nhưng dự kiến rằng # echo-server.py
# ...
with socket.socket[socket.AF_INET, socket.SOCK_STREAM] as s:
s.bind[[HOST, PORT]]
s.listen[]
conn, addr = s.accept[]
with conn:
print[f"Connected by {addr}"]
while True:
data = conn.recv[1024]
if not data:
break
conn.sendall[data]
653 sẽ cần được gọi nhiều lầnPhiên bản máy khách của
# echo-server.py
# ...
with socket.socket[socket.AF_INET, socket.SOCK_STREAM] as s:
s.bind[[HOST, PORT]]
s.listen[]
conn, addr = s.accept[]
with conn:
print[f"Connected by {addr}"]
while True:
data = conn.recv[1024]
if not data:
break
conn.sendall[data]
626 cũng tương tự# echo-server.py
# ...
with socket.socket[socket.AF_INET, socket.SOCK_STREAM] as s:
s.bind[[HOST, PORT]]
s.listen[]
conn, addr = s.accept[]
with conn:
print[f"Connected by {addr}"]
while True:
data = conn.recv[1024]
if not data:
break
conn.sendall[data]
65Vì máy khách bắt đầu kết nối với máy chủ và gửi yêu cầu trước nên biến trạng thái
# echo-server.py
# ...
with socket.socket[socket.AF_INET, socket.SOCK_STREAM] as s:
s.bind[[HOST, PORT]]
s.listen[]
conn, addr = s.accept[]
with conn:
print[f"Connected by {addr}"]
while True:
data = conn.recv[1024]
if not data:
break
conn.sendall[data]
660 được chọn. Nếu một yêu cầu chưa được xếp hàng đợi, nó sẽ gọi # echo-server.py
# ...
with socket.socket[socket.AF_INET, socket.SOCK_STREAM] as s:
s.bind[[HOST, PORT]]
s.listen[]
conn, addr = s.accept[]
with conn:
print[f"Connected by {addr}"]
while True:
data = conn.recv[1024]
if not data:
break
conn.sendall[data]
661. Phương thức # echo-server.py
# ...
with socket.socket[socket.AF_INET, socket.SOCK_STREAM] as s:
s.bind[[HOST, PORT]]
s.listen[]
conn, addr = s.accept[]
with conn:
print[f"Connected by {addr}"]
while True:
data = conn.recv[1024]
if not data:
break
conn.sendall[data]
662 tạo yêu cầu và ghi nó vào bộ đệm gửi. Nó cũng đặt biến trạng thái # echo-server.py
# ...
with socket.socket[socket.AF_INET, socket.SOCK_STREAM] as s:
s.bind[[HOST, PORT]]
s.listen[]
conn, addr = s.accept[]
with conn:
print[f"Connected by {addr}"]
while True:
data = conn.recv[1024]
if not data:
break
conn.sendall[data]
660 để nó chỉ được gọi một lầnCũng giống như đối với máy chủ,
# echo-server.py
# ...
with socket.socket[socket.AF_INET, socket.SOCK_STREAM] as s:
s.bind[[HOST, PORT]]
s.listen[]
conn, addr = s.accept[]
with conn:
print[f"Connected by {addr}"]
while True:
data = conn.recv[1024]
if not data:
break
conn.sendall[data]
653 gọi # echo-server.py
# ...
with socket.socket[socket.AF_INET, socket.SOCK_STREAM] as s:
s.bind[[HOST, PORT]]
s.listen[]
conn, addr = s.accept[]
with conn:
print[f"Connected by {addr}"]
while True:
data = conn.recv[1024]
if not data:
break
conn.sendall[data]
960 nếu có dữ liệu trong bộ đệm gửiSự khác biệt đáng chú ý trong phiên bản
# echo-server.py
# ...
with socket.socket[socket.AF_INET, socket.SOCK_STREAM] as s:
s.bind[[HOST, PORT]]
s.listen[]
conn, addr = s.accept[]
with conn:
print[f"Connected by {addr}"]
while True:
data = conn.recv[1024]
if not data:
break
conn.sendall[data]
626 của khách hàng là lần kiểm tra cuối cùng để xem yêu cầu đã được xếp hàng chưa. Điều này sẽ được giải thích thêm trong phần Client Main Script, nhưng lý do của việc này là để báo cho # echo-server.py
# ...
with socket.socket[socket.AF_INET, socket.SOCK_STREAM] as s:
s.bind[[HOST, PORT]]
s.listen[]
conn, addr = s.accept[]
with conn:
print[f"Connected by {addr}"]
while True:
data = conn.recv[1024]
if not data:
break
conn.sendall[data]
616 ngừng theo dõi ổ cắm để ghi các sự kiện. Nếu yêu cầu đã được xếp hàng đợi và bộ đệm gửi trống, thì bạn đã viết xong và bạn chỉ quan tâm đến các sự kiện đã đọc. Không có lý do gì để được thông báo rằng ổ cắm có thể ghiĐể kết thúc phần này, hãy xem xét suy nghĩ này. mục đích chính của phần này là để giải thích rằng
# echo-server.py
# ...
with socket.socket[socket.AF_INET, socket.SOCK_STREAM] as s:
s.bind[[HOST, PORT]]
s.listen[]
conn, addr = s.accept[]
with conn:
print[f"Connected by {addr}"]
while True:
data = conn.recv[1024]
if not data:
break
conn.sendall[data]
616 đang gọi vào lớp # echo-server.py
# ...
with socket.socket[socket.AF_INET, socket.SOCK_STREAM] as s:
s.bind[[HOST, PORT]]
s.listen[]
conn, addr = s.accept[]
with conn:
print[f"Connected by {addr}"]
while True:
data = conn.recv[1024]
if not data:
break
conn.sendall[data]
993 thông qua phương thức # echo-server.py
# ...
with socket.socket[socket.AF_INET, socket.SOCK_STREAM] as s:
s.bind[[HOST, PORT]]
s.listen[]
conn, addr = s.accept[]
with conn:
print[f"Connected by {addr}"]
while True:
data = conn.recv[1024]
if not data:
break
conn.sendall[data]
621 và để mô tả cách quản lý trạng tháiĐiều này rất quan trọng vì
# echo-server.py
# ...
with socket.socket[socket.AF_INET, socket.SOCK_STREAM] as s:
s.bind[[HOST, PORT]]
s.listen[]
conn, addr = s.accept[]
with conn:
print[f"Connected by {addr}"]
while True:
data = conn.recv[1024]
if not data:
break
conn.sendall[data]
621 sẽ được gọi nhiều lần trong suốt thời gian kết nối. Do đó, hãy đảm bảo rằng bất kỳ phương thức nào chỉ nên được gọi một lần đều đang tự kiểm tra biến trạng thái hoặc biến trạng thái do phương thức đặt được kiểm tra bởi người gọiTập lệnh chính của máy chủ
Trong tập lệnh chính của máy chủ
# echo-server.py
# ...
with socket.socket[socket.AF_INET, socket.SOCK_STREAM] as s:
s.bind[[HOST, PORT]]
s.listen[]
conn, addr = s.accept[]
with conn:
print[f"Connected by {addr}"]
while True:
data = conn.recv[1024]
if not data:
break
conn.sendall[data]
998, các đối số được đọc từ dòng lệnh chỉ định giao diện và cổng để nghe trên đó# echo-server.py
# ...
with socket.socket[socket.AF_INET, socket.SOCK_STREAM] as s:
s.bind[[HOST, PORT]]
s.listen[]
conn, addr = s.accept[]
with conn:
print[f"Connected by {addr}"]
while True:
data = conn.recv[1024]
if not data:
break
conn.sendall[data]
66Ví dụ: để nghe trên giao diện loopback trên cổng
# echo-server.py
# ...
with socket.socket[socket.AF_INET, socket.SOCK_STREAM] as s:
s.bind[[HOST, PORT]]
s.listen[]
conn, addr = s.accept[]
with conn:
print[f"Connected by {addr}"]
while True:
data = conn.recv[1024]
if not data:
break
conn.sendall[data]
673, hãy nhập# echo-server.py
# ...
with socket.socket[socket.AF_INET, socket.SOCK_STREAM] as s:
s.bind[[HOST, PORT]]
s.listen[]
conn, addr = s.accept[]
with conn:
print[f"Connected by {addr}"]
while True:
data = conn.recv[1024]
if not data:
break
conn.sendall[data]
67Sử dụng một chuỗi trống cho
# echo-server.py
# ...
with socket.socket[socket.AF_INET, socket.SOCK_STREAM] as s:
s.bind[[HOST, PORT]]
s.listen[]
conn, addr = s.accept[]
with conn:
print[f"Connected by {addr}"]
while True:
data = conn.recv[1024]
if not data:
break
conn.sendall[data]
674 để nghe trên tất cả các giao diệnSau khi tạo ổ cắm, một cuộc gọi được thực hiện tới
# echo-server.py
# ...
with socket.socket[socket.AF_INET, socket.SOCK_STREAM] as s:
s.bind[[HOST, PORT]]
s.listen[]
conn, addr = s.accept[]
with conn:
print[f"Connected by {addr}"]
while True:
data = conn.recv[1024]
if not data:
break
conn.sendall[data]
675 với tùy chọn # echo-server.py
# ...
with socket.socket[socket.AF_INET, socket.SOCK_STREAM] as s:
s.bind[[HOST, PORT]]
s.listen[]
conn, addr = s.accept[]
with conn:
print[f"Connected by {addr}"]
while True:
data = conn.recv[1024]
if not data:
break
conn.sendall[data]
676# echo-server.py
# ...
with socket.socket[socket.AF_INET, socket.SOCK_STREAM] as s:
s.bind[[HOST, PORT]]
s.listen[]
conn, addr = s.accept[]
with conn:
print[f"Connected by {addr}"]
while True:
data = conn.recv[1024]
if not data:
break
conn.sendall[data]
68Đặt tùy chọn ổ cắm này sẽ tránh được lỗi
# echo-server.py
# ...
with socket.socket[socket.AF_INET, socket.SOCK_STREAM] as s:
s.bind[[HOST, PORT]]
s.listen[]
conn, addr = s.accept[]
with conn:
print[f"Connected by {addr}"]
while True:
data = conn.recv[1024]
if not data:
break
conn.sendall[data]
677. Bạn sẽ thấy điều này khi khởi động máy chủ trên một cổng có kết nối ở trạng thái TIME_WAITVí dụ: nếu máy chủ chủ động đóng kết nối, nó sẽ duy trì ở trạng thái
# echo-server.py
# ...
with socket.socket[socket.AF_INET, socket.SOCK_STREAM] as s:
s.bind[[HOST, PORT]]
s.listen[]
conn, addr = s.accept[]
with conn:
print[f"Connected by {addr}"]
while True:
data = conn.recv[1024]
if not data:
break
conn.sendall[data]
678 trong hai phút trở lên, tùy thuộc vào hệ điều hành. Nếu bạn cố gắng khởi động lại máy chủ trước khi trạng thái # echo-server.py
# ...
with socket.socket[socket.AF_INET, socket.SOCK_STREAM] as s:
s.bind[[HOST, PORT]]
s.listen[]
conn, addr = s.accept[]
with conn:
print[f"Connected by {addr}"]
while True:
data = conn.recv[1024]
if not data:
break
conn.sendall[data]
678 hết hạn, thì bạn sẽ nhận được một ngoại lệ # echo-server.py
# ...
with socket.socket[socket.AF_INET, socket.SOCK_STREAM] as s:
s.bind[[HOST, PORT]]
s.listen[]
conn, addr = s.accept[]
with conn:
print[f"Connected by {addr}"]
while True:
data = conn.recv[1024]
if not data:
break
conn.sendall[data]
970 của # echo-server.py
# ...
with socket.socket[socket.AF_INET, socket.SOCK_STREAM] as s:
s.bind[[HOST, PORT]]
s.listen[]
conn, addr = s.accept[]
with conn:
print[f"Connected by {addr}"]
while True:
data = conn.recv[1024]
if not data:
break
conn.sendall[data]
677. Đây là một biện pháp bảo vệ để đảm bảo rằng bất kỳ gói bị trì hoãn nào trong mạng không được gửi đến ứng dụng saiVòng lặp sự kiện bắt bất kỳ lỗi nào để máy chủ có thể duy trì và tiếp tục chạy
# echo-server.py
# ...
with socket.socket[socket.AF_INET, socket.SOCK_STREAM] as s:
s.bind[[HOST, PORT]]
s.listen[]
conn, addr = s.accept[]
with conn:
print[f"Connected by {addr}"]
while True:
data = conn.recv[1024]
if not data:
break
conn.sendall[data]
69Khi kết nối máy khách được chấp nhận, đối tượng
# echo-server.py
# ...
with socket.socket[socket.AF_INET, socket.SOCK_STREAM] as s:
s.bind[[HOST, PORT]]
s.listen[]
conn, addr = s.accept[]
with conn:
print[f"Connected by {addr}"]
while True:
data = conn.recv[1024]
if not data:
break
conn.sendall[data]
993 được tạo# echo-server.py
# ...
with socket.socket[socket.AF_INET, socket.SOCK_STREAM] as s:
s.bind[[HOST, PORT]]
s.listen[]
conn, addr = s.accept[]
with conn:
print[f"Connected by {addr}"]
while True:
data = conn.recv[1024]
if not data:
break
conn.sendall[data]
60Đối tượng
# echo-server.py
# ...
with socket.socket[socket.AF_INET, socket.SOCK_STREAM] as s:
s.bind[[HOST, PORT]]
s.listen[]
conn, addr = s.accept[]
with conn:
print[f"Connected by {addr}"]
while True:
data = conn.recv[1024]
if not data:
break
conn.sendall[data]
993 được liên kết với ổ cắm trong lệnh gọi tới # echo-server.py
# ...
with socket.socket[socket.AF_INET, socket.SOCK_STREAM] as s:
s.bind[[HOST, PORT]]
s.listen[]
conn, addr = s.accept[]
with conn:
print[f"Connected by {addr}"]
while True:
data = conn.recv[1024]
if not data:
break
conn.sendall[data]
902 và ban đầu được đặt để chỉ giám sát các sự kiện đọc. Khi yêu cầu đã được đọc, bạn sẽ sửa đổi nó để chỉ lắng nghe các sự kiện ghiMột lợi thế của việc sử dụng phương pháp này trong máy chủ là trong hầu hết các trường hợp, khi ổ cắm hoạt động tốt và không có sự cố mạng, nó sẽ luôn có thể ghi được
Nếu bạn yêu cầu
# echo-server.py
# ...
with socket.socket[socket.AF_INET, socket.SOCK_STREAM] as s:
s.bind[[HOST, PORT]]
s.listen[]
conn, addr = s.accept[]
with conn:
print[f"Connected by {addr}"]
while True:
data = conn.recv[1024]
if not data:
break
conn.sendall[data]
902 cũng theo dõi # echo-server.py
# ...
with socket.socket[socket.AF_INET, socket.SOCK_STREAM] as s:
s.bind[[HOST, PORT]]
s.listen[]
conn, addr = s.accept[]
with conn:
print[f"Connected by {addr}"]
while True:
data = conn.recv[1024]
if not data:
break
conn.sendall[data]
686, thì vòng lặp sự kiện sẽ ngay lập tức thức dậy và thông báo cho bạn rằng đây là trường hợp. Tuy nhiên, tại thời điểm này, không có lý do gì để thức dậy và gọi # echo-server.py
# ...
with socket.socket[socket.AF_INET, socket.SOCK_STREAM] as s:
s.bind[[HOST, PORT]]
s.listen[]
conn, addr = s.accept[]
with conn:
print[f"Connected by {addr}"]
while True:
data = conn.recv[1024]
if not data:
break
conn.sendall[data]
4 trên ổ cắm. Không có phản hồi để gửi vì yêu cầu chưa được xử lý. Điều này sẽ tiêu tốn và lãng phí các chu kỳ CPU có giá trịLớp tin nhắn máy chủ
Trong phần Điểm nhập thông báo, bạn đã học cách đối tượng
# echo-server.py
# ...
with socket.socket[socket.AF_INET, socket.SOCK_STREAM] as s:
s.bind[[HOST, PORT]]
s.listen[]
conn, addr = s.accept[]
with conn:
print[f"Connected by {addr}"]
while True:
data = conn.recv[1024]
if not data:
break
conn.sendall[data]
993 được gọi vào hoạt động khi các sự kiện ổ cắm đã sẵn sàng thông qua # echo-server.py
# ...
with socket.socket[socket.AF_INET, socket.SOCK_STREAM] as s:
s.bind[[HOST, PORT]]
s.listen[]
conn, addr = s.accept[]
with conn:
print[f"Connected by {addr}"]
while True:
data = conn.recv[1024]
if not data:
break
conn.sendall[data]
621. Bây giờ, bạn sẽ tìm hiểu điều gì sẽ xảy ra khi dữ liệu được đọc trên ổ cắm và một thành phần hoặc một phần của thông báo đã sẵn sàng để máy chủ xử lýThe server’s message class is in
# echo-server.py
# ...
with socket.socket[socket.AF_INET, socket.SOCK_STREAM] as s:
s.bind[[HOST, PORT]]
s.listen[]
conn, addr = s.accept[]
with conn:
print[f"Connected by {addr}"]
while True:
data = conn.recv[1024]
if not data:
break
conn.sendall[data]
607, which is part of the source code you downloaded earlier. Bạn cũng có thể tải xuống mã bằng cách nhấp vào liên kết bên dướiGet Source Code. Click here to get the source code you’ll use for the examples in this tutorial
Các phương thức xuất hiện trong lớp theo thứ tự xử lý thông báo
Khi máy chủ đã đọc ít nhất hai byte, tiêu đề có độ dài cố định có thể được xử lý
# echo-server.py
# ...
with socket.socket[socket.AF_INET, socket.SOCK_STREAM] as s:
s.bind[[HOST, PORT]]
s.listen[]
conn, addr = s.accept[]
with conn:
print[f"Connected by {addr}"]
while True:
data = conn.recv[1024]
if not data:
break
conn.sendall[data]
61Tiêu đề có độ dài cố định là một số nguyên 2 byte theo thứ tự byte mạng hoặc big-endian. Nó chứa độ dài của tiêu đề JSON. Bạn sẽ sử dụng cấu trúc. unpack[] để đọc giá trị, giải mã và lưu trữ trong
# echo-server.py
# ...
with socket.socket[socket.AF_INET, socket.SOCK_STREAM] as s:
s.bind[[HOST, PORT]]
s.listen[]
conn, addr = s.accept[]
with conn:
print[f"Connected by {addr}"]
while True:
data = conn.recv[1024]
if not data:
break
conn.sendall[data]
642. Sau khi xử lý đoạn tin nhắn mà nó chịu trách nhiệm, # echo-server.py
# ...
with socket.socket[socket.AF_INET, socket.SOCK_STREAM] as s:
s.bind[[HOST, PORT]]
s.listen[]
conn, addr = s.accept[]
with conn:
print[f"Connected by {addr}"]
while True:
data = conn.recv[1024]
if not data:
break
conn.sendall[data]
692 xóa nó khỏi bộ đệm nhậnCũng giống như tiêu đề có độ dài cố định, khi có đủ dữ liệu trong bộ đệm nhận để chứa tiêu đề JSON, nó cũng có thể được xử lý
# echo-server.py
# ...
with socket.socket[socket.AF_INET, socket.SOCK_STREAM] as s:
s.bind[[HOST, PORT]]
s.listen[]
conn, addr = s.accept[]
with conn:
print[f"Connected by {addr}"]
while True:
data = conn.recv[1024]
if not data:
break
conn.sendall[data]
62Phương thức
# echo-server.py
# ...
with socket.socket[socket.AF_INET, socket.SOCK_STREAM] as s:
s.bind[[HOST, PORT]]
s.listen[]
conn, addr = s.accept[]
with conn:
print[f"Connected by {addr}"]
while True:
data = conn.recv[1024]
if not data:
break
conn.sendall[data]
693 được gọi để giải mã và giải tuần tự hóa tiêu đề JSON thành một từ điển. Vì tiêu đề JSON được xác định là Unicode với mã hóa UTF-8, nên # echo-server.py
# ...
with socket.socket[socket.AF_INET, socket.SOCK_STREAM] as s:
s.bind[[HOST, PORT]]
s.listen[]
conn, addr = s.accept[]
with conn:
print[f"Connected by {addr}"]
while True:
data = conn.recv[1024]
if not data:
break
conn.sendall[data]
985 được mã hóa cứng trong cuộc gọi. Kết quả được lưu vào # echo-server.py
# ...
with socket.socket[socket.AF_INET, socket.SOCK_STREAM] as s:
s.bind[[HOST, PORT]]
s.listen[]
conn, addr = s.accept[]
with conn:
print[f"Connected by {addr}"]
while True:
data = conn.recv[1024]
if not data:
break
conn.sendall[data]
644. Sau khi xử lý đoạn tin nhắn mà nó chịu trách nhiệm, # echo-server.py
# ...
with socket.socket[socket.AF_INET, socket.SOCK_STREAM] as s:
s.bind[[HOST, PORT]]
s.listen[]
conn, addr = s.accept[]
with conn:
print[f"Connected by {addr}"]
while True:
data = conn.recv[1024]
if not data:
break
conn.sendall[data]
643 xóa nó khỏi bộ đệm nhậnTiếp theo là nội dung thực tế hoặc tải trọng của tin nhắn. Nó được mô tả bằng tiêu đề JSON trong
# echo-server.py
# ...
with socket.socket[socket.AF_INET, socket.SOCK_STREAM] as s:
s.bind[[HOST, PORT]]
s.listen[]
conn, addr = s.accept[]
with conn:
print[f"Connected by {addr}"]
while True:
data = conn.recv[1024]
if not data:
break
conn.sendall[data]
644. Khi # echo-server.py
# ...
with socket.socket[socket.AF_INET, socket.SOCK_STREAM] as s:
s.bind[[HOST, PORT]]
s.listen[]
conn, addr = s.accept[]
with conn:
print[f"Connected by {addr}"]
while True:
data = conn.recv[1024]
if not data:
break
conn.sendall[data]
980 byte có sẵn trong bộ đệm nhận, yêu cầu có thể được xử lý# echo-server.py
# ...
with socket.socket[socket.AF_INET, socket.SOCK_STREAM] as s:
s.bind[[HOST, PORT]]
s.listen[]
conn, addr = s.accept[]
with conn:
print[f"Connected by {addr}"]
while True:
data = conn.recv[1024]
if not data:
break
conn.sendall[data]
63Sau khi lưu nội dung tin nhắn vào biến
# echo-server.py
# ...
with socket.socket[socket.AF_INET, socket.SOCK_STREAM] as s:
s.bind[[HOST, PORT]]
s.listen[]
conn, addr = s.accept[]
with conn:
print[f"Connected by {addr}"]
while True:
data = conn.recv[1024]
if not data:
break
conn.sendall[data]
905, # echo-server.py
# ...
with socket.socket[socket.AF_INET, socket.SOCK_STREAM] as s:
s.bind[[HOST, PORT]]
s.listen[]
conn, addr = s.accept[]
with conn:
print[f"Connected by {addr}"]
while True:
data = conn.recv[1024]
if not data:
break
conn.sendall[data]
635 xóa nó khỏi bộ đệm nhận. Sau đó, nếu loại nội dung là JSON, # echo-server.py
# ...
with socket.socket[socket.AF_INET, socket.SOCK_STREAM] as s:
s.bind[[HOST, PORT]]
s.listen[]
conn, addr = s.accept[]
with conn:
print[f"Connected by {addr}"]
while True:
data = conn.recv[1024]
if not data:
break
conn.sendall[data]
635 sẽ giải mã và giải tuần tự hóa nó. Nếu không, ứng dụng ví dụ này giả định rằng đó là một yêu cầu nhị phân và chỉ cần in loại nội dungĐiều cuối cùng mà
# echo-server.py
# ...
with socket.socket[socket.AF_INET, socket.SOCK_STREAM] as s:
s.bind[[HOST, PORT]]
s.listen[]
conn, addr = s.accept[]
with conn:
print[f"Connected by {addr}"]
while True:
data = conn.recv[1024]
if not data:
break
conn.sendall[data]
635 thực hiện là sửa đổi bộ chọn để chỉ giám sát các sự kiện ghi. Trong tập lệnh chính của máy chủ, # echo-server.py
# ...
with socket.socket[socket.AF_INET, socket.SOCK_STREAM] as s:
s.bind[[HOST, PORT]]
s.listen[]
conn, addr = s.accept[]
with conn:
print[f"Connected by {addr}"]
while True:
data = conn.recv[1024]
if not data:
break
conn.sendall[data]
998, ổ cắm ban đầu được đặt để chỉ giám sát các sự kiện đã đọc. Giờ đây, yêu cầu đã được xử lý hoàn toàn, bạn không còn hứng thú đọc nữaBây giờ một phản hồi có thể được tạo và ghi vào ổ cắm. Khi ổ cắm có thể ghi,
# echo-server.py
# ...
with socket.socket[socket.AF_INET, socket.SOCK_STREAM] as s:
s.bind[[HOST, PORT]]
s.listen[]
conn, addr = s.accept[]
with conn:
print[f"Connected by {addr}"]
while True:
data = conn.recv[1024]
if not data:
break
conn.sendall[data]
650 được gọi từ # echo-server.py
# ...
with socket.socket[socket.AF_INET, socket.SOCK_STREAM] as s:
s.bind[[HOST, PORT]]
s.listen[]
conn, addr = s.accept[]
with conn:
print[f"Connected by {addr}"]
while True:
data = conn.recv[1024]
if not data:
break
conn.sendall[data]
626# echo-server.py
# ...
with socket.socket[socket.AF_INET, socket.SOCK_STREAM] as s:
s.bind[[HOST, PORT]]
s.listen[]
conn, addr = s.accept[]
with conn:
print[f"Connected by {addr}"]
while True:
data = conn.recv[1024]
if not data:
break
conn.sendall[data]
64Một phản hồi được tạo bằng cách gọi các phương thức khác, tùy thuộc vào loại nội dung. Trong ứng dụng ví dụ này, một tra cứu từ điển đơn giản được thực hiện cho các yêu cầu JSON khi
# echo-server.py
# ...
with socket.socket[socket.AF_INET, socket.SOCK_STREAM] as s:
s.bind[[HOST, PORT]]
s.listen[]
conn, addr = s.accept[]
with conn:
print[f"Connected by {addr}"]
while True:
data = conn.recv[1024]
if not data:
break
conn.sendall[data]
606. Đối với các ứng dụng của riêng bạn, bạn có thể xác định các phương thức khác được gọi tại đâySau khi tạo thông báo phản hồi, biến trạng thái
# echo-server.py
# ...
with socket.socket[socket.AF_INET, socket.SOCK_STREAM] as s:
s.bind[[HOST, PORT]]
s.listen[]
conn, addr = s.accept[]
with conn:
print[f"Connected by {addr}"]
while True:
data = conn.recv[1024]
if not data:
break
conn.sendall[data]
607 được đặt để # echo-server.py
# ...
with socket.socket[socket.AF_INET, socket.SOCK_STREAM] as s:
s.bind[[HOST, PORT]]
s.listen[]
conn, addr = s.accept[]
with conn:
print[f"Connected by {addr}"]
while True:
data = conn.recv[1024]
if not data:
break
conn.sendall[data]
626 không gọi lại # echo-server.py
# ...
with socket.socket[socket.AF_INET, socket.SOCK_STREAM] as s:
s.bind[[HOST, PORT]]
s.listen[]
conn, addr = s.accept[]
with conn:
print[f"Connected by {addr}"]
while True:
data = conn.recv[1024]
if not data:
break
conn.sendall[data]
650. Cuối cùng, phản hồi được thêm vào bộ đệm gửi. Điều này được nhìn thấy và gửi qua # echo-server.py
# ...
with socket.socket[socket.AF_INET, socket.SOCK_STREAM] as s:
s.bind[[HOST, PORT]]
s.listen[]
conn, addr = s.accept[]
with conn:
print[f"Connected by {addr}"]
while True:
data = conn.recv[1024]
if not data:
break
conn.sendall[data]
653Một chút khó khăn để tìm ra là làm thế nào để đóng kết nối sau khi phản hồi được viết. Bạn có thể thực hiện cuộc gọi đến
# echo-server.py
# ...
with socket.socket[socket.AF_INET, socket.SOCK_STREAM] as s:
s.bind[[HOST, PORT]]
s.listen[]
conn, addr = s.accept[]
with conn:
print[f"Connected by {addr}"]
while True:
data = conn.recv[1024]
if not data:
break
conn.sendall[data]
6 theo phương thức # echo-server.py
# ...
with socket.socket[socket.AF_INET, socket.SOCK_STREAM] as s:
s.bind[[HOST, PORT]]
s.listen[]
conn, addr = s.accept[]
with conn:
print[f"Connected by {addr}"]
while True:
data = conn.recv[1024]
if not data:
break
conn.sendall[data]
653# echo-server.py
# ...
with socket.socket[socket.AF_INET, socket.SOCK_STREAM] as s:
s.bind[[HOST, PORT]]
s.listen[]
conn, addr = s.accept[]
with conn:
print[f"Connected by {addr}"]
while True:
data = conn.recv[1024]
if not data:
break
conn.sendall[data]
65Mặc dù nó hơi bị ẩn nhưng đây là một sự đánh đổi có thể chấp nhận được vì lớp
# echo-server.py
# ...
with socket.socket[socket.AF_INET, socket.SOCK_STREAM] as s:
s.bind[[HOST, PORT]]
s.listen[]
conn, addr = s.accept[]
with conn:
print[f"Connected by {addr}"]
while True:
data = conn.recv[1024]
if not data:
break
conn.sendall[data]
993 chỉ xử lý một thông báo cho mỗi kết nối. Sau khi phản hồi được viết, máy chủ không còn việc gì để làm. Nó đã hoàn thành công việc của nóTập lệnh chính của khách hàng
Trong tập lệnh chính của máy khách,
# echo-server.py
# ...
with socket.socket[socket.AF_INET, socket.SOCK_STREAM] as s:
s.bind[[HOST, PORT]]
s.listen[]
conn, addr = s.accept[]
with conn:
print[f"Connected by {addr}"]
while True:
data = conn.recv[1024]
if not data:
break
conn.sendall[data]
997, các đối số được đọc từ dòng lệnh và được sử dụng để tạo yêu cầu và bắt đầu kết nối với máy chủ# echo-server.py
# ...
with socket.socket[socket.AF_INET, socket.SOCK_STREAM] as s:
s.bind[[HOST, PORT]]
s.listen[]
conn, addr = s.accept[]
with conn:
print[f"Connected by {addr}"]
while True:
data = conn.recv[1024]
if not data:
break
conn.sendall[data]
66Đây là một ví dụ
# echo-server.py
# ...
with socket.socket[socket.AF_INET, socket.SOCK_STREAM] as s:
s.bind[[HOST, PORT]]
s.listen[]
conn, addr = s.accept[]
with conn:
print[f"Connected by {addr}"]
while True:
data = conn.recv[1024]
if not data:
break
conn.sendall[data]
67Sau khi tạo một từ điển đại diện cho yêu cầu từ các đối số dòng lệnh, máy chủ, cổng và từ điển yêu cầu được chuyển đến
# echo-server.py
# ...
with socket.socket[socket.AF_INET, socket.SOCK_STREAM] as s:
s.bind[[HOST, PORT]]
s.listen[]
conn, addr = s.accept[]
with conn:
print[f"Connected by {addr}"]
while True:
data = conn.recv[1024]
if not data:
break
conn.sendall[data]
615# echo-server.py
# ...
with socket.socket[socket.AF_INET, socket.SOCK_STREAM] as s:
s.bind[[HOST, PORT]]
s.listen[]
conn, addr = s.accept[]
with conn:
print[f"Connected by {addr}"]
while True:
data = conn.recv[1024]
if not data:
break
conn.sendall[data]
68Ổ cắm được tạo cho kết nối máy chủ, cũng như đối tượng
# echo-server.py
# ...
with socket.socket[socket.AF_INET, socket.SOCK_STREAM] as s:
s.bind[[HOST, PORT]]
s.listen[]
conn, addr = s.accept[]
with conn:
print[f"Connected by {addr}"]
while True:
data = conn.recv[1024]
if not data:
break
conn.sendall[data]
993 sử dụng từ điển # echo-server.py
# ...
with socket.socket[socket.AF_INET, socket.SOCK_STREAM] as s:
s.bind[[HOST, PORT]]
s.listen[]
conn, addr = s.accept[]
with conn:
print[f"Connected by {addr}"]
while True:
data = conn.recv[1024]
if not data:
break
conn.sendall[data]
649Giống như đối với máy chủ, đối tượng
# echo-server.py
# ...
with socket.socket[socket.AF_INET, socket.SOCK_STREAM] as s:
s.bind[[HOST, PORT]]
s.listen[]
conn, addr = s.accept[]
with conn:
print[f"Connected by {addr}"]
while True:
data = conn.recv[1024]
if not data:
break
conn.sendall[data]
993 được liên kết với ổ cắm trong lệnh gọi tới # echo-server.py
# ...
with socket.socket[socket.AF_INET, socket.SOCK_STREAM] as s:
s.bind[[HOST, PORT]]
s.listen[]
conn, addr = s.accept[]
with conn:
print[f"Connected by {addr}"]
while True:
data = conn.recv[1024]
if not data:
break
conn.sendall[data]
902. Tuy nhiên, đối với máy khách, ổ cắm ban đầu được đặt để được giám sát cho cả sự kiện đọc và ghi. Khi yêu cầu đã được viết, bạn sẽ sửa đổi nó để chỉ lắng nghe các sự kiện đã đọcCách tiếp cận này mang lại cho bạn lợi thế giống như máy chủ. không lãng phí chu kỳ CPU. Sau khi yêu cầu đã được gửi, bạn không còn quan tâm đến các sự kiện viết nữa, vì vậy không có lý do gì để thức dậy và xử lý chúng
Lớp tin nhắn khách hàng
In the section Message Entry Point, you learned how the message object was called into action when socket events were ready via
# echo-server.py
# ...
with socket.socket[socket.AF_INET, socket.SOCK_STREAM] as s:
s.bind[[HOST, PORT]]
s.listen[]
conn, addr = s.accept[]
with conn:
print[f"Connected by {addr}"]
while True:
data = conn.recv[1024]
if not data:
break
conn.sendall[data]
621. Bây giờ bạn sẽ tìm hiểu điều gì sẽ xảy ra sau khi dữ liệu được đọc và ghi trên ổ cắm và một thông báo đã sẵn sàng để máy khách xử lýLớp thông báo của khách hàng nằm trong
# echo-server.py
# ...
with socket.socket[socket.AF_INET, socket.SOCK_STREAM] as s:
s.bind[[HOST, PORT]]
s.listen[]
conn, addr = s.accept[]
with conn:
print[f"Connected by {addr}"]
while True:
data = conn.recv[1024]
if not data:
break
conn.sendall[data]
610, đây là một phần của mã nguồn mà bạn đã tải xuống trước đó. Bạn cũng có thể tải xuống mã bằng cách nhấp vào liên kết bên dướiGet Source Code. Click here to get the source code you’ll use for the examples in this tutorial
Các phương thức xuất hiện trong lớp theo thứ tự xử lý thông báo
Nhiệm vụ đầu tiên cho khách hàng là xếp hàng yêu cầu
# echo-server.py
# ...
with socket.socket[socket.AF_INET, socket.SOCK_STREAM] as s:
s.bind[[HOST, PORT]]
s.listen[]
conn, addr = s.accept[]
with conn:
print[f"Connected by {addr}"]
while True:
data = conn.recv[1024]
if not data:
break
conn.sendall[data]
69Từ điển được sử dụng để tạo yêu cầu, tùy thuộc vào nội dung được truyền trên dòng lệnh, nằm trong tập lệnh chính của máy khách,
# echo-server.py
# ...
with socket.socket[socket.AF_INET, socket.SOCK_STREAM] as s:
s.bind[[HOST, PORT]]
s.listen[]
conn, addr = s.accept[]
with conn:
print[f"Connected by {addr}"]
while True:
data = conn.recv[1024]
if not data:
break
conn.sendall[data]
997. Từ điển yêu cầu được truyền dưới dạng đối số cho lớp khi đối tượng # echo-server.py
# ...
with socket.socket[socket.AF_INET, socket.SOCK_STREAM] as s:
s.bind[[HOST, PORT]]
s.listen[]
conn, addr = s.accept[]
with conn:
print[f"Connected by {addr}"]
while True:
data = conn.recv[1024]
if not data:
break
conn.sendall[data]
993 được tạoThông báo yêu cầu được tạo và nối vào bộ đệm gửi, sau đó được nhìn thấy và gửi qua
# echo-server.py
# ...
with socket.socket[socket.AF_INET, socket.SOCK_STREAM] as s:
s.bind[[HOST, PORT]]
s.listen[]
conn, addr = s.accept[]
with conn:
print[f"Connected by {addr}"]
while True:
data = conn.recv[1024]
if not data:
break
conn.sendall[data]
653. Biến trạng thái # echo-server.py
# ...
with socket.socket[socket.AF_INET, socket.SOCK_STREAM] as s:
s.bind[[HOST, PORT]]
s.listen[]
conn, addr = s.accept[]
with conn:
print[f"Connected by {addr}"]
while True:
data = conn.recv[1024]
if not data:
break
conn.sendall[data]
625 được đặt sao cho # echo-server.py
# ...
with socket.socket[socket.AF_INET, socket.SOCK_STREAM] as s:
s.bind[[HOST, PORT]]
s.listen[]
conn, addr = s.accept[]
with conn:
print[f"Connected by {addr}"]
while True:
data = conn.recv[1024]
if not data:
break
conn.sendall[data]
661 không được gọi lạiSau khi yêu cầu đã được gửi, máy khách chờ phản hồi từ máy chủ
Các phương pháp đọc và xử lý tin nhắn trong máy khách cũng giống như đối với máy chủ. Khi dữ liệu phản hồi được đọc từ ổ cắm, các phương thức tiêu đề
# echo-server.py
# ...
with socket.socket[socket.AF_INET, socket.SOCK_STREAM] as s:
s.bind[[HOST, PORT]]
s.listen[]
conn, addr = s.accept[]
with conn:
print[f"Connected by {addr}"]
while True:
data = conn.recv[1024]
if not data:
break
conn.sendall[data]
640 được gọi. # echo-server.py
# ...
with socket.socket[socket.AF_INET, socket.SOCK_STREAM] as s:
s.bind[[HOST, PORT]]
s.listen[]
conn, addr = s.accept[]
with conn:
print[f"Connected by {addr}"]
while True:
data = conn.recv[1024]
if not data:
break
conn.sendall[data]
692 và # echo-server.py
# ...
with socket.socket[socket.AF_INET, socket.SOCK_STREAM] as s:
s.bind[[HOST, PORT]]
s.listen[]
conn, addr = s.accept[]
with conn:
print[f"Connected by {addr}"]
while True:
data = conn.recv[1024]
if not data:
break
conn.sendall[data]
629Sự khác biệt nằm ở cách đặt tên của các phương thức
# echo-server.py
# ...
with socket.socket[socket.AF_INET, socket.SOCK_STREAM] as s:
s.bind[[HOST, PORT]]
s.listen[]
conn, addr = s.accept[]
with conn:
print[f"Connected by {addr}"]
while True:
data = conn.recv[1024]
if not data:
break
conn.sendall[data]
640 cuối cùng và thực tế là chúng đang xử lý một phản hồi chứ không phải tạo một phản hồi. # echo-server.py
# ...
with socket.socket[socket.AF_INET, socket.SOCK_STREAM] as s:
s.bind[[HOST, PORT]]
s.listen[]
conn, addr = s.accept[]
with conn:
print[f"Connected by {addr}"]
while True:
data = conn.recv[1024]
if not data:
break
conn.sendall[data]
634, # echo-server.py
# ...
with socket.socket[socket.AF_INET, socket.SOCK_STREAM] as s:
s.bind[[HOST, PORT]]
s.listen[]
conn, addr = s.accept[]
with conn:
print[f"Connected by {addr}"]
while True:
data = conn.recv[1024]
if not data:
break
conn.sendall[data]
632 và # echo-server.py
# ...
with socket.socket[socket.AF_INET, socket.SOCK_STREAM] as s:
s.bind[[HOST, PORT]]
s.listen[]
conn, addr = s.accept[]
with conn:
print[f"Connected by {addr}"]
while True:
data = conn.recv[1024]
if not data:
break
conn.sendall[data]
633Cuối cùng, nhưng không kém phần quan trọng, là cuộc gọi cuối cùng cho
# echo-server.py
# ...
with socket.socket[socket.AF_INET, socket.SOCK_STREAM] as s:
s.bind[[HOST, PORT]]
s.listen[]
conn, addr = s.accept[]
with conn:
print[f"Connected by {addr}"]
while True:
data = conn.recv[1024]
if not data:
break
conn.sendall[data]
634# echo-server.py
# ...
with socket.socket[socket.AF_INET, socket.SOCK_STREAM] as s:
s.bind[[HOST, PORT]]
s.listen[]
conn, addr = s.accept[]
with conn:
print[f"Connected by {addr}"]
while True:
data = conn.recv[1024]
if not data:
break
conn.sendall[data]
70Gói lớp tin nhắn
Để kết thúc quá trình tìm hiểu của bạn về lớp
# echo-server.py
# ...
with socket.socket[socket.AF_INET, socket.SOCK_STREAM] as s:
s.bind[[HOST, PORT]]
s.listen[]
conn, addr = s.accept[]
with conn:
print[f"Connected by {addr}"]
while True:
data = conn.recv[1024]
if not data:
break
conn.sendall[data]
993, cần đề cập đến một số điều quan trọng cần lưu ý cùng với một số phương pháp hỗ trợBất kỳ ngoại lệ nào do lớp đưa ra đều bị tập lệnh chính bắt trong mệnh đề
# echo-server.py
# ...
with socket.socket[socket.AF_INET, socket.SOCK_STREAM] as s:
s.bind[[HOST, PORT]]
s.listen[]
conn, addr = s.accept[]
with conn:
print[f"Connected by {addr}"]
while True:
data = conn.recv[1024]
if not data:
break
conn.sendall[data]
636 bên trong vòng lặp sự kiện# echo-server.py
# ...
with socket.socket[socket.AF_INET, socket.SOCK_STREAM] as s:
s.bind[[HOST, PORT]]
s.listen[]
conn, addr = s.accept[]
with conn:
print[f"Connected by {addr}"]
while True:
data = conn.recv[1024]
if not data:
break
conn.sendall[data]
71Lưu ý dòng.
# echo-server.py
# ...
with socket.socket[socket.AF_INET, socket.SOCK_STREAM] as s:
s.bind[[HOST, PORT]]
s.listen[]
conn, addr = s.accept[]
with conn:
print[f"Connected by {addr}"]
while True:
data = conn.recv[1024]
if not data:
break
conn.sendall[data]
637Đây là một dòng thực sự quan trọng, vì nhiều lý do. Nó không chỉ đảm bảo rằng ổ cắm đã được đóng mà
# echo-server.py
# ...
with socket.socket[socket.AF_INET, socket.SOCK_STREAM] as s:
s.bind[[HOST, PORT]]
s.listen[]
conn, addr = s.accept[]
with conn:
print[f"Connected by {addr}"]
while True:
data = conn.recv[1024]
if not data:
break
conn.sendall[data]
637 còn loại bỏ ổ cắm khỏi sự giám sát của # echo-server.py
# ...
with socket.socket[socket.AF_INET, socket.SOCK_STREAM] as s:
s.bind[[HOST, PORT]]
s.listen[]
conn, addr = s.accept[]
with conn:
print[f"Connected by {addr}"]
while True:
data = conn.recv[1024]
if not data:
break
conn.sendall[data]
488. Điều này đơn giản hóa đáng kể mã trong lớp và giảm độ phức tạp. Nếu có một ngoại lệ hoặc bạn tự nêu ra một cách rõ ràng, bạn biết rằng # echo-server.py
# ...
with socket.socket[socket.AF_INET, socket.SOCK_STREAM] as s:
s.bind[[HOST, PORT]]
s.listen[]
conn, addr = s.accept[]
with conn:
print[f"Connected by {addr}"]
while True:
data = conn.recv[1024]
if not data:
break
conn.sendall[data]
6 sẽ lo việc dọn dẹpCác phương pháp
# echo-server.py
# ...
with socket.socket[socket.AF_INET, socket.SOCK_STREAM] as s:
s.bind[[HOST, PORT]]
s.listen[]
conn, addr = s.accept[]
with conn:
print[f"Connected by {addr}"]
while True:
data = conn.recv[1024]
if not data:
break
conn.sendall[data]
641 và # echo-server.py
# ...
with socket.socket[socket.AF_INET, socket.SOCK_STREAM] as s:
s.bind[[HOST, PORT]]
s.listen[]
conn, addr = s.accept[]
with conn:
print[f"Connected by {addr}"]
while True:
data = conn.recv[1024]
if not data:
break
conn.sendall[data]
642 cũng chứa một số điều thú vị# echo-server.py
# ...
with socket.socket[socket.AF_INET, socket.SOCK_STREAM] as s:
s.bind[[HOST, PORT]]
s.listen[]
conn, addr = s.accept[]
with conn:
print[f"Connected by {addr}"]
while True:
data = conn.recv[1024]
if not data:
break
conn.sendall[data]
72Lưu ý dòng
# echo-server.py
# ...
with socket.socket[socket.AF_INET, socket.SOCK_STREAM] as s:
s.bind[[HOST, PORT]]
s.listen[]
conn, addr = s.accept[]
with conn:
print[f"Connected by {addr}"]
while True:
data = conn.recv[1024]
if not data:
break
conn.sendall[data]
643Phương thức
# echo-server.py
# ...
with socket.socket[socket.AF_INET, socket.SOCK_STREAM] as s:
s.bind[[HOST, PORT]]
s.listen[]
conn, addr = s.accept[]
with conn:
print[f"Connected by {addr}"]
while True:
data = conn.recv[1024]
if not data:
break
conn.sendall[data]
653 cũng có một. Những dòng này rất quan trọng vì chúng phát hiện lỗi tạm thời và bỏ qua nó bằng cách sử dụng # echo-server.py
# ...
with socket.socket[socket.AF_INET, socket.SOCK_STREAM] as s:
s.bind[[HOST, PORT]]
s.listen[]
conn, addr = s.accept[]
with conn:
print[f"Connected by {addr}"]
while True:
data = conn.recv[1024]
if not data:
break
conn.sendall[data]
645. Lỗi tạm thời là khi ổ cắm bị chặn, chẳng hạn như nếu nó đang chờ trên mạng hoặc đầu kia của kết nối, còn được gọi là ngang hàng của nóBằng cách bắt và bỏ qua ngoại lệ với
# echo-server.py
# ...
with socket.socket[socket.AF_INET, socket.SOCK_STREAM] as s:
s.bind[[HOST, PORT]]
s.listen[]
conn, addr = s.accept[]
with conn:
print[f"Connected by {addr}"]
while True:
data = conn.recv[1024]
if not data:
break
conn.sendall[data]
645, # echo-server.py
# ...
with socket.socket[socket.AF_INET, socket.SOCK_STREAM] as s:
s.bind[[HOST, PORT]]
s.listen[]
conn, addr = s.accept[]
with conn:
print[f"Connected by {addr}"]
while True:
data = conn.recv[1024]
if not data:
break
conn.sendall[data]
488 cuối cùng sẽ kích hoạt một cuộc gọi mới và bạn sẽ có một cơ hội khác để đọc hoặc ghi dữ liệuRemove adsChạy ứng dụng Client và Server
Sau tất cả những công việc khó khăn này, đã đến lúc vui chơi và thực hiện một số tìm kiếm
Trong các ví dụ này, bạn sẽ chạy máy chủ để nó lắng nghe trên tất cả các giao diện bằng cách chuyển một chuỗi trống cho đối số
# echo-server.py
# ...
with socket.socket[socket.AF_INET, socket.SOCK_STREAM] as s:
s.bind[[HOST, PORT]]
s.listen[]
conn, addr = s.accept[]
with conn:
print[f"Connected by {addr}"]
while True:
data = conn.recv[1024]
if not data:
break
conn.sendall[data]
38. Điều này sẽ cho phép bạn chạy ứng dụng khách và kết nối từ một máy ảo trên một mạng khác. Nó mô phỏng một cỗ máy PowerPC lớnĐầu tiên, khởi động máy chủ
# echo-server.py
# ...
with socket.socket[socket.AF_INET, socket.SOCK_STREAM] as s:
s.bind[[HOST, PORT]]
s.listen[]
conn, addr = s.accept[]
with conn:
print[f"Connected by {addr}"]
while True:
data = conn.recv[1024]
if not data:
break
conn.sendall[data]
73Bây giờ hãy chạy ứng dụng khách và nhập tìm kiếm. Xem nếu bạn có thể tìm thấy anh ta
# echo-server.py
# ...
with socket.socket[socket.AF_INET, socket.SOCK_STREAM] as s:
s.bind[[HOST, PORT]]
s.listen[]
conn, addr = s.accept[]
with conn:
print[f"Connected by {addr}"]
while True:
data = conn.recv[1024]
if not data:
break
conn.sendall[data]
74Bạn có thể nhận thấy rằng thiết bị đầu cuối đang chạy trình bao sử dụng mã hóa văn bản Unicode [UTF-8], do đó, đầu ra ở trên được in đẹp mắt với các biểu tượng cảm xúc
Bây giờ hãy xem bạn có thể tìm thấy những chú chó con không
# echo-server.py
# ...
with socket.socket[socket.AF_INET, socket.SOCK_STREAM] as s:
s.bind[[HOST, PORT]]
s.listen[]
conn, addr = s.accept[]
with conn:
print[f"Connected by {addr}"]
while True:
data = conn.recv[1024]
if not data:
break
conn.sendall[data]
75Lưu ý chuỗi byte được gửi qua mạng cho yêu cầu trong dòng
# echo-server.py
# ...
with socket.socket[socket.AF_INET, socket.SOCK_STREAM] as s:
s.bind[[HOST, PORT]]
s.listen[]
conn, addr = s.accept[]
with conn:
print[f"Connected by {addr}"]
while True:
data = conn.recv[1024]
if not data:
break
conn.sendall[data]
649. Sẽ dễ dàng hơn nếu bạn tìm kiếm các byte được in ở dạng hex đại diện cho biểu tượng cảm xúc cún con. # echo-server.py
# ...
with socket.socket[socket.AF_INET, socket.SOCK_STREAM] as s:
s.bind[[HOST, PORT]]
s.listen[]
conn, addr = s.accept[]
with conn:
print[f"Connected by {addr}"]
while True:
data = conn.recv[1024]
if not data:
break
conn.sendall[data]
650. Nếu thiết bị đầu cuối của bạn đang sử dụng Unicode với mã hóa UTF-8, bạn sẽ có thể nhập biểu tượng cảm xúc cho tìm kiếmĐiều này chứng tỏ rằng bạn đang gửi các byte thô qua mạng và chúng cần được người nhận giải mã để được diễn giải chính xác. Đây là lý do tại sao bạn gặp khó khăn khi tạo tiêu đề chứa loại nội dung và mã hóa
Đây là đầu ra máy chủ từ cả hai kết nối máy khách ở trên
# echo-server.py
# ...
with socket.socket[socket.AF_INET, socket.SOCK_STREAM] as s:
s.bind[[HOST, PORT]]
s.listen[]
conn, addr = s.accept[]
with conn:
print[f"Connected by {addr}"]
while True:
data = conn.recv[1024]
if not data:
break
conn.sendall[data]
76Look at the
# echo-server.py
# ...
with socket.socket[socket.AF_INET, socket.SOCK_STREAM] as s:
s.bind[[HOST, PORT]]
s.listen[]
conn, addr = s.accept[]
with conn:
print[f"Connected by {addr}"]
while True:
data = conn.recv[1024]
if not data:
break
conn.sendall[data]
649 line to see the bytes that were written to the client’s socket. Đây là thông báo phản hồi của máy chủBạn cũng có thể kiểm tra việc gửi các yêu cầu nhị phân đến máy chủ nếu đối số
# echo-server.py
# ...
with socket.socket[socket.AF_INET, socket.SOCK_STREAM] as s:
s.bind[[HOST, PORT]]
s.listen[]
conn, addr = s.accept[]
with conn:
print[f"Connected by {addr}"]
while True:
data = conn.recv[1024]
if not data:
break
conn.sendall[data]
652 là bất kỳ thứ gì khác ngoài # echo-server.py
# ...
with socket.socket[socket.AF_INET, socket.SOCK_STREAM] as s:
s.bind[[HOST, PORT]]
s.listen[]
conn, addr = s.accept[]
with conn:
print[f"Connected by {addr}"]
while True:
data = conn.recv[1024]
if not data:
break
conn.sendall[data]
653# echo-server.py
# ...
with socket.socket[socket.AF_INET, socket.SOCK_STREAM] as s:
s.bind[[HOST, PORT]]
s.listen[]
conn, addr = s.accept[]
with conn:
print[f"Connected by {addr}"]
while True:
data = conn.recv[1024]
if not data:
break
conn.sendall[data]
77Vì
# echo-server.py
# ...
with socket.socket[socket.AF_INET, socket.SOCK_STREAM] as s:
s.bind[[HOST, PORT]]
s.listen[]
conn, addr = s.accept[]
with conn:
print[f"Connected by {addr}"]
while True:
data = conn.recv[1024]
if not data:
break
conn.sendall[data]
981 của yêu cầu không phải là # echo-server.py
# ...
with socket.socket[socket.AF_INET, socket.SOCK_STREAM] as s:
s.bind[[HOST, PORT]]
s.listen[]
conn, addr = s.accept[]
with conn:
print[f"Connected by {addr}"]
while True:
data = conn.recv[1024]
if not data:
break
conn.sendall[data]
982 nên máy chủ coi nó là một loại nhị phân tùy chỉnh và không thực hiện giải mã JSON. Nó chỉ cần in # echo-server.py
# ...
with socket.socket[socket.AF_INET, socket.SOCK_STREAM] as s:
s.bind[[HOST, PORT]]
s.listen[]
conn, addr = s.accept[]
with conn:
print[f"Connected by {addr}"]
while True:
data = conn.recv[1024]
if not data:
break
conn.sendall[data]
981 và trả về 10 byte đầu tiên cho máy khách# echo-server.py
# ...
with socket.socket[socket.AF_INET, socket.SOCK_STREAM] as s:
s.bind[[HOST, PORT]]
s.listen[]
conn, addr = s.accept[]
with conn:
print[f"Connected by {addr}"]
while True:
data = conn.recv[1024]
if not data:
break
conn.sendall[data]
78Xử lý sự cố
Chắc chắn, một cái gì đó sẽ không hoạt động và bạn sẽ tự hỏi phải làm gì. Đừng lo lắng, nó xảy ra với tất cả mọi người. Hy vọng rằng với sự trợ giúp của hướng dẫn này, trình gỡ lỗi và công cụ tìm kiếm yêu thích của bạn, bạn sẽ có thể bắt đầu lại với phần mã nguồn
Nếu không, điểm dừng đầu tiên của bạn phải là tài liệu về mô-đun ổ cắm của Python. Đảm bảo rằng bạn đã đọc tất cả tài liệu cho từng chức năng hoặc phương thức mà bạn đang gọi. Ngoài ra, hãy đọc qua phần Tham khảo bên dưới để biết ý tưởng. Cụ thể, hãy kiểm tra phần Lỗi
Đôi khi, nó không phải là tất cả về mã nguồn. Mã nguồn có thể đúng và đó chỉ là máy chủ, máy khách hoặc máy chủ khác. Hoặc nó có thể là mạng. Có thể một bộ định tuyến, tường lửa hoặc một số thiết bị mạng khác đang đóng vai trò trung gian
Đối với các loại sự cố này, cần có các công cụ bổ sung. Dưới đây là một số công cụ và tiện ích có thể trợ giúp hoặc ít nhất là cung cấp một số manh mối
Remove adsping
# echo-server.py
# ...
with socket.socket[socket.AF_INET, socket.SOCK_STREAM] as s:
s.bind[[HOST, PORT]]
s.listen[]
conn, addr = s.accept[]
with conn:
print[f"Connected by {addr}"]
while True:
data = conn.recv[1024]
if not data:
break
conn.sendall[data]
657 sẽ kiểm tra xem máy chủ có còn hoạt động và được kết nối với mạng hay không bằng cách gửi yêu cầu tiếng vang ICMP. Nó giao tiếp trực tiếp với ngăn xếp giao thức TCP/IP của hệ điều hành, vì vậy nó hoạt động độc lập với bất kỳ ứng dụng nào đang chạy trên máy chủDưới đây là ví dụ chạy ping trên macOS
# echo-server.py
# ...
with socket.socket[socket.AF_INET, socket.SOCK_STREAM] as s:
s.bind[[HOST, PORT]]
s.listen[]
conn, addr = s.accept[]
with conn:
print[f"Connected by {addr}"]
while True:
data = conn.recv[1024]
if not data:
break
conn.sendall[data]
79Lưu ý số liệu thống kê ở cuối đầu ra. Điều này có thể hữu ích khi bạn đang cố gắng khám phá các sự cố kết nối không liên tục. Ví dụ, có mất gói nào không?
Nếu có tường lửa giữa bạn và máy chủ khác, yêu cầu tiếng vang của ping có thể không được phép. Một số quản trị viên tường lửa thực hiện các chính sách thực thi điều này. Ý tưởng là họ không muốn máy chủ của mình có thể được khám phá. Nếu trường hợp này xảy ra và bạn đã thêm các quy tắc tường lửa để cho phép các máy chủ giao tiếp, thì hãy đảm bảo rằng các quy tắc đó cũng cho phép ICMP chuyển giữa chúng
ICMP là giao thức được sử dụng bởi
# echo-server.py
# ...
with socket.socket[socket.AF_INET, socket.SOCK_STREAM] as s:
s.bind[[HOST, PORT]]
s.listen[]
conn, addr = s.accept[]
with conn:
print[f"Connected by {addr}"]
while True:
data = conn.recv[1024]
if not data:
break
conn.sendall[data]
657, nhưng nó cũng là giao thức mà TCP và các giao thức cấp thấp khác sử dụng để truyền thông báo lỗi. Nếu bạn đang gặp hành vi lạ hoặc kết nối chậm, đây có thể là lý doThông báo ICMP được xác định theo loại và mã. Để cung cấp cho bạn ý tưởng về thông tin quan trọng mà họ mang theo, đây là một số
Loại ICMP Mã ICMP Mô tả80Yêu cầu tiếng vang00Trả lời tiếng vang30Không thể truy cập mạng đích31Không thể truy cập máy chủ đích32Không thể truy cập giao thức đích33Không thể truy cập cổng đích34Yêu cầu phân đoạn và đặt cờ DF110TTL đã hết hạn trong quá trình vận chuyển
Xem bài viết Khám phá đường dẫn MTU để biết thông tin về phân mảnh và thông báo ICMP. Đây là một ví dụ về điều gì đó có thể gây ra hành vi lạ
netstat
Trong phần Xem trạng thái ổ cắm, bạn đã học cách sử dụng
# echo-server.py
# ...
with socket.socket[socket.AF_INET, socket.SOCK_STREAM] as s:
s.bind[[HOST, PORT]]
s.listen[]
conn, addr = s.accept[]
with conn:
print[f"Connected by {addr}"]
while True:
data = conn.recv[1024]
if not data:
break
conn.sendall[data]
437 để hiển thị thông tin về ổ cắm và trạng thái hiện tại của chúng. Tiện ích này có sẵn trên macOS, Linux và WindowsPhần đó không đề cập đến các cột
# echo-server.py
# ...
with socket.socket[socket.AF_INET, socket.SOCK_STREAM] as s:
s.bind[[HOST, PORT]]
s.listen[]
conn, addr = s.accept[]
with conn:
print[f"Connected by {addr}"]
while True:
data = conn.recv[1024]
if not data:
break
conn.sendall[data]
660 và # echo-server.py
# ...
with socket.socket[socket.AF_INET, socket.SOCK_STREAM] as s:
s.bind[[HOST, PORT]]
s.listen[]
conn, addr = s.accept[]
with conn:
print[f"Connected by {addr}"]
while True:
data = conn.recv[1024]
if not data:
break
conn.sendall[data]
661 trong đầu ra ví dụ. Các cột này sẽ hiển thị cho bạn số lượng byte được giữ trong bộ đệm mạng được xếp hàng đợi để truyền hoặc nhận, nhưng vì lý do nào đó chưa được đọc hoặc ghi bởi ứng dụng từ xa hoặc cục bộNói cách khác, các byte đang đợi trong bộ đệm mạng trong hàng đợi của hệ điều hành. Một lý do có thể là ứng dụng bị ràng buộc CPU hoặc không thể gọi
# echo-server.py
# ...
with socket.socket[socket.AF_INET, socket.SOCK_STREAM] as s:
s.bind[[HOST, PORT]]
s.listen[]
conn, addr = s.accept[]
with conn:
print[f"Connected by {addr}"]
while True:
data = conn.recv[1024]
if not data:
break
conn.sendall[data]
637 hoặc # echo-server.py
# ...
with socket.socket[socket.AF_INET, socket.SOCK_STREAM] as s:
s.bind[[HOST, PORT]]
s.listen[]
conn, addr = s.accept[]
with conn:
print[f"Connected by {addr}"]
while True:
data = conn.recv[1024]
if not data:
break
conn.sendall[data]
960 và xử lý các byte. Hoặc có thể có sự cố mạng ảnh hưởng đến hoạt động liên lạc, chẳng hạn như tắc nghẽn hoặc lỗi phần cứng hoặc cáp mạngĐể chứng minh điều này và xem bạn có thể gửi bao nhiêu dữ liệu trước khi gặp lỗi, bạn có thể dùng thử ứng dụng khách thử nghiệm kết nối với máy chủ thử nghiệm và gọi liên tục
# echo-server.py
# ...
with socket.socket[socket.AF_INET, socket.SOCK_STREAM] as s:
s.bind[[HOST, PORT]]
s.listen[]
conn, addr = s.accept[]
with conn:
print[f"Connected by {addr}"]
while True:
data = conn.recv[1024]
if not data:
break
conn.sendall[data]
960. Máy chủ thử nghiệm không bao giờ gọi # echo-server.py
# ...
with socket.socket[socket.AF_INET, socket.SOCK_STREAM] as s:
s.bind[[HOST, PORT]]
s.listen[]
conn, addr = s.accept[]
with conn:
print[f"Connected by {addr}"]
while True:
data = conn.recv[1024]
if not data:
break
conn.sendall[data]
637. Nó chỉ chấp nhận kết nối. This causes the network buffers on the server to fill, which eventually raises an error on the clientĐầu tiên, khởi động máy chủ
$ python echo-server.py
0Sau đó chạy client xem lỗi là gì
$ python echo-server.py
1Đây là kết quả đầu ra của
# echo-server.py
# ...
with socket.socket[socket.AF_INET, socket.SOCK_STREAM] as s:
s.bind[[HOST, PORT]]
s.listen[]
conn, addr = s.accept[]
with conn:
print[f"Connected by {addr}"]
while True:
data = conn.recv[1024]
if not data:
break
conn.sendall[data]
437 trong khi máy khách và máy chủ vẫn đang chạy, với máy khách in ra thông báo lỗi ở trên nhiều lần$ python echo-server.py
2Mục đầu tiên là máy chủ [______2438 có cổng 65432]
$ python echo-server.py
3Lưu ý
# echo-server.py
# ...
with socket.socket[socket.AF_INET, socket.SOCK_STREAM] as s:
s.bind[[HOST, PORT]]
s.listen[]
conn, addr = s.accept[]
with conn:
print[f"Connected by {addr}"]
while True:
data = conn.recv[1024]
if not data:
break
conn.sendall[data]
660. # echo-server.py
# ...
with socket.socket[socket.AF_INET, socket.SOCK_STREAM] as s:
s.bind[[HOST, PORT]]
s.listen[]
conn, addr = s.accept[]
with conn:
print[f"Connected by {addr}"]
while True:
data = conn.recv[1024]
if not data:
break
conn.sendall[data]
669Mục thứ hai là máy khách [____5670 có cổng 65432]
$ python echo-server.py
4Lưu ý
# echo-server.py
# ...
with socket.socket[socket.AF_INET, socket.SOCK_STREAM] as s:
s.bind[[HOST, PORT]]
s.listen[]
conn, addr = s.accept[]
with conn:
print[f"Connected by {addr}"]
while True:
data = conn.recv[1024]
if not data:
break
conn.sendall[data]
661. # echo-server.py
# ...
with socket.socket[socket.AF_INET, socket.SOCK_STREAM] as s:
s.bind[[HOST, PORT]]
s.listen[]
conn, addr = s.accept[]
with conn:
print[f"Connected by {addr}"]
while True:
data = conn.recv[1024]
if not data:
break
conn.sendall[data]
672Máy khách chắc chắn đang cố ghi byte, nhưng máy chủ không đọc chúng. Điều này khiến hàng đợi bộ đệm mạng của máy chủ được lấp đầy ở bên nhận và hàng đợi bộ đệm mạng của máy khách được lấp đầy ở bên gửi
các cửa sổ
Nếu bạn làm việc với Windows, có một bộ tiện ích mà bạn chắc chắn nên xem qua nếu chưa có. hệ thống Windows
Một trong số đó là
# echo-server.py
# ...
with socket.socket[socket.AF_INET, socket.SOCK_STREAM] as s:
s.bind[[HOST, PORT]]
s.listen[]
conn, addr = s.accept[]
with conn:
print[f"Connected by {addr}"]
while True:
data = conn.recv[1024]
if not data:
break
conn.sendall[data]
673. TCPView là một # echo-server.py
# ...
with socket.socket[socket.AF_INET, socket.SOCK_STREAM] as s:
s.bind[[HOST, PORT]]
s.listen[]
conn, addr = s.accept[]
with conn:
print[f"Connected by {addr}"]
while True:
data = conn.recv[1024]
if not data:
break
conn.sendall[data]
437 đồ họa cho Windows. Ngoài địa chỉ, số cổng và trạng thái ổ cắm, nó sẽ hiển thị cho bạn tổng số đang chạy cho số lượng gói và byte được gửi và nhận. Giống như với tiện ích Unix # echo-server.py
# ...
with socket.socket[socket.AF_INET, socket.SOCK_STREAM] as s:
s.bind[[HOST, PORT]]
s.listen[]
conn, addr = s.accept[]
with conn:
print[f"Connected by {addr}"]
while True:
data = conn.recv[1024]
if not data:
break
conn.sendall[data]
455, bạn cũng nhận được tên quy trình và ID. Kiểm tra các menu để biết các tùy chọn hiển thị kháccá mập
Đôi khi bạn cần xem những gì đang xảy ra trên dây. Quên những gì nhật ký ứng dụng nói hoặc giá trị được trả về từ một cuộc gọi thư viện. Bạn muốn xem những gì thực sự được gửi hoặc nhận trên mạng. Cũng giống như với trình gỡ lỗi, khi bạn cần xem nó, không có gì thay thế
Wireshark là một ứng dụng phân tích giao thức mạng và nắm bắt lưu lượng chạy trên macOS, Linux và Windows, trong số những ứng dụng khác. There’s a GUI version named
# echo-server.py
# ...
with socket.socket[socket.AF_INET, socket.SOCK_STREAM] as s:
s.bind[[HOST, PORT]]
s.listen[]
conn, addr = s.accept[]
with conn:
print[f"Connected by {addr}"]
while True:
data = conn.recv[1024]
if not data:
break
conn.sendall[data]
676 and also a terminal, text-based version named # echo-server.py
# ...
with socket.socket[socket.AF_INET, socket.SOCK_STREAM] as s:
s.bind[[HOST, PORT]]
s.listen[]
conn, addr = s.accept[]
with conn:
print[f"Connected by {addr}"]
while True:
data = conn.recv[1024]
if not data:
break
conn.sendall[data]
677Running a traffic capture is a great way to watch how an application behaves on the network and gather evidence about what it sends and receives, and how often and how much. Bạn cũng có thể biết khi nào máy khách hoặc máy chủ đóng hoặc hủy kết nối hoặc ngừng phản hồi. This information can be extremely helpful when you’re troubleshooting
There are many good tutorials and other resources on the web that will walk you through the basics of using Wireshark and TShark
Here’s an example of a traffic capture using Wireshark on the loopback interface
Here’s the same example shown above using
# echo-server.py
# ...
with socket.socket[socket.AF_INET, socket.SOCK_STREAM] as s:
s.bind[[HOST, PORT]]
s.listen[]
conn, addr = s.accept[]
with conn:
print[f"Connected by {addr}"]
while True:
data = conn.recv[1024]
if not data:
break
conn.sendall[data]
677$ python echo-server.py
5Next up, you’ll get more references to support your socket programming journey
Reference
You can use this section as a general reference with additional information and links to external resources
Python Documentation
- Python’s socket module
- Python’s Socket Programming HOWTO
Errors
The following is from Python’s
# echo-server.py
# ...
with socket.socket[socket.AF_INET, socket.SOCK_STREAM] as s:
s.bind[[HOST, PORT]]
s.listen[]
conn, addr = s.accept[]
with conn:
print[f"Connected by {addr}"]
while True:
data = conn.recv[1024]
if not data:
break
conn.sendall[data]
679 module documentation“Tất cả các lỗi đều có ngoại lệ. Các ngoại lệ thông thường đối với các loại đối số không hợp lệ và các điều kiện hết bộ nhớ có thể được nêu ra; . 3, các lỗi liên quan đến ngữ nghĩa ổ cắm hoặc địa chỉ nâng cao
970 hoặc một trong các lớp con của nó. " [Nguồn]# echo-server.py # ... with socket.socket[socket.AF_INET, socket.SOCK_STREAM] as s: s.bind[[HOST, PORT]] s.listen[] conn, addr = s.accept[] with conn: print[f"Connected by {addr}"] while True: data = conn.recv[1024] if not data: break conn.sendall[data]
Here are some common errors you’ll probably encounter when working with sockets
Exception
# echo-server.py
# ...
with socket.socket[socket.AF_INET, socket.SOCK_STREAM] as s:
s.bind[[HOST, PORT]]
s.listen[]
conn, addr = s.accept[]
with conn:
print[f"Connected by {addr}"]
while True:
data = conn.recv[1024]
if not data:
break
conn.sendall[data]
681 ConstantDescriptionBlockingIOErrorEWOULDBLOCKResource temporarily unavailable. For example, in non-blocking mode, when calling # echo-server.py
# ...
with socket.socket[socket.AF_INET, socket.SOCK_STREAM] as s:
s.bind[[HOST, PORT]]
s.listen[]
conn, addr = s.accept[]
with conn:
print[f"Connected by {addr}"]
while True:
data = conn.recv[1024]
if not data:
break
conn.sendall[data]
4 and the peer is busy and not reading, the send queue [network buffer] is full. Or there are issues with the network. Hopefully this is a temporary condition. OSErrorEADDRINUSEAddress already in use. Make sure that there’s not another process running that’s using the same port number and that your server is setting the socket option # echo-server.py
# ...
with socket.socket[socket.AF_INET, socket.SOCK_STREAM] as s:
s.bind[[HOST, PORT]]
s.listen[]
conn, addr = s.accept[]
with conn:
print[f"Connected by {addr}"]
while True:
data = conn.recv[1024]
if not data:
break
conn.sendall[data]
683. # echo-server.py
# ...
with socket.socket[socket.AF_INET, socket.SOCK_STREAM] as s:
s.bind[[HOST, PORT]]
s.listen[]
conn, addr = s.accept[]
with conn:
print[f"Connected by {addr}"]
while True:
data = conn.recv[1024]
if not data:
break
conn.sendall[data]
684. ConnectionResetErrorECONNRESETConnection reset by peer. The remote process crashed or did not close its socket properly, also known as an unclean shutdown. Or there’s a firewall or other device in the network path that’s missing rules or misbehaving. TimeoutErrorETIMEDOUTOperation timed out. No response from peer. ConnectionRefusedErrorECONNREFUSEDConnection refused. No application listening on specified portSocket Address Families
# echo-server.py
# ...
with socket.socket[socket.AF_INET, socket.SOCK_STREAM] as s:
s.bind[[HOST, PORT]]
s.listen[]
conn, addr = s.accept[]
with conn:
print[f"Connected by {addr}"]
while True:
data = conn.recv[1024]
if not data:
break
conn.sendall[data]
36 and # echo-server.py
# ...
with socket.socket[socket.AF_INET, socket.SOCK_STREAM] as s:
s.bind[[HOST, PORT]]
s.listen[]
conn, addr = s.accept[]
with conn:
print[f"Connected by {addr}"]
while True:
data = conn.recv[1024]
if not data:
break
conn.sendall[data]
686 represent the address and protocol families used for the first argument to # echo-server.py
# ...
with socket.socket[socket.AF_INET, socket.SOCK_STREAM] as s:
s.bind[[HOST, PORT]]
s.listen[]
conn, addr = s.accept[]
with conn:
print[f"Connected by {addr}"]
while True:
data = conn.recv[1024]
if not data:
break
conn.sendall[data]
7. APIs that use an address expect it to be in a certain format, depending on whether the socket was created with # echo-server.py
# ...
with socket.socket[socket.AF_INET, socket.SOCK_STREAM] as s:
s.bind[[HOST, PORT]]
s.listen[]
conn, addr = s.accept[]
with conn:
print[f"Connected by {addr}"]
while True:
data = conn.recv[1024]
if not data:
break
conn.sendall[data]
36 or # echo-server.py
# ...
with socket.socket[socket.AF_INET, socket.SOCK_STREAM] as s:
s.bind[[HOST, PORT]]
s.listen[]
conn, addr = s.accept[]
with conn:
print[f"Connected by {addr}"]
while True:
data = conn.recv[1024]
if not data:
break
conn.sendall[data]
686Address FamilyProtocolAddress TupleDescription
# echo-server.py
# ...
with socket.socket[socket.AF_INET, socket.SOCK_STREAM] as s:
s.bind[[HOST, PORT]]
s.listen[]
conn, addr = s.accept[]
with conn:
print[f"Connected by {addr}"]
while True:
data = conn.recv[1024]
if not data:
break
conn.sendall[data]
36IPv4# echo-server.py
# ...
with socket.socket[socket.AF_INET, socket.SOCK_STREAM] as s:
s.bind[[HOST, PORT]]
s.listen[]
conn, addr = s.accept[]
with conn:
print[f"Connected by {addr}"]
while True:
data = conn.recv[1024]
if not data:
break
conn.sendall[data]
37# echo-server.py
# ...
with socket.socket[socket.AF_INET, socket.SOCK_STREAM] as s:
s.bind[[HOST, PORT]]
s.listen[]
conn, addr = s.accept[]
with conn:
print[f"Connected by {addr}"]
while True:
data = conn.recv[1024]
if not data:
break
conn.sendall[data]
38 is a string with a hostname like # echo-server.py
# ...
with socket.socket[socket.AF_INET, socket.SOCK_STREAM] as s:
s.bind[[HOST, PORT]]
s.listen[]
conn, addr = s.accept[]
with conn:
print[f"Connected by {addr}"]
while True:
data = conn.recv[1024]
if not data:
break
conn.sendall[data]
693 or an IPv4 address like # echo-server.py
# ...
with socket.socket[socket.AF_INET, socket.SOCK_STREAM] as s:
s.bind[[HOST, PORT]]
s.listen[]
conn, addr = s.accept[]
with conn:
print[f"Connected by {addr}"]
while True:
data = conn.recv[1024]
if not data:
break
conn.sendall[data]
694. # echo-server.py
# ...
with socket.socket[socket.AF_INET, socket.SOCK_STREAM] as s:
s.bind[[HOST, PORT]]
s.listen[]
conn, addr = s.accept[]
with conn:
print[f"Connected by {addr}"]
while True:
data = conn.recv[1024]
if not data:
break
conn.sendall[data]
401 is an integer. # echo-server.py
# ...
with socket.socket[socket.AF_INET, socket.SOCK_STREAM] as s:
s.bind[[HOST, PORT]]
s.listen[]
conn, addr = s.accept[]
with conn:
print[f"Connected by {addr}"]
while True:
data = conn.recv[1024]
if not data:
break
conn.sendall[data]
686IPv6# echo-server.py
# ...
with socket.socket[socket.AF_INET, socket.SOCK_STREAM] as s:
s.bind[[HOST, PORT]]
s.listen[]
conn, addr = s.accept[]
with conn:
print[f"Connected by {addr}"]
while True:
data = conn.recv[1024]
if not data:
break
conn.sendall[data]
418# echo-server.py
# ...
with socket.socket[socket.AF_INET, socket.SOCK_STREAM] as s:
s.bind[[HOST, PORT]]
s.listen[]
conn, addr = s.accept[]
with conn:
print[f"Connected by {addr}"]
while True:
data = conn.recv[1024]
if not data:
break
conn.sendall[data]
38 is a string with a hostname like # echo-server.py
# ...
with socket.socket[socket.AF_INET, socket.SOCK_STREAM] as s:
s.bind[[HOST, PORT]]
s.listen[]
conn, addr = s.accept[]
with conn:
print[f"Connected by {addr}"]
while True:
data = conn.recv[1024]
if not data:
break
conn.sendall[data]
693 or an IPv6 address like # echo-server.py
# ...
with socket.socket[socket.AF_INET, socket.SOCK_STREAM] as s:
s.bind[[HOST, PORT]]
s.listen[]
conn, addr = s.accept[]
with conn:
print[f"Connected by {addr}"]
while True:
data = conn.recv[1024]
if not data:
break
conn.sendall[data]
700. # echo-server.py
# ...
with socket.socket[socket.AF_INET, socket.SOCK_STREAM] as s:
s.bind[[HOST, PORT]]
s.listen[]
conn, addr = s.accept[]
with conn:
print[f"Connected by {addr}"]
while True:
data = conn.recv[1024]
if not data:
break
conn.sendall[data]
401 is an integer. # echo-server.py
# ...
with socket.socket[socket.AF_INET, socket.SOCK_STREAM] as s:
s.bind[[HOST, PORT]]
s.listen[]
conn, addr = s.accept[]
with conn:
print[f"Connected by {addr}"]
while True:
data = conn.recv[1024]
if not data:
break
conn.sendall[data]
702 and # echo-server.py
# ...
with socket.socket[socket.AF_INET, socket.SOCK_STREAM] as s:
s.bind[[HOST, PORT]]
s.listen[]
conn, addr = s.accept[]
with conn:
print[f"Connected by {addr}"]
while True:
data = conn.recv[1024]
if not data:
break
conn.sendall[data]
703 represent the # echo-server.py
# ...
with socket.socket[socket.AF_INET, socket.SOCK_STREAM] as s:
s.bind[[HOST, PORT]]
s.listen[]
conn, addr = s.accept[]
with conn:
print[f"Connected by {addr}"]
while True:
data = conn.recv[1024]
if not data:
break
conn.sendall[data]
704 and # echo-server.py
# ...
with socket.socket[socket.AF_INET, socket.SOCK_STREAM] as s:
s.bind[[HOST, PORT]]
s.listen[]
conn, addr = s.accept[]
with conn:
print[f"Connected by {addr}"]
while True:
data = conn.recv[1024]
if not data:
break
conn.sendall[data]
705 members in the C struct # echo-server.py
# ...
with socket.socket[socket.AF_INET, socket.SOCK_STREAM] as s:
s.bind[[HOST, PORT]]
s.listen[]
conn, addr = s.accept[]
with conn:
print[f"Connected by {addr}"]
while True:
data = conn.recv[1024]
if not data:
break
conn.sendall[data]
706Note the excerpt below from Python’s socket module documentation regarding the
# echo-server.py
# ...
with socket.socket[socket.AF_INET, socket.SOCK_STREAM] as s:
s.bind[[HOST, PORT]]
s.listen[]
conn, addr = s.accept[]
with conn:
print[f"Connected by {addr}"]
while True:
data = conn.recv[1024]
if not data:
break
conn.sendall[data]
38 value of the address tuple“For IPv4 addresses, two special forms are accepted instead of a host address. the empty string represents
708, and the string# echo-server.py # ... with socket.socket[socket.AF_INET, socket.SOCK_STREAM] as s: s.bind[[HOST, PORT]] s.listen[] conn, addr = s.accept[] with conn: print[f"Connected by {addr}"] while True: data = conn.recv[1024] if not data: break conn.sendall[data]
709 represents# echo-server.py # ... with socket.socket[socket.AF_INET, socket.SOCK_STREAM] as s: s.bind[[HOST, PORT]] s.listen[] conn, addr = s.accept[] with conn: print[f"Connected by {addr}"] while True: data = conn.recv[1024] if not data: break conn.sendall[data]
710. This behavior is not compatible with IPv6, therefore, you may want to avoid these if you intend to support IPv6 with your Python programs. ” [Source]# echo-server.py # ... with socket.socket[socket.AF_INET, socket.SOCK_STREAM] as s: s.bind[[HOST, PORT]] s.listen[] conn, addr = s.accept[] with conn: print[f"Connected by {addr}"] while True: data = conn.recv[1024] if not data: break conn.sendall[data]
See Python’s Socket families documentation for more information
This tutorial uses IPv4 sockets, but if your network supports it, try testing and using IPv6 if possible. One way to support this easily is by using the function socket. getaddrinfo[]. It translates the
# echo-server.py
# ...
with socket.socket[socket.AF_INET, socket.SOCK_STREAM] as s:
s.bind[[HOST, PORT]]
s.listen[]
conn, addr = s.accept[]
with conn:
print[f"Connected by {addr}"]
while True:
data = conn.recv[1024]
if not data:
break
conn.sendall[data]
38 and # echo-server.py
# ...
with socket.socket[socket.AF_INET, socket.SOCK_STREAM] as s:
s.bind[[HOST, PORT]]
s.listen[]
conn, addr = s.accept[]
with conn:
print[f"Connected by {addr}"]
while True:
data = conn.recv[1024]
if not data:
break
conn.sendall[data]
401 arguments into a sequence of five-tuples that contains all of the necessary arguments for creating a socket connected to that service. # echo-server.py
# ...
with socket.socket[socket.AF_INET, socket.SOCK_STREAM] as s:
s.bind[[HOST, PORT]]
s.listen[]
conn, addr = s.accept[]
with conn:
print[f"Connected by {addr}"]
while True:
data = conn.recv[1024]
if not data:
break
conn.sendall[data]
713 sẽ hiểu và diễn giải các địa chỉ IPv6 được truyền vào và tên máy chủ phân giải thành địa chỉ IPv6, ngoài IPv4The following example returns address information for a TCP connection to
# echo-server.py
# ...
with socket.socket[socket.AF_INET, socket.SOCK_STREAM] as s:
s.bind[[HOST, PORT]]
s.listen[]
conn, addr = s.accept[]
with conn:
print[f"Connected by {addr}"]
while True:
data = conn.recv[1024]
if not data:
break
conn.sendall[data]
714 on port # echo-server.py
# ...
with socket.socket[socket.AF_INET, socket.SOCK_STREAM] as s:
s.bind[[HOST, PORT]]
s.listen[]
conn, addr = s.accept[]
with conn:
print[f"Connected by {addr}"]
while True:
data = conn.recv[1024]
if not data:
break
conn.sendall[data]
715>>>
$ python echo-server.py
6Results may differ on your system if IPv6 isn’t enabled. The values returned above can be used by passing them to
# echo-server.py
# ...
with socket.socket[socket.AF_INET, socket.SOCK_STREAM] as s:
s.bind[[HOST, PORT]]
s.listen[]
conn, addr = s.accept[]
with conn:
print[f"Connected by {addr}"]
while True:
data = conn.recv[1024]
if not data:
break
conn.sendall[data]
7 and # echo-server.py
# ...
with socket.socket[socket.AF_INET, socket.SOCK_STREAM] as s:
s.bind[[HOST, PORT]]
s.listen[]
conn, addr = s.accept[]
with conn:
print[f"Connected by {addr}"]
while True:
data = conn.recv[1024]
if not data:
break
conn.sendall[data]
717. There’s a client and server example in the Example section of Python’s socket module documentationUsing Hostnames
For context, this section applies mostly to using hostnames with
$ python echo-server.py
9 and # echo-server.py
# ...
with socket.socket[socket.AF_INET, socket.SOCK_STREAM] as s:
s.bind[[HOST, PORT]]
s.listen[]
conn, addr = s.accept[]
with conn:
print[f"Connected by {addr}"]
while True:
data = conn.recv[1024]
if not data:
break
conn.sendall[data]
2, or # echo-server.py
# ...
with socket.socket[socket.AF_INET, socket.SOCK_STREAM] as s:
s.bind[[HOST, PORT]]
s.listen[]
conn, addr = s.accept[]
with conn:
print[f"Connected by {addr}"]
while True:
data = conn.recv[1024]
if not data:
break
conn.sendall[data]
3, when you intend to use the loopback interface, “localhost. ” However, it also applies any time you’re using a hostname and there’s an expectation of it resolving to a certain address and having a special meaning to your application that affects its behavior or assumptions. This is in contrast to the typical scenario of a client using a hostname to connect to a server that’s resolved by DNS, like www. example. comThe following is from Python’s
# echo-server.py
# ...
with socket.socket[socket.AF_INET, socket.SOCK_STREAM] as s:
s.bind[[HOST, PORT]]
s.listen[]
conn, addr = s.accept[]
with conn:
print[f"Connected by {addr}"]
while True:
data = conn.recv[1024]
if not data:
break
conn.sendall[data]
679 module documentation“If you use a hostname in the host portion of IPv4/v6 socket address, the program may show a non-deterministic behavior, as Python uses the first address returned from the DNS resolution. The socket address will be resolved differently into an actual IPv4/v6 address, depending on the results from DNS resolution and/or the host configuration. For deterministic behavior use a numeric address in host portion. ” [Source]
The standard convention for the name “localhost” is for it to resolve to
# echo-server.py
# ...
with socket.socket[socket.AF_INET, socket.SOCK_STREAM] as s:
s.bind[[HOST, PORT]]
s.listen[]
conn, addr = s.accept[]
with conn:
print[f"Connected by {addr}"]
while True:
data = conn.recv[1024]
if not data:
break
conn.sendall[data]
400 or # echo-server.py
# ...
with socket.socket[socket.AF_INET, socket.SOCK_STREAM] as s:
s.bind[[HOST, PORT]]
s.listen[]
conn, addr = s.accept[]
with conn:
print[f"Connected by {addr}"]
while True:
data = conn.recv[1024]
if not data:
break
conn.sendall[data]
469, the loopback interface. This will more than likely be the case for you on your system, but maybe not. It depends on how your system is configured for name resolution. As with all things IT, there are always exceptions, and there are no guarantees that using the name “localhost” will connect to the loopback interfaceFor example, on Linux, see
# echo-server.py
# ...
with socket.socket[socket.AF_INET, socket.SOCK_STREAM] as s:
s.bind[[HOST, PORT]]
s.listen[]
conn, addr = s.accept[]
with conn:
print[f"Connected by {addr}"]
while True:
data = conn.recv[1024]
if not data:
break
conn.sendall[data]
724, the Name Service Switch configuration file. Another place to check on macOS and Linux is the file # echo-server.py
# ...
with socket.socket[socket.AF_INET, socket.SOCK_STREAM] as s:
s.bind[[HOST, PORT]]
s.listen[]
conn, addr = s.accept[]
with conn:
print[f"Connected by {addr}"]
while True:
data = conn.recv[1024]
if not data:
break
conn.sendall[data]
725. On Windows, see # echo-server.py
# ...
with socket.socket[socket.AF_INET, socket.SOCK_STREAM] as s:
s.bind[[HOST, PORT]]
s.listen[]
conn, addr = s.accept[]
with conn:
print[f"Connected by {addr}"]
while True:
data = conn.recv[1024]
if not data:
break
conn.sendall[data]
726. The # echo-server.py
# ...
with socket.socket[socket.AF_INET, socket.SOCK_STREAM] as s:
s.bind[[HOST, PORT]]
s.listen[]
conn, addr = s.accept[]
with conn:
print[f"Connected by {addr}"]
while True:
data = conn.recv[1024]
if not data:
break
conn.sendall[data]
727 file contains a static table of name-to-address mappings in a simple text format. DNS is another piece of the puzzle altogetherInterestingly enough, as of June 2018, there’s an RFC draft Let ‘localhost’ be localhost that discusses the conventions, assumptions, and security around using the name “localhost. ”
What’s important to understand is that when you use hostnames in your application, the returned addresses could literally be anything. Don’t make assumptions regarding a name if you have a security-sensitive application. Depending on your application and environment, this may or may not be a concern for you
Note. Security precautions and best practices still apply, even if your application isn’t explicitly security-sensitive. If your application accesses the network, it should be secured and maintained. This means, at a minimum
System software updates and security patches are applied regularly, including Python. Are you using any third-party libraries? If so, make sure those are checked and updated too
Nếu có thể, hãy sử dụng tường lửa chuyên dụng hoặc dựa trên máy chủ để chỉ hạn chế kết nối với các hệ thống đáng tin cậy
What DNS servers are configured? Do you trust them and their administrators?
Make sure that request data is sanitized and validated as much as possible prior to calling other code that processes it. Use fuzz tests for this and run them regularly
Regardless of whether or not you’re using hostnames, if your application needs to support secure connections through encryption and authentication, then you’ll probably want to look into using TLS. This is its own separate topic and beyond the scope of this tutorial. See Python’s ssl module documentation to get started. This is the same protocol that your web browser uses to connect securely to web sites
With interfaces, IP addresses, and name resolution to consider, there are many variables. What should you do? Here are some recommendations that you can use if you don’t have a network application review process
ApplicationUsageRecommendationServerloopback interfaceUse an IP address, such as
# echo-server.py
# ...
with socket.socket[socket.AF_INET, socket.SOCK_STREAM] as s:
s.bind[[HOST, PORT]]
s.listen[]
conn, addr = s.accept[]
with conn:
print[f"Connected by {addr}"]
while True:
data = conn.recv[1024]
if not data:
break
conn.sendall[data]
400 or # echo-server.py
# ...
with socket.socket[socket.AF_INET, socket.SOCK_STREAM] as s:
s.bind[[HOST, PORT]]
s.listen[]
conn, addr = s.accept[]
with conn:
print[f"Connected by {addr}"]
while True:
data = conn.recv[1024]
if not data:
break
conn.sendall[data]
469. Serverethernet interfaceUse an IP address, such as # echo-server.py
# ...
with socket.socket[socket.AF_INET, socket.SOCK_STREAM] as s:
s.bind[[HOST, PORT]]
s.listen[]
conn, addr = s.accept[]
with conn:
print[f"Connected by {addr}"]
while True:
data = conn.recv[1024]
if not data:
break
conn.sendall[data]
407. To support more than one interface, use an empty string for all interfaces/addresses. See the security note above. Clientloopback interfaceUse an IP address, such as # echo-server.py
# ...
with socket.socket[socket.AF_INET, socket.SOCK_STREAM] as s:
s.bind[[HOST, PORT]]
s.listen[]
conn, addr = s.accept[]
with conn:
print[f"Connected by {addr}"]
while True:
data = conn.recv[1024]
if not data:
break
conn.sendall[data]
400 or # echo-server.py
# ...
with socket.socket[socket.AF_INET, socket.SOCK_STREAM] as s:
s.bind[[HOST, PORT]]
s.listen[]
conn, addr = s.accept[]
with conn:
print[f"Connected by {addr}"]
while True:
data = conn.recv[1024]
if not data:
break
conn.sendall[data]
469. Giao diện clientethernetSử dụng địa chỉ IP để đảm bảo tính nhất quán và không phụ thuộc vào độ phân giải tên. Đối với trường hợp điển hình, hãy sử dụng tên máy chủ. Xem lưu ý bảo mật ở trênĐối với máy khách hoặc máy chủ, nếu bạn cần xác thực máy chủ mà bạn đang kết nối, hãy xem xét sử dụng TLS
chặn cuộc gọi
Hàm hoặc phương thức ổ cắm tạm thời treo ứng dụng của bạn là lệnh gọi chặn. Ví dụ: khối
# echo-server.py
# ...
with socket.socket[socket.AF_INET, socket.SOCK_STREAM] as s:
s.bind[[HOST, PORT]]
s.listen[]
conn, addr = s.accept[]
with conn:
print[f"Connected by {addr}"]
while True:
data = conn.recv[1024]
if not data:
break
conn.sendall[data]
1, # echo-server.py
# ...
with socket.socket[socket.AF_INET, socket.SOCK_STREAM] as s:
s.bind[[HOST, PORT]]
s.listen[]
conn, addr = s.accept[]
with conn:
print[f"Connected by {addr}"]
while True:
data = conn.recv[1024]
if not data:
break
conn.sendall[data]
2, # echo-server.py
# ...
with socket.socket[socket.AF_INET, socket.SOCK_STREAM] as s:
s.bind[[HOST, PORT]]
s.listen[]
conn, addr = s.accept[]
with conn:
print[f"Connected by {addr}"]
while True:
data = conn.recv[1024]
if not data:
break
conn.sendall[data]
4 và # echo-server.py
# ...
with socket.socket[socket.AF_INET, socket.SOCK_STREAM] as s:
s.bind[[HOST, PORT]]
s.listen[]
conn, addr = s.accept[]
with conn:
print[f"Connected by {addr}"]
while True:
data = conn.recv[1024]
if not data:
break
conn.sendall[data]
5, nghĩa là chúng không quay trở lại ngay lập tức. Blocking calls have to wait on system calls [I/O] to complete before they can return a value. Vì vậy, bạn, người gọi, bị chặn cho đến khi họ thực hiện xong hoặc hết thời gian chờ hoặc xảy ra lỗi khácCác cuộc gọi ổ cắm chặn có thể được đặt thành chế độ không chặn để chúng quay lại ngay lập tức. Nếu bạn làm điều này, thì ít nhất bạn sẽ cần cấu trúc lại hoặc thiết kế lại ứng dụng của mình để xử lý hoạt động của ổ cắm khi nó sẵn sàng
Because the call returns immediately, data may not be ready. Callee đang đợi trên mạng và không có thời gian để hoàn thành công việc của mình. Nếu đây là trường hợp, thì trạng thái hiện tại là giá trị
# echo-server.py
# ...
with socket.socket[socket.AF_INET, socket.SOCK_STREAM] as s:
s.bind[[HOST, PORT]]
s.listen[]
conn, addr = s.accept[]
with conn:
print[f"Connected by {addr}"]
while True:
data = conn.recv[1024]
if not data:
break
conn.sendall[data]
681 # echo-server.py
# ...
with socket.socket[socket.AF_INET, socket.SOCK_STREAM] as s:
s.bind[[HOST, PORT]]
s.listen[]
conn, addr = s.accept[]
with conn:
print[f"Connected by {addr}"]
while True:
data = conn.recv[1024]
if not data:
break
conn.sendall[data]
738. Chế độ không chặn được hỗ trợ với. thiết lập chặn []By default, sockets are always created in blocking mode. See Notes on socket timeouts for a description of the three modes
Đóng kết nối
An interesting thing to note with TCP is that it’s completely legal for the client or server to close their side of the connection while the other side remains open. Điều này được gọi là kết nối “nửa mở”. Đó là quyết định của ứng dụng cho dù điều này có được mong muốn hay không. In general, it’s not. In this state, the side that has closed their end of the connection can no longer send data. They can only receive it
Cách tiếp cận này không nhất thiết được khuyến nghị, nhưng ví dụ: HTTP sử dụng tiêu đề có tên "Kết nối" được sử dụng để chuẩn hóa cách các ứng dụng nên đóng hoặc duy trì các kết nối mở. For details, see section 6. 3 in RFC 7230, Hypertext Transfer Protocol [HTTP/1. 1]. Message Syntax and Routing
When designing and writing your application and its application-layer protocol, it’s a good idea to go ahead and work out how you expect connections to be closed. Sometimes this is obvious and simple, or it’s something that can take some initial prototyping and testing. It depends on the application and how the message loop is processed with its expected data. Just make sure that sockets are always closed in a timely manner after they complete their work
Byte Endianness
See Wikipedia’s article on endianness for details on how different CPUs store byte orderings in memory. When interpreting individual bytes, this isn’t a problem. However, when you’re handling multiple bytes that are read and processed as a single value, for example a 4-byte integer, the byte order needs to be reversed if you’re communicating with a machine that uses a different endianness
Byte order is also important for text strings that are represented as multi-byte sequences, like Unicode. Unless you’re always using true, strict ASCII and control the client and server implementations, you’re probably better off using Unicode with an encoding like UTF-8 or one that supports a byte order mark [BOM]
It’s important to explicitly define the encoding used in your application-layer protocol. You can do this by mandating that all text is UTF-8 or using a “content-encoding” header that specifies the encoding. This prevents your application from having to detect the encoding, which you should avoid if possible
This becomes problematic when there is data involved that’s stored in files or a database and there’s no metadata available that specifies its encoding. When the data is transferred to another endpoint, it’ll have to try to detect the encoding. For a discussion, see Wikipedia’s Unicode article, which references RFC 3629. UTF-8, a transformation format of ISO 10646
“However RFC 3629, the UTF-8 standard, recommends that byte order marks be forbidden in protocols using UTF-8, but discusses the cases where this may not be possible. In addition, the large restriction on possible patterns in UTF-8 [for instance there cannot be any lone bytes with the high bit set] means that it should be possible to distinguish UTF-8 from other character encodings without relying on the BOM. ” [Source]
The takeaway from this is to always store the encoding used for data that’s handled by your application if it can vary. In other words, try to somehow store the encoding as metadata if it’s not always UTF-8 or some other encoding with a BOM. Then you can send that encoding in a header along with the data to tell the receiver what it is
The byte ordering used in TCP/IP is big-endian and is referred to as network order. Network order is used to represent integers in lower layers of the protocol stack, like IP addresses and port numbers. Python’s socket module includes functions that convert integers to and from network and host byte order
FunctionDescription
# echo-server.py
# ...
with socket.socket[socket.AF_INET, socket.SOCK_STREAM] as s:
s.bind[[HOST, PORT]]
s.listen[]
conn, addr = s.accept[]
with conn:
print[f"Connected by {addr}"]
while True:
data = conn.recv[1024]
if not data:
break
conn.sendall[data]
739Convert 32-bit positive integers from network to host byte order. On machines where the host byte order is the same as network byte order, this is a no-op; otherwise, it performs a 4-byte swap operation. # echo-server.py
# ...
with socket.socket[socket.AF_INET, socket.SOCK_STREAM] as s:
s.bind[[HOST, PORT]]
s.listen[]
conn, addr = s.accept[]
with conn:
print[f"Connected by {addr}"]
while True:
data = conn.recv[1024]
if not data:
break
conn.sendall[data]
740Convert 16-bit positive integers from network to host byte order. On machines where the host byte order is the same as network byte order, this is a no-op; otherwise, it performs a 2-byte swap operation. # echo-server.py
# ...
with socket.socket[socket.AF_INET, socket.SOCK_STREAM] as s:
s.bind[[HOST, PORT]]
s.listen[]
conn, addr = s.accept[]
with conn:
print[f"Connected by {addr}"]
while True:
data = conn.recv[1024]
if not data:
break
conn.sendall[data]
741Convert 32-bit positive integers from host to network byte order. On machines where the host byte order is the same as network byte order, this is a no-op; otherwise, it performs a 4-byte swap operation. # echo-server.py
# ...
with socket.socket[socket.AF_INET, socket.SOCK_STREAM] as s:
s.bind[[HOST, PORT]]
s.listen[]
conn, addr = s.accept[]
with conn:
print[f"Connected by {addr}"]
while True:
data = conn.recv[1024]
if not data:
break
conn.sendall[data]
742Convert 16-bit positive integers from host to network byte order. On machines where the host byte order is the same as network byte order, this is a no-op; otherwise, it performs a 2-byte swap operationYou can also use the struct module to pack and unpack binary data using format strings
$ python echo-server.py
7Conclusion
You covered a lot of ground in this tutorial. Networking and sockets are large subjects. If you’re new to networking or sockets, don’t be discouraged by all of the terms and acronyms
There are a lot of pieces to become familiar with in order to understand how everything works together. However, just like Python, it will start to make more sense as you get to know the individual pieces and spend more time with them
In this tutorial, you
- Looked at the low-level socket API in Python’s
679 module and saw how it can be used to create client-server applications# echo-server.py # ... with socket.socket[socket.AF_INET, socket.SOCK_STREAM] as s: s.bind[[HOST, PORT]] s.listen[] conn, addr = s.accept[] with conn: print[f"Connected by {addr}"] while True: data = conn.recv[1024] if not data: break conn.sendall[data]
- Built a client and server that can handle multiple connections using a
744 object# echo-server.py # ... with socket.socket[socket.AF_INET, socket.SOCK_STREAM] as s: s.bind[[HOST, PORT]] s.listen[] conn, addr = s.accept[] with conn: print[f"Connected by {addr}"] while True: data = conn.recv[1024] if not data: break conn.sendall[data]
- Created your own custom class and used it as an application-layer protocol to exchange messages and data between endpoints
From here, you can use your custom class and build upon it to learn and help make creating your own socket applications easier and faster
To review the examples, you can click the link below
Get Source Code. Click here to get the source code you’ll use for the examples in this tutorial
Congratulations on making it to the end. You are now well on your way to using sockets in your own applications. Best of luck on your sockets development journey
Mark as Completed
🐍 Python Tricks 💌
Get a short & sweet Python Trick delivered to your inbox every couple of days. No spam ever. Unsubscribe any time. Curated by the Real Python team
Gửi cho tôi thủ thuật Python »
About Nathan Jennings
Nathan is a member of the Real Python tutorial team who started his programmer career with C a long time ago, but eventually found Python. From web applications and data collection to networking and network security, he enjoys all things Pythonic
» More about NathanEach tutorial at Real Python is created by a team of developers so that it meets our high quality standards. The team members who worked on this tutorial are
Aldren
Brad
Geir Arne
Ian
Jim
Joanna
Kate
Master Real-World Python Skills With Unlimited Access to Real Python
Join us and get access to thousands of tutorials, hands-on video courses, and a community of expert Pythonistas
Level Up Your Python Skills »
Master Real-World Python Skills
With Unlimited Access to Real Python
Join us and get access to thousands of tutorials, hands-on video courses, and a community of expert Pythonistas
Level Up Your Python Skills »
What Do You Think?
Đánh giá bài viết này
Tweet Chia sẻ Chia sẻ EmailWhat’s your #1 takeaway or favorite thing you learned? How are you going to put your newfound skills to use? Leave a comment below and let us know
Mẹo bình luận. The most useful comments are those written with the goal of learning from or helping out other students. Nhận các mẹo để đặt câu hỏi hay và nhận câu trả lời cho các câu hỏi phổ biến trong cổng thông tin hỗ trợ của chúng tôi