Xin chào mọi người, hôm nay chúng ta sẽ tạo một phòng trò chuyện thực sự đơn giản trong Python 3 với sự trợ giúp của các mô-đun tích hợp socket và threading
Ứng dụng trò chuyện của chúng tôi sẽ bao gồm một máy chủ và nhiều máy khách. Các máy khách sẽ thiết lập kết nối ổ cắm với máy chủ. Để kết nối ổ cắm hoạt động, cả máy chủ và máy khách cần phải ở trên cùng một máy hoặc trong cùng một mạng. Vì vậy, phòng trò chuyện sẽ hoạt động trên mạng LAN [Mạng cục bộ]
Hiểu về ổ cắm PythonTrước khi nhảy vào mã, chúng ta cần hiểu cách thức hoạt động của các ổ cắm. Không cần thiết phải biết cách thức hoạt động của các ổ cắm bên trong, thật thú vị khi biết rằng mô-đun ổ cắm python sử dụng thư viện ổ cắm C để trao đổi dữ liệu trên mạng. Về cơ bản, một máy chủ socket cần được khởi tạo, sau đó máy khách sẽ kết nối trực tiếp với máy chủ. Khi kết nối được thiết lập, một ổ cắm có thể vừa nghe vừa gửi tin nhắn, nếu một ổ cắm đang gửi và ổ cắm kia đang nghe, chúng ta sẽ có thể trao đổi dữ liệu giữa chúng
Bước 1. Mã hóa máy chủ
Khi bạn đã tạo tệp
my_socket.listen[]
client, client_address = my_socket.accept[]
8 của mình, chúng ta có thể bắt đầu mã hóaĐầu tiên, chúng tôi sẽ nhập mô-đun chúng tôi cần
import socket
Sau đó, hãy tạo đối tượng socket của chúng ta
my_socket = socket.socket[socket.AF_INET, socket.SOCK_STREAM]
my_socket.listen[]
client, client_address = my_socket.accept[]
9 và message = client.recv[1024] #bytes
print[message.decode[]]
0 chỉ là các hằng số được định nghĩa trong module socket để chọn loại socket mà chúng ta muốn, bạn không cần hiểu ý nghĩa của chúng để sử dụng chúngBây giờ ổ cắm đã được tạo, chúng ta có thể liên kết nó với một cổng và tùy chọn một địa chỉ. Chúng tôi tạo hai hằng số có tên là
message = client.recv[1024] #bytes
print[message.decode[]]
1 và message = client.recv[1024] #bytes
print[message.decode[]]
2 để giữ cổng và địa chỉ chúng tôi sẽ sử dụng. Hiện tại, chúng tôi để địa chỉ là message = client.recv[1024] #bytes
print[message.decode[]]
3, vì chúng tôi không biết địa chỉ của khách hàng sẽ là gì________số 8Bây giờ ổ cắm của chúng tôi đã sẵn sàng, chúng tôi có thể bắt đầu lắng nghe kết nối. Sau đó, chúng ta cần chấp nhận kết nối đến
my_socket.listen[]
client, client_address = my_socket.accept[]
Phương thức listen[] chỉ cho phép các kết nối đến. Phương thức accept[] trả về một bộ, phần tử đầu tiên là kết nối, bây giờ chúng ta sẽ sử dụng nó để tương tác với máy khách và phần tử thứ hai là một bộ chứa địa chỉ IP của máy khách cũng như cổng được sử dụng [có thể là
Bây giờ chúng tôi đã sẵn sàng để bắt đầu nghe tin nhắn từ khách hàng
message = client.recv[1024] #bytes
print[message.decode[]]
Phương thức recv[] chỉ nhận một đối số không tùy chọn, kích thước bộ đệm, đó là dung lượng tối đa có sẵn để nhận tin nhắn. Đừng quên rằng phương thức này trả về một đối tượng byte và vì vậy bạn cần giải mã nó thành một chuỗi
OK, vậy bây giờ chúng ta sẽ hoàn thành với tập lệnh máy chủ cơ bản nhất có thể và tập lệnh máy khách thậm chí còn đơn giản hơn, bạn sẽ thấy. Ngay trước khi chuyển sang mã máy khách, hãy đảm bảo rằng chúng ta có cùng mã máy chủ, nếu bạn làm theo hướng dẫn này tốt, mã của bạn sẽ trông giống như thế
import socket
1Bước 2. Mã hóa khách hàng
Tập lệnh máy khách gần giống như tập lệnh máy chủ, ngoại trừ thay vì lắng nghe kết nối và tin nhắn, chúng tôi thực sự sẽ kết nối và gửi tin nhắn
Đầu tiên, nhập mô-đun và tạo đối tượng ổ cắm của chúng tôi
import socket
2Bây giờ chúng ta cần xác định cổng và địa chỉ của máy chủ, nếu bạn đang sử dụng cùng cổng với tôi, thì đó phải là
message = client.recv[1024] #bytes
print[message.decode[]]
4. Đối với địa chỉ, bạn chỉ cần nhập địa chỉ của máy chủ, nếu bạn đang chạy máy chủ và máy khách trên cùng một máy tính, thì địa chỉ máy chủ phải là message = client.recv[1024] #bytes
print[message.decode[]]
5, nếu không thì chỉ cần tìm địa chỉ IP của máy chủ [Tôi sẽ không giải thích import socket
5Sau đó, chúng ta có thể kết nối với máy chủ
import socket
6Bây giờ chúng tôi đã sẵn sàng để gửi tin nhắn. Chỉ cần gõ vào
import socket
7Đừng quên mã hóa chuỗi thành byte, như chúng ta đã thấy trước đây, socket trao đổi byte, không phải chuỗi
Vì vậy, bây giờ tập lệnh máy khách của bạn sẽ trông giống như thế
my_socket = socket.socket[socket.AF_INET, socket.SOCK_STREAM]
0Bây giờ bạn có thể sử dụng tập lệnh, khởi động tập lệnh máy chủ và khi nó bắt đầu khởi chạy tập lệnh máy khách, nếu mọi thứ diễn ra suôn sẻ, bạn sẽ thấy thông báo bạn đã chọn, được hiển thị trong bảng điều khiển của máy chủ bảng điều khiển
Cải thiện bản demo cơ bản của chúng tôiBây giờ có lẽ bạn đã thử nghiệm bản demo nhỏ của chúng tôi và có thể bạn đang tự nhủ rằng đây không giống một phòng chat. Và như bạn đang nói, đây chỉ là một bản demo để hiểu các ổ cắm, bây giờ chúng tôi thực sự có thể triển khai phòng trò chuyện nhỏ của mình
Đầu tiên, vì đây là một cuộc trò chuyện, nên chúng tôi có thể sẽ cần gửi nhiều tin nhắn chứ không chỉ một tin nhắn, vì vậy chúng tôi sẽ chỉnh sửa tập lệnh máy chủ của mình để nghe mãi mãi và trong ứng dụng khách, chúng tôi sẽ cho phép người dùng nhập một số
my_socket = socket.socket[socket.AF_INET, socket.SOCK_STREAM]
1Như bạn có thể thấy, tôi đã thêm một vòng lặp vô hạn để không bao giờ ngừng nghe tin nhắn. Bây giờ hãy làm việc trên client script
my_socket = socket.socket[socket.AF_INET, socket.SOCK_STREAM]
2Và ở đây, như bạn có thể thấy, người dùng hiện có thể nhập tin nhắn mà anh ấy muốn gửi và tôi cũng đã thêm một vòng lặp vô hạn ở đây. Tôi khuyến khích bạn thử mã này để thấy rằng nó hoạt động
Bước 3. Cho phép khách hàng của chúng tôi nhận được
OK, bây giờ chúng ta có thể gửi nhiều tin nhắn đến máy chủ, nhưng còn việc nhận tin nhắn từ máy chủ thì sao?
Vì vậy, chúng tôi sẽ cần lắng nghe cả đầu vào của người dùng và lắng nghe thông báo của máy chủ cùng một lúc, chúng tôi có thể làm điều đó như thế nào?
Một trong những giải pháp đơn giản nhất là sử dụng mô-đun tích hợp luồng python, với điều đó, chúng tôi sẽ có thể chạy nhiều luồng cùng một lúc, tôi sẽ không đi sâu vào chi tiết ở đây, chỉ cần xem các luồng như . Nếu bạn không biết cách thức hoạt động của các luồng, tôi khuyến khích bạn tìm thêm thông tin về chúng vì nó thực sự hữu ích trong mạng và lập trình nói chung
Bây giờ chúng tôi biết cách giải quyết vấn đề, chúng tôi cần mô-đun luồng, vì vậy hãy nhập nó
my_socket = socket.socket[socket.AF_INET, socket.SOCK_STREAM]
3Bây giờ chúng ta cần xác định hai hàm, một để nghe và một để gửi. Đối với phần gửi, chúng ta chỉ cần đặt vòng lặp while của mình vào một hàm, đại loại như thế này
my_socket = socket.socket[socket.AF_INET, socket.SOCK_STREAM]
4Và chức năng nghe sẽ không phức tạp hơn
my_socket = socket.socket[socket.AF_INET, socket.SOCK_STREAM]
5Khi chúng tôi có hai chức năng của mình, bây giờ chúng tôi có thể tạo hai luồng, một luồng cho mỗi chức năng và bắt đầu chúng. Các luồng thực sự đơn giản để sử dụng, chúng ta chỉ cần tạo hai đối tượng luồng và chỉ định chức năng mà chúng sẽ thực thi
my_socket = socket.socket[socket.AF_INET, socket.SOCK_STREAM]
6Chúng tôi chỉ cần bắt đầu chúng và đó là tất cả cho khách hàng bây giờ
my_socket = socket.socket[socket.AF_INET, socket.SOCK_STREAM]
7Bạn có thể thử chạy tập lệnh máy khách và bạn sẽ không thấy bất kỳ sự khác biệt nào, đó là vì chúng tôi chưa yêu cầu máy chủ gửi bất kỳ tin nhắn nào, vì vậy hãy bắt tay vào việc đó. Để đơn giản, chúng ta sẽ làm cho máy chủ gửi một thứ gì đó mỗi khi nhận được tin nhắn, đại loại như thế
my_socket = socket.socket[socket.AF_INET, socket.SOCK_STREAM]
8Bây giờ bạn có thể gửi tin nhắn và nhận phản hồi từ máy chủ. Như mọi khi, trước khi bắt đầu bước tiếp theo, hãy đảm bảo rằng chúng ta làm việc với cùng một mã
my_socket = socket.socket[socket.AF_INET, socket.SOCK_STREAM]
9Và khách hàng
PORT = 8000
ADDRESS = "0.0.0.0"
my_socket.bind[[ADDRESS, PORT]]
0Bước 4. Thêm nhiều hơn một khách hàng
OK, vậy bây giờ chúng ta có thể kết nối với máy chủ bằng ứng dụng khách, chúng ta có thể gửi và nhận tin nhắn từ máy chủ, chúng ta gần như đã hoàn tất, nhưng, không phải một cuộc trò chuyện bao gồm nhiều người sao?
Vì vậy ban đầu chúng ta có thể chỉ nghĩ rằng để tạo một chat thì chỉ cần bắt đầu nhiều client, nhưng sau khi thử nghiệm phương pháp này, bạn sẽ hiểu rằng trong một chat, client cần phải tương tác với các client khác chứ không chỉ tương tác với nhau. . Để giải quyết vấn đề này, chúng tôi sẽ cần giữ một danh sách tất cả các máy khách được kết nối và mỗi khi ai đó gửi tin nhắn, chúng tôi sẽ gửi tin nhắn này cho tất cả các máy khách trong danh sách. Máy chủ của chúng tôi sẽ truyền tin nhắn từ khách hàng này sang khách hàng khác
Bước đầu tiên là có thể xử lý nhiều kết nối, như bạn có thể thấy trong mã, phương thức accept[] chỉ được gọi một lần, nghĩa là chúng ta chỉ có thể nhận một kết nối, hãy thay đổi điều đó và chúng ta sẽ viết mã
PORT = 8000
ADDRESS = "0.0.0.0"
my_socket.bind[[ADDRESS, PORT]]
1Bây giờ chúng ta có thể thêm ứng dụng khách vào danh sách phát, trước tiên chúng ta cần tạo danh sách [ngoài chức năng]
PORT = 8000
ADDRESS = "0.0.0.0"
my_socket.bind[[ADDRESS, PORT]]
2Và nối ứng dụng khách vào danh sách [trong vòng lặp]
PORT = 8000
ADDRESS = "0.0.0.0"
my_socket.bind[[ADDRESS, PORT]]
3Và điều cuối cùng, chúng ta cần thiết lập một chuỗi sẽ lắng nghe tin nhắn từ khách hàng
PORT = 8000
ADDRESS = "0.0.0.0"
my_socket.bind[[ADDRESS, PORT]]
4Như bạn có thể thấy, chúng tôi chưa mã hóa chức năng này, chúng tôi sẽ thực hiện điều đó sau một phút, trước khi đảm bảo rằng chúng tôi có chức năng tương tự
PORT = 8000
ADDRESS = "0.0.0.0"
my_socket.bind[[ADDRESS, PORT]]
5OK, bây giờ chúng ta chắc chắn có cùng mã, vì vậy hãy tạo hàm
message = client.recv[1024] #bytes
print[message.decode[]]
6. Chức năng này cần tạo một chuỗi dành riêng cho ứng dụng khách này sẽ nghe tin nhắn và phát chúngPORT = 8000
ADDRESS = "0.0.0.0"
my_socket.bind[[ADDRESS, PORT]]
6Bây giờ chúng ta cần triển khai chức năng
message = client.recv[1024] #bytes
print[message.decode[]]
7 của mìnhPORT = 8000
ADDRESS = "0.0.0.0"
my_socket.bind[[ADDRESS, PORT]]
7Và chức năng cuối cùng để viết,
message = client.recv[1024] #bytes
print[message.decode[]]
8 sẽ chỉ gửi tin nhắn cho mọi khách hàng trong danh sách quảng báPORT = 8000
ADDRESS = "0.0.0.0"
my_socket.bind[[ADDRESS, PORT]]
8Bây giờ chúng ta có thể chạy một chức năng để bắt đầu chấp nhận kết nối. Bây giờ mã của bạn sẽ trông như thế
PORT = 8000
ADDRESS = "0.0.0.0"
my_socket.bind[[ADDRESS, PORT]]
9Nếu bạn đã mã hóa mọi thứ đúng, bây giờ bạn có thể khởi động máy chủ và kết nối một số máy khách với nó, gửi tin nhắn, v.v.
Bước 5. Một số vấn đề cần giải quyết
Nếu bạn đã kiểm tra trò chuyện, bạn sẽ nhận thấy một số vấn đề, thứ nhất, khi tin nhắn được gửi, chúng tôi không có cách nào để biết ai đã gửi tin nhắn và thứ hai, [cái này ít hiển thị hơn] nhưng chúng tôi đã tạo ra không có cách nào.
Thêm biệt danh vào ứng dụng của chúng tôi
Vì vậy, chúng tôi có hai tùy chọn để triển khai biệt hiệu, chúng tôi có thể triển khai điều này ở phía máy chủ hoặc phía máy khách. Để đơn giản ở đây chúng ta sẽ chọn tùy chọn thứ hai. [Hãy nhớ rằng phòng trò chuyện của chúng tôi hoàn toàn không được bảo mật, có nhiều cách khai thác nhưng chúng tôi không quan tâm đến điều đó. ]
Tập lệnh máy khách sẽ cần yêu cầu người dùng chọn biệt hiệu, sau đó gửi biệt hiệu cùng với tin nhắn. Điều này không phức tạp lắm
my_socket.listen[]
client, client_address = my_socket.accept[]
0Và chúng tôi có thể xác minh biệt hiệu không trống
my_socket.listen[]
client, client_address = my_socket.accept[]
1Và bây giờ chúng ta có biệt danh của người dùng, chúng ta có thể gửi biệt hiệu đó cùng với tin nhắn, chức năng
message = client.recv[1024] #bytes
print[message.decode[]]
9 của chúng ta bây giờ trông như thế nàymy_socket.listen[]
client, client_address = my_socket.accept[]
2Và bây giờ, người dùng có một biệt danh, nó không phức tạp lắm.
import socket
10 của bạn sẽ trông như thế nàymy_socket.listen[]
client, client_address = my_socket.accept[]
3Bây giờ máy chủ sẽ xử lý nếu máy khách ngắt kết nối
Bạn có thể nhận thấy rằng khi máy khách ngắt kết nối [sử dụng Ctrl+C], máy chủ có một hành vi rất lạ khi nó không ngừng in
import socket
11Vì vậy, trước tiên, hãy đảm bảo rằng khách hàng chỉ gửi tin nhắn nếu nó không trống
my_socket.listen[]
client, client_address = my_socket.accept[]
4Và máy chủ chỉ in thông báo nếu nó không trống, nếu có nghĩa là máy khách đã bị ngắt kết nối, vì vậy chúng ta có thể dừng chuỗi nghe [để dừng chuỗi chúng ta chỉ cần thoát khỏi chức năng]
my_socket.listen[]
client, client_address = my_socket.accept[]
5Bây giờ mã của bạn sẽ trông như thế này
my_socket.listen[]
client, client_address = my_socket.accept[]
6Và kịch bản khách hàng
my_socket.listen[]
client, client_address = my_socket.accept[]
7Nếu mã của bạn giống như vậy, phòng chat sẽ hoạt động. Rõ ràng là có rất nhiều thứ bạn có thể thêm vào nhưng hướng dẫn này chỉ là xây dựng một cuộc trò chuyện rất đơn giản