Ví dụ máy chủ ổ cắm không chặn Python
Ổ cắm và API ổ cắm được sử dụng để gửi tin nhắn qua mạng. Họ cung cấp một hình thức giao tiếp giữa các quá trình (IPC). Mạng có thể là mạng cục bộ, hợp lý với máy tính hoặc mạng được kết nối vật lý với mạng bên ngoài, có kết nối riêng với các mạng khác. Ví dụ rõ ràng là Internet mà bạn kết nối thông qua ISP của mình Show
Trong hướng dẫn này, bạn sẽ tạo
Đến cuối hướng dẫn này, bạn sẽ hiểu cách sử dụng các hàm và phương thức chính trong mô-đun socket của Python để viết các ứng dụng máy khách-máy chủ của riêng bạn. Bạn sẽ biết cách sử dụng một lớp tùy chỉnh để gửi tin nhắn và dữ liệu giữa các điểm cuối mà bạn có thể xây dựng và sử dụng cho các ứng dụng của riêng mình Các ví dụ trong hướng dẫn này yêu cầu Python 3. 6 trở lên và đã được thử nghiệm bằng Python 3. 10. Để tận dụng tối đa hướng dẫn này, tốt nhất bạn nên tải xuống mã nguồn và có sẵn nó để tham khảo khi đọc Nhận mã nguồn. Nhấp vào đây để lấy mã nguồn mà bạn sẽ sử dụng cho các ví dụ trong hướng dẫn này Mạng và ổ cắm là những chủ đề lớn. Khối lượng văn học đã được viết về họ. Nếu bạn chưa quen với ổ cắm hoặc kết nối mạng, việc bạn cảm thấy choáng ngợp với tất cả các thuật ngữ và phần là hoàn toàn bình thường. Đừng nản lòng mặc dù. Hướng dẫn này là dành cho bạn. Như với bất kỳ thứ gì liên quan đến Python, bạn có thể học từng chút một. Đánh dấu bài viết này và quay lại khi bạn đã sẵn sàng cho phần tiếp theo Lý lịchỔ cắm có một lịch sử lâu dài. Việc sử dụng chúng bắt nguồn từ ARPANET vào năm 1971 và sau đó trở thành API trong hệ điều hành Phân phối phần mềm Berkeley (BSD) phát hành năm 1983 được gọi là ổ cắm Berkeley Khi Internet cất cánh vào những năm 1990 với World Wide Web, lập trình mạng cũng vậy. Máy chủ và trình duyệt web không phải là ứng dụng duy nhất tận dụng các mạng mới được kết nối và sử dụng ổ cắm. Các ứng dụng máy khách-máy chủ thuộc mọi loại và kích cỡ được sử dụng rộng rãi Ngày nay, mặc dù các giao thức cơ bản được sử dụng bởi API ổ cắm đã phát triển qua nhiều năm và các giao thức mới đã được phát triển, nhưng API cấp thấp vẫn giữ nguyên Loại ứng dụng ổ cắm phổ biến nhất là ứng dụng máy khách-máy chủ, trong đó một bên đóng vai trò là máy chủ và chờ kết nối từ máy khách. Đây là loại ứng dụng mà bạn sẽ tạo trong hướng dẫn này. Cụ thể hơn, bạn sẽ tập trung vào API ổ cắm cho ổ cắm Internet, đôi khi được gọi là ổ cắm Berkeley hoặc BSD. Ngoài ra còn có các ổ cắm tên miền Unix, chỉ có thể được sử dụng để giao tiếp giữa các quy trình trên cùng một máy chủ Loại bỏ các quảng cáoTổng quan về API ổ cắmMô-đun ổ cắm của Python cung cấp giao diện cho API ổ cắm Berkeley. Đây là mô-đun mà bạn sẽ sử dụng trong hướng dẫn này Các hàm và phương thức API ổ cắm chính trong mô-đun này là
Python cung cấp một API thuận tiện và nhất quán ánh xạ trực tiếp tới các lệnh gọi hệ thống, các đối tác C của chúng. Trong phần tiếp theo, bạn sẽ tìm hiểu cách chúng được sử dụng cùng nhau Là một phần của thư viện chuẩn, Python cũng có các lớp giúp sử dụng các hàm ổ cắm cấp thấp này dễ dàng hơn. Mặc dù nó không được đề cập trong hướng dẫn này, nhưng bạn có thể xem mô-đun socketserver, một khung dành cho máy chủ mạng. Ngoài ra còn có nhiều mô-đun triển khai các giao thức Internet cấp cao hơn như HTTP và SMTP. Để biết tổng quan, hãy xem Hỗ trợ và Giao thức Internet ổ cắm TCPBạn sẽ tạo một đối tượng ổ cắm bằng cách sử dụng 7, chỉ định loại ổ cắm là 8. Khi bạn làm điều đó, giao thức mặc định được sử dụng là Giao thức điều khiển truyền tải (TCP). Đây là một mặc định tốt và có thể là những gì bạn muốnTại sao bạn nên sử dụng TCP?
Ngược lại, ổ cắm Giao thức gói dữ liệu người dùng (UDP) được tạo bằng 9 không đáng tin cậy và dữ liệu được đọc bởi người nhận có thể không theo thứ tự từ việc ghi của người gửiTại sao nó lại quan trọng? . Không có gì đảm bảo rằng dữ liệu của bạn sẽ đến đích hoặc bạn sẽ nhận được những gì đã được gửi cho bạn Các thiết bị mạng, chẳng hạn như bộ định tuyến và bộ chuyển mạch, có sẵn băng thông hữu hạn và đi kèm với các giới hạn hệ thống vốn có của riêng chúng. Chúng có CPU, bộ nhớ, bus và bộ đệm gói giao diện, giống như máy khách và máy chủ của bạn. TCP giúp bạn không phải lo lắng về việc mất gói, dữ liệu đến không theo thứ tự và các cạm bẫy khác luôn xảy ra khi bạn liên lạc qua mạng Để hiểu rõ hơn về điều này, hãy xem trình tự lệnh gọi API ổ cắm và luồng dữ liệu cho TCP Cột bên trái đại diện cho máy chủ. Ở phía bên tay phải là khách hàng Bắt đầu từ cột trên cùng bên trái, hãy lưu ý các lệnh gọi API mà máy chủ thực hiện để thiết lập ổ cắm “nghe”
Ổ cắm nghe thực hiện đúng như tên gọi của nó. Nó lắng nghe các kết nối từ khách hàng. Khi máy khách kết nối, máy chủ gọi 1 để chấp nhận hoặc hoàn tất kết nốiMáy khách gọi 2 để thiết lập kết nối với máy chủ và bắt đầu quá trình bắt tay ba bước. Bước bắt tay rất quan trọng vì nó đảm bảo rằng mỗi bên của kết nối đều có thể truy cập được trong mạng, hay nói cách khác là máy khách có thể truy cập máy chủ và ngược lại. Có thể chỉ một máy chủ, máy khách hoặc máy chủ có thể kết nối với nhauỞ giữa là phần khứ hồi, nơi dữ liệu được trao đổi giữa máy khách và máy chủ bằng cách gọi tới 4 và 5Ở phía dưới, máy khách và máy chủ đóng các ổ cắm tương ứng của chúng Loại bỏ các quảng cáoMáy khách và máy chủ EchoBây giờ bạn đã có cái nhìn tổng quan về API socket và cách máy khách và máy chủ giao tiếp với nhau, bạn đã sẵn sàng để tạo máy khách và máy chủ đầu tiên của mình. You’ll begin with a simple implementation. The server will simply echo whatever it receives back to the client Echo ServerHere’s the server 0Ghi chú. 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 Được rồi, vậy chính xác điều gì đang xảy ra trong lệnh gọi API? 7 tạo một đối tượng ổ cắm hỗ trợ loại trình quản lý bối cảnh, vì vậy bạn có thể sử dụng nó trong câu lệnh 29. Không cần gọi 30 4Các đối số được truyền cho 8 là các hằng số được sử dụng để chỉ định họ địa chỉ và loại ổ cắm. 32 là họ địa chỉ Internet cho IPv4. 33 là loại ổ cắm cho TCP, giao thức sẽ được sử dụng để vận chuyển thông điệp trong mạngPhương pháp 9 được sử dụng để liên kết ổ cắm với một giao diện mạng và số cổng cụ thể 9Các giá trị được chuyển đến 9 phụ thuộc vào họ địa chỉ của ổ cắm. Trong ví dụ này, bạn đang sử dụng 36 (IPv4). Vì vậy, nó mong đợi một hai tuple. 37 38 có thể là tên máy chủ, địa chỉ IP hoặc chuỗi rỗng. Nếu địa chỉ IP được sử dụng, thì 38 phải là chuỗi địa chỉ có định dạng IPv4. Địa chỉ IP 400 là địa chỉ IPv4 tiêu chuẩn cho giao diện loopback, vì vậy chỉ các quy trình trên máy chủ mới có thể kết nối với máy chủ. Nếu bạn chuyển một chuỗi trống, máy chủ sẽ chấp nhận các kết nối trên tất cả các giao diện IPv4 có sẵn 401 đại diện cho số cổng TCP để chấp nhận kết nối từ máy khách. Nó phải là một số nguyên từ 402 đến 403, vì 404 được đặt trước. Một số hệ thống có thể yêu cầu đặc quyền siêu người dùng nếu số cổng nhỏ hơn 405Đây là một lưu ý về việc sử dụng tên máy chủ với 9
Bạn sẽ tìm hiểu thêm về điều này sau, trong Sử dụng tên máy chủ. Hiện tại, bạn chỉ cần hiểu rằng khi sử dụng tên máy chủ, bạn có thể thấy các kết quả khác nhau tùy thuộc vào những gì được trả về từ quá trình phân giải tên. Những kết quả này có thể là bất cứ điều gì. Lần đầu tiên bạn chạy ứng dụng của mình, bạn có thể nhận được địa chỉ 407. Lần sau, bạn nhận được một địa chỉ khác, 408. Lần thứ ba, bạn có thể nhận được 409, v.v.Trong ví dụ máy chủ, 0 cho phép máy chủ chấp nhận kết nối. Nó làm cho máy chủ trở thành ổ cắm “nghe” 6Phương thức 0 có tham số 412. Nó chỉ định số lượng kết nối không được chấp nhận mà hệ thống sẽ cho phép trước khi từ chối kết nối mới. Bắt đầu bằng Python 3. 5, nó là tùy chọn. Nếu không được chỉ định, giá trị 412 mặc định sẽ được chọnNếu máy chủ của bạn nhận được nhiều yêu cầu kết nối đồng thời, việc tăng giá trị 412 có thể hữu ích bằng cách đặt độ dài tối đa của hàng đợi cho các kết nối đang chờ xử lý. Giá trị tối đa phụ thuộc vào hệ thống. Ví dụ: trên Linux, xem 415Phương thức 1 chặn thực thi và đợi kết nối đến. Khi một máy khách kết nối, nó trả về một đối tượng ổ cắm mới đại diện cho kết nối và một bộ chứa địa chỉ của máy khách. Bộ dữ liệu sẽ chứa 37 cho các kết nối IPv4 hoặc 418 cho IPv6. Xem Các họ địa chỉ ổ cắm trong phần tham khảo để biết chi tiết về các giá trị bộ dữ liệuMột điều bắt buộc phải hiểu là bây giờ bạn có một đối tượng ổ cắm mới từ 1. Điều này rất quan trọng vì nó là ổ cắm mà bạn sẽ sử dụng để giao tiếp với khách hàng. Nó khác với ổ cắm nghe mà máy chủ đang sử dụng để chấp nhận các kết nối mới 6Sau khi 1 cung cấp đối tượng ổ cắm máy khách 421, một vòng lặp vô hạn 422 được sử dụng để lặp lại các cuộc gọi chặn tới 423. Điều này đọc bất kỳ dữ liệu nào mà khách hàng gửi và lặp lại dữ liệu đó bằng cách sử dụng 424Nếu 423 trả về một đối tượng 426 trống, 427, báo hiệu rằng máy khách đã đóng kết nối và vòng lặp kết thúc. Câu lệnh 29 được sử dụng với 421 để tự động đóng socket ở cuối khốiLoại bỏ các quảng cáoMáy khách EchoBây giờ hãy nhìn vào khách hàng 7In comparison to the server, the client is pretty simple. Nó tạo một đối tượng ổ cắm, sử dụng 2 để kết nối với máy chủ và gọi 431 để gửi tin nhắn của nó. Cuối cùng, nó gọi 432 để đọc câu trả lời của máy chủ và sau đó in nóChạy máy khách và máy chủ EchoTrong phần này, bạn sẽ chạy máy khách và máy chủ để xem cách chúng hoạt động và kiểm tra điều gì đang xảy ra Ghi chú. Nếu bạn gặp khó khăn khi lấy các ví dụ hoặc mã của riêng mình để chạy từ dòng lệnh, hãy đọc Làm cách nào để tôi tạo các lệnh dòng lệnh của riêng mình bằng Python? . Nếu bạn đang sử dụng Windows, hãy xem Câu hỏi thường gặp về Windows về Python Mở một thiết bị đầu cuối hoặc dấu nhắc lệnh, điều hướng đến thư mục chứa tập lệnh của bạn, đảm bảo rằng bạn có Python 3. 6 trở lên được cài đặt và trên đường dẫn của bạn, sau đó chạy máy chủ
Thiết bị đầu cuối của bạn sẽ xuất hiện để treo. Đó là do máy chủ bị chặn hoặc bị treo vào ngày 1
Nó đang chờ kết nối máy khách. Bây giờ, hãy mở một cửa sổ đầu cuối khác hoặc dấu nhắc lệnh và chạy ứng dụng khách 2Trong cửa sổ máy chủ, bạn sẽ nhận thấy một cái gì đó như thế này 3Trong kết quả ở trên, máy chủ đã in bộ dữ liệu 434 được trả về từ 435. Đây là địa chỉ IP và số cổng TCP của máy khách. Số cổng, 436, rất có thể sẽ khác khi bạn chạy nó trên máy của mìnhXem trạng thái ổ cắmĐể 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 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ủ 40Lưu ý rằng 438 là 439. Nếu 440 đã sử dụng 441 thay vì 442, netstat sẽ hiển thị điều này 41 438 là 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, 36 đã được sử dụng (IPv4) trong lệnh gọi tới 8. Bạn có thể thấy điều này trong cột 447. 448The output above is trimmed to show the echo server only. 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 447, 438 và 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 ( 448), trên cổng 65432 trên tất cả các giao diện ( 444) và nó đang ở trạng thái lắng nghe ( 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 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ó 42 455 cung cấp cho bạn 457, 458 (ID quy trình) và 459 (ID người dùng) của ổ cắm Internet đang mở khi được sử dụng với tùy chọn 460. Trên đây là quá trình echo server 437 và 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 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 464 và 465. Đối với Windows, hãy sử dụng 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 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. Bạn cũng có thể thấy lỗi 467. Thêm quy tắc tường lửa cho phép máy khách kết nối với cổng TCPCó một danh sách các lỗi phổ biến trong phần tham khảo Loại bỏ các quảng cáosự cố truyền thôngBâ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 400 hoặc địa chỉ IPv6 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ủ. Điều này thể hiện bản chất bên trong của giao diện loopback và cho thấy rằng các kết nối và dữ liệu truyền qua nó là cục bộ của máy chủ. Đây là lý do tại sao bạn cũng sẽ nghe thấy giao diện loopback và địa chỉ IP 400 hoặc 469 được gọi là “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ộ Bạn có thể thấy điều này đang hoạt động nếu bạn có một máy chủ ứng dụng sử dụng cơ sở dữ liệu riêng của nó. If it’s not a database used by other servers, it’s probably configured to listen for connections on the loopback interface only. 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ông phải là 400 hoặc 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. Đây là cổng vào các máy chủ khác bên ngoài vương quốc “localhost” của bạnHãy cẩn thận ở ngoài đó. Đó là một thế giới khó chịu, tàn nhẫn. Hãy nhớ đọc phần Sử dụng tên máy chủ trước khi mạo hiểm thoát khỏi giới hạn an toàn của “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ốiMá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 432, có thể nó sẽ chỉ trả về một byte, 475 từ 476 44Đối số 477 của 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à 5 sẽ trả về 405 bytePhương thức 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 4 nhiều lần nếu cần để gửi tất cả dữ liệu
Trong ví dụ trên, bạn tránh phải làm điều này bằng cách sử dụng 483
Bạn có hai vấn đề tại thời điểm này
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ộ. 487 đã được đưa vào thư viện chuẩn trong 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. Tất cả những gì cần làm là để một trong số này tự hiển thị và ứng dụng của bạn có thể đột nhiên bị lỗi theo những cách không mấy tế nhị Đ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. If your application needs to scale, it’s a necessity if you want to use more than one processor or one core. 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. 488Phương pháp 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 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ì.
Tuy nhiên, bằng cách sử dụng 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. Nó phụ thuộc vào những gì ứng dụng của bạn cần thực hiện khi nó phục vụ một yêu cầu và số lượng máy khách mà nó cần hỗ trợ 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 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 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 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.Nếu bạn đang nhận được yêu cầu từ các máy khách bắt đầu công việc liên kết với CPU, hãy xem đồng thời. 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 488 để xử lý đồng thời nhiều kết nối và gọi 4 và 5 nhiều lần nếu cầnLoại bỏ các quảng cáoMáy khách và máy chủ đa kết nốiTrong 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 499 được tạo từ mô-đun bộ chọnMáy chủ đa kết nốiĐầ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 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 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 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 902 đăng ký ổ cắm sẽ được giám sát với 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. 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 905. Nó được trả lại khi 488 trả về. Bạn sẽ sử dụng 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 46Khối 908 cho đến khi có ổ cắm sẵn sàng cho 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 909 và một 910. 909 là SelectorKey 912 có chứa thuộc tính 913. 914 là đối tượng ổ cắm và 910 là mặt nạ sự kiện của các hoạt động đã sẵn sàngNếu 916 là 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 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 916 không phải là 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 đó, 921 được gọi với 909 và 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 918 của bạn 47Bởi vì ổ cắm nghe đã được đăng ký cho sự kiện 904, nó sẽ sẵn sàng để đọc. Bạn gọi 926 và sau đó gọi 927 để đặt ổ cắm ở chế độ không chặnHã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 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 48Sau đó, các đối tượng mặt nạ, ổ cắm và dữ liệu của 929 được chuyển đến 902Bây giờ hãy xem 921 để xem kết nối máy khách được xử lý như thế nào khi sẵn sàng 49Đây là trái tim của máy chủ đa kết nối đơn giản. 909 là 912 được trả về từ 488 có chứa đối tượng ổ cắm ( 913) và đối tượng dữ liệu. 910 chứa các sự kiện đã sẵn sàngNếu ổ cắm đã sẵn sàng để đọc, thì 937 sẽ đánh giá thành 938, do đó, 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 941 để kiểm tra nếu không nhận được dữ liệu 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 942 trước khi đóng cửa, để nó không còn bị giám sát bởi 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 940 sẽ được gửi lại cho máy khách bằng cách sử dụng 945. Các byte được gửi sau đó được xóa khỏi bộ đệm gửi 91Phương thức 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 947 để loại bỏ các byte đã gửiLoại bỏ các quảng cáoMáy khách đa kết nốiBây giờ hãy xem ứng dụng khách đa kết nối, 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 949 92 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 3 thay vì 2 vì 2 sẽ ngay lập tức đưa ra một ngoại lệ 954. Phương pháp 3 ban đầu trả về một chỉ báo lỗi, 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 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 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 959 vì mỗi kết nối sẽ gọi 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 905Kiểm tra các thay đổi được thực hiện từ 921 của máy chủ đối với phiên bản của máy khách 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ốiBây giờ là lúc để chạy 963 và 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ố 38 và 401 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ủ, 967 95Dưới đây là đầu ra của máy chủ khi nghe trên giao diện loopback trên cổng 65432 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 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 Loại bỏ các quảng cáoMáy khách và máy chủ ứng dụngVí 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ụ 968 trước đó trong lần triển khai cuối cùng. ứng dụng khách và máy chủBạ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à 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
Vì vậy, một điều bạn cần làm là bắt 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. Timeouts happen and are a so-called normal error. Hosts and routers are rebooted, switch ports go bad, cables go bad, cables get unplugged, you name it. 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ó 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 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 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ô đó This is why you need to define an application-layer protocol. 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. This is directly related to what you learned in the previous paragraph regarding reading bytes from the socket. When you’re reading bytes with 5, you need to keep up with how many bytes were read, and figure out where the message boundaries areLà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. Also, you’re still left with the problem of what to do about data that doesn’t fit into one message In this tutorial, you’ll learn a generic approach, one that’s used by many protocols, including 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 đề. Once you’ve read the header, you can process it to determine the length of the message’s content. 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, thì bạn 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 Bạn có thể tìm thấy lời giải thích trong tài liệu Mã hóa và Unicode của Python. 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 Bạn có thể dễ dàng xác định thứ tự byte của máy bằng cách sử dụng 977. Ví dụ, bạn có thể thấy một cái gì đó như thế này 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 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 Loại bỏ các quảng cáoTiêu đề giao thức ứng dụngBây giờ bạn sẽ xác định đầy đủ tiêu đề giao thức. Tiêu đề giao thức là
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ả 978 Thứ tự byte của máy (sử dụng 977). Điều này có thể không cần thiết cho ứng dụng của bạn. 980Độ dài của nội dung tính bằng byte. 981Loại nội dung trong tải trọng, ví dụ: 982 hoặc 983. 984Mã hóa mà nội dung sử dụng, ví dụ: 985 cho văn bản Unicode hoặc 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ụngVẫ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 5?Trước đây, khi bạn đã học về cách sử dụng 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 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à 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 5 và đọc 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ụngCuối cùng, phần thưởng. Trong phần này, bạn sẽ nghiên cứu lớp 993 và xem nó được sử dụng như thế nào với 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 993 làm điểm bắt đầu và sửa đổi nó để sử dụng cho riêng mìnhỨng dụng này không xa lắm so với ví dụ máy khách và máy chủ 968. Mã vòng lặp sự kiện giữ nguyên trong 997 và 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à 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, như 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 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 / Message Content1ClientSends a 993 chứa nội dung yêu cầu2ServerNhận và xử lý yêu cầu của client 9933ServerSends 993 chứa nội dung phản hồi4ClientNhận và xử lý phản hồi của máy chủ 993Đây là bố cục tệp và mã ApplicationFileCodeServer 998Kịch bản chính của máy chủServer 607Lớp 993 của máy chủClient 997Kịch bản chính của máy kháchClient 610Lớp 993 của khách hàngĐiểm nhập tin nhắnHiểu cách hoạt động của lớp 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 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 614 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 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 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 905 trên đối tượng 909 và gọi một phương thức trong 993 61Looking at the event loop above, you’ll see that 901 is in the driver’s seat. 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 621. Đó là lý do tại sao 621 là điểm vàoĐây là những gì phương thức 621 làm 62Tốt đấy. 621 thật đơn giản. Nó chỉ có thể làm hai việc. gọi 625 và 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ừ 625 và 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 625 hoặc 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 625 và 626 Bây giờ hãy nhìn vào 625. Đây là phiên bản của máy chủ, nhưng của khách hàng là như nhau. It just uses a different method name, 634 instead of 635 63Phương thức 636 được gọi đầu tiên. Nó gọi 637 để đọc dữ liệu từ ổ cắm và lưu trữ trong bộ đệm nhậnHãy nhớ rằng khi 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. 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. Nếu có, nó sẽ xử lý các byte tương ứng của nó, loại bỏ chúng khỏi bộ đệm và ghi đầu ra của nó vào một biến được sử dụng trong giai đoạn xử lý tiếp theo. Because there are three components to a message, there are three state checks and 640 method callsMessage ComponentMethodOutputTiêu đề có độ dài cố định 641 642JSON header 643 644Content 645 646Tiếp theo, hãy xem 626. Đây là phiên bản của máy chủ 64Phương pháp 626 trước tiên kiểm tra một 649. Nếu một cái tồn tại và một phản hồi chưa được tạo, thì 650 được gọi là. Phương thức 650 đặt biến trạng thái 652 và ghi phản hồi vào bộ đệm gửiPhương thức 653 gọi 960 nếu có dữ liệu trong bộ đệm gửiHãy nhớ rằng khi 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 960. Đây là lý do tại sao có kiểm tra nhà nước. Phương thức 650 chỉ nên được gọi một lần, nhưng dự kiến rằng 653 sẽ cần được gọi nhiều lầnPhiên bản máy khách của 626 cũng tương tự 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 660 được chọn. Nếu một yêu cầu chưa được xếp hàng đợi, nó sẽ gọi 661. Phương thức 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 660 để nó chỉ được gọi một lầnCũng giống như đối với máy chủ, 653 gọi 960 nếu có dữ liệu trong bộ đệm gửiSự khác biệt đáng chú ý trong phiên bản 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. This will be explained more in the section Client Main Script, but the reason for this is to tell 616 to stop monitoring the socket for write events. 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. There’s no reason to be notified that the socket is writableĐể 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 616 đang gọi vào lớp 993 thông qua phương thức 621 và để mô tả cách quản lý trạng tháiĐiều này rất quan trọng vì 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ủIn the server’s main script 998, arguments are read from the command line that specify the interface and port to listen on 66Ví dụ: để nghe trên giao diện loopback trên cổng 673, hãy nhập 67Sử dụng một chuỗi trống cho 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 675 với tùy chọn 676 68Đặt tùy chọn ổ cắm này sẽ tránh được lỗi 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_WAITFor example, if the server actively closed a connection, it’ll remain in the 678 state for two minutes or more, depending on the operating system. Nếu bạn cố gắng khởi động lại máy chủ trước khi trạng thái 678 hết hạn, thì bạn sẽ nhận được một ngoại lệ 970 của 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 69When a client connection is accepted, a 993 object is created 60Đối tượng 993 được liên kết với ổ cắm trong lệnh gọi tới 902 và ban đầu được đặt để chỉ giám sát các sự kiện đọc. Once the request has been read, you’ll modify it to listen for write events onlyMộ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 902 cũng theo dõi 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 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 993 được gọi vào hoạt động khi các sự kiện ổ cắm đã sẵn sàng thông qua 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ýLớp thông báo của máy chủ nằm trong 607, đâ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ướiNhận mã nguồn. Nhấp vào đây để lấy mã nguồn mà bạn sẽ sử dụng cho các ví dụ trong hướng dẫn này 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ý 61The fixed-length header is a 2-byte integer in network, or big-endian, byte order. It contains the length of the JSON header. You’ll use struct. unpack() để đọc giá trị, giải mã và lưu trữ trong 642. Sau khi xử lý đoạn tin nhắn mà nó chịu trách nhiệm, 692 xóa nó khỏi bộ đệm nhậnJust like with the fixed-length header, when there’s enough data in the receive buffer to contain the JSON header, it can be processed as well 62Phương thức 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 985 được mã hóa cứng trong cuộc gọi. Kết quả được lưu vào 644. Sau khi xử lý đoạn tin nhắn mà nó chịu trách nhiệm, 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 644. Khi 980 byte có sẵn trong bộ đệm nhận, yêu cầu có thể được xử lý 63Sau khi lưu nội dung tin nhắn vào biến 905, 635 xóa nó khỏi bộ đệm nhận. Then, if the content type is JSON, 635 decodes and deserializes it. If it’s not, this example application assumes that it’s a binary request and simply prints the content typeĐiều cuối cùng mà 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ủ, 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, 650 được gọi từ 626 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 606. For your own applications, you can define other methods that get called hereSau khi tạo thông báo phản hồi, biến trạng thái 607 được đặt để 626 không gọi lại 650. Finally, the response is appended to the send buffer. This is seen by and sent via 653One tricky bit to figure out is how to close the connection after the response is written. You can put the call to 6 in the method 653 65Although it’s somewhat hidden, this is an acceptable trade-off given that the 993 class only handles one message per connection. After the response is written, there’s nothing left for the server to do. It’s completed its workClient Main ScriptIn the client’s main script, 997, arguments are read from the command line and used to create requests and start connections to the server 66Here’s an example 67After creating a dictionary representing the request from the command-line arguments, the host, port, and request dictionary are passed to 615 68A socket is created for the server connection, as well as a 993 object using the 649 dictionaryLike for the server, the 993 object is associated with the socket in the call to 902. However, for the client, the socket is initially set to be monitored for both read and write events. Once the request has been written, you’ll modify it to listen for read events onlyThis approach gives you the same advantage as the server. not wasting CPU cycles. After the request has been sent, you’re no longer interested in write events, so there’s no reason to wake up and process them Client Message ClassTrong phần Điểm nhập thông báo, bạn đã học cách gọi đối tượng thông báo khi các sự kiện ổ cắm đã sẵn sàng thông qua 621. Now you’ll learn what happens after data is read and written on the socket and a message is ready to be processed by the clientThe client’s message class is in 610, which is part of the source code you downloaded earlier. You can also download the code by clicking the link belowNhận mã nguồn. Nhấp vào đây để lấy mã nguồn mà bạn sẽ sử dụng cho các ví dụ trong hướng dẫn này Các phương thức xuất hiện trong lớp theo thứ tự xử lý thông báo The first task for the client is to queue the request 69The dictionaries used to create the request, depending on what was passed on the command line, are in the client’s main script, 997. The request dictionary is passed as an argument to the class when a 993 object is createdThe request message is created and appended to the send buffer, which is then seen by and sent via 653. The state variable 625 is set so that 661 isn’t called againAfter the request has been sent, the client waits for a response from the server The methods for reading and processing a message in the client are the same as for the server. As response data is read from the socket, the 640 header methods are called. 692 and 629The difference is in the naming of the final 640 methods and the fact that they’re processing a response, not creating one. 634, 632, and 633Last, but certainly not least, is the final call for 634 70Message Class WrapupTo conclude your learning about the 993 class, it’s worth mentioning a couple of things that are important to notice with a few of the supporting methodsAny exceptions raised by the class are caught by the main script in the 636 clause inside the event loop 71Note the line. 637This is a really important line, for more than one reason. Not only does it make sure that the socket is closed, but 637 also removes the socket from being monitored by 488. This greatly simplifies the code in the class and reduces complexity. If there’s an exception or you explicitly raise one yourself, you know 6 will take care of the cleanupThe methods 641 and 642 also contain something interesting 72Note the 643 lineThe 653 method has one too. These lines are important because they catch a temporary error and skip over it using 645. The temporary error is when the socket would block, for example if it’s waiting on the network or the other end of the connection, also known as its peerBy catching and skipping over the exception with 645, 488 will eventually trigger a new call, and you’ll get another chance to read or write the dataLoại bỏ các quảng cáoRunning the Application Client and ServerAfter all of this hard work, it’s time to have some fun and run some searches In these examples, you’ll run the server so that it listens on all interfaces by passing an empty string for the 38 argument. This will allow you to run the client and connect from a virtual machine that’s on another network. It emulates a big-endian PowerPC machineFirst, start the server 73Now run the client and enter a search. See if you can find him 74You might notice that the terminal is running a shell that’s using a text encoding of Unicode (UTF-8), so the output above prints nicely with emojis Now see if you can find the puppies 75Notice the byte string sent over the network for the request in the 649 line. It’s easier to see if you look for the bytes printed in hex that represent the puppy emoji. 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 76Nhìn vào dòng 649 để xem các byte đã được ghi vào ổ cắm của máy khách. Đâ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ố 652 là bất kỳ thứ gì khác ngoài 653 77Because the request’s 981 is not 982, the server treats it as a custom binary type and doesn’t perform JSON decoding. Nó chỉ cần in 981 và trả về 10 byte đầu tiên cho máy khách 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. Also, read through the Reference section below for ideas. 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. The source code might be correct, and it’s just the other host, the client, or server. Or it could be the network. 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 For these types of issues, additional tools are essential. 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 Loại bỏ các quảng cáoping 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 79Lưu ý số liệu thống kê ở cuối đầu ra. This can be helpful when you’re trying to discover intermittent connectivity problems. For example, is there any packet loss? How much latency is there? You can check the round-trip times If there’s a firewall between you and the other host, a ping’s echo request may not be allowed. Some firewall administrators implement policies that enforce this. The idea is that they don’t want their hosts to be discoverable. 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 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. If you’re experiencing strange behavior or slow connections, this could be the reasonThô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ố ICMP TypeICMP CodeDescription80Echo request00Echo reply30Destination network unreachable31Destination host unreachable32Destination protocol unreachable33Destination port unreachable34Fragmentation required, and DF flag set110TTL expired in transit See the article Path MTU Discovery for information regarding fragmentation and ICMP messages. This is an example of something that can cause strange behavior netstatIn the section Viewing Socket State, you learned how 437 can be used to display information about sockets and their current state. This utility is available on macOS, Linux, and WindowsThat section didn’t mention the columns 660 and 661 in the example output. These columns will show you the number of bytes that are held in network buffers that are queued for transmission or receipt, but for some reason haven’t been read or written by the remote or local applicationIn other words, the bytes are waiting in network buffers in the operating system’s queues. One reason could be that the application is CPU bound or is otherwise unable to call 637 or 960 and process the bytes. Or there could be network issues affecting communications, like congestion or failing network hardware or cablingTo demonstrate this and see how much data you can send before seeing an error, you can try out a test client that connects to a test server and repeatedly calls 960. The test server never calls 637. It just accepts the connection. This causes the network buffers on the server to fill, which eventually raises an error on the clientFirst, start the server 0Then run the client to see what the error is 1Here’s 437 output from while the client and server are still running, with the client printing out the error message above multiple times 2The first entry is the server ( 438 has port 65432) 3Lưu ý 660. 669The second entry is the client ( 670 has port 65432) 4Notice the 661. 672The client sure was trying to write bytes, but the server wasn’t reading them. This caused the server’s network buffer queue to fill on the receive side and the client’s network buffer queue to fill on the send side WindowsIf you work with Windows, there’s a suite of utilities that you should definitely check out if you haven’t already. Windows Sysinternals One of them is 673. TCPView is a graphical 437 for Windows. In addition to addresses, port numbers, and socket state, it’ll show you running totals for the number of packets and bytes sent and received. Like with the Unix utility 455, you also get the process name and ID. Check the menus for other display optionsWiresharkSometimes you need to see what’s happening on the wire. Forget about what the application log says or what the value is that’s being returned from a library call. You want to see what’s actually being sent or received on the network. Just like with debuggers, when you need to see it, there’s no substitute Wireshark is a network protocol analyzer and traffic capture application that runs on macOS, Linux, and Windows, among others. There’s a GUI version named 676 and also a terminal, text-based version named 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. You’ll also be able to see when a client or server closes or aborts a connection or stops responding. 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 677 5Next up, you’ll get more references to support your socket programming journey ReferenceYou can use this section as a general reference with additional information and links to external resources Python Documentation
ErrorsThe following is from Python’s 679 module documentation
Here are some common errors you’ll probably encounter when working with sockets Exception 681 ConstantDescriptionBlockingIOErrorEWOULDBLOCKResource temporarily unavailable. For example, in non-blocking mode, when calling 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 683. 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 36 and 686 represent the address and protocol families used for the first argument to 7. APIs that use an address expect it to be in a certain format, depending on whether the socket was created with 36 or 686Address FamilyProtocolAddress TupleDescription 36IPv4 37 38 is a string with a hostname like 693 or an IPv4 address like 694. 401 is an integer. 686IPv6 418 38 is a string with a hostname like 693 or an IPv6 address like 700. 401 là một số nguyên. 702 and 703 represent the 704 and 705 members in the C struct 706Note the excerpt below from Python’s socket module documentation regarding the 38 value of the address tuple
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 38 and 401 arguments into a sequence of five-tuples that contains all of the necessary arguments for creating a socket connected to that service. 713 will understand and interpret passed-in IPv6 addresses and hostnames that resolve to IPv6 addresses, in addition to IPv4The following example returns address information for a TCP connection to 714 on port 715>>> 6Results may differ on your system if IPv6 isn’t enabled. The values returned above can be used by passing them to 7 and 717. There’s a client and server example in the Example section of Python’s socket module documentationUsing HostnamesFor context, this section applies mostly to using hostnames with 9 and 2, or 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 679 module documentation
The standard convention for the name “localhost” is for it to resolve to 400 or 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 724, the Name Service Switch configuration file. Another place to check on macOS and Linux is the file 725. On Windows, see 726. The 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
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 400 or 469. Serverethernet interfaceUse an IP address, such as 407. Để hỗ trợ nhiều giao diện, hãy sử dụng một chuỗi trống cho tất cả các giao diện/địa chỉ. See the security note above. Clientloopback interfaceUse an IP address, such as 400 or 469. Clientethernet interfaceUse an IP address for consistency and non-reliance on name resolution. For the typical case, use a hostname. See the security note aboveFor clients or servers, if you need to authenticate the host that you’re connecting to, look into using TLS Blocking CallsA socket function or method that temporarily suspends your application is a blocking call. For example, 1, 2, 4, and 5 block, meaning they don’t return immediately. Blocking calls have to wait on system calls (I/O) to complete before they can return a value. So you, the caller, are blocked until they’re done or a timeout or other error occursBlocking socket calls can be set to non-blocking mode so they return immediately. If you do this, then you’ll need to at least refactor or redesign your application to handle the socket operation when it’s ready Because the call returns immediately, data may not be ready. The callee is waiting on the network and hasn’t had time to complete its work. If this is the case, then the current status is the 681 value 738. Non-blocking mode is supported with . setblocking()By default, sockets are always created in blocking mode. See Notes on socket timeouts for a description of the three modes Closing ConnectionsAn 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. This is referred to as a “half-open” connection. It’s the application’s decision whether or not this is desirable. 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 This approach isn’t necessarily recommended, but as an example, HTTP uses a header named “Connection” that’s used to standardize how applications should close or persist open connections. 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 EndiannessSee 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
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 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. 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. 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. 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 7ConclusionYou 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
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 Nhận mã nguồn. Nhấp vào đây để lấy mã nguồn mà bạn sẽ sử dụng cho các ví dụ trong hướng dẫn này 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 Send Me Python Tricks » 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 Join us and get access to thousands of tutorials, hands-on video courses, and a community of expert Pythonistas Level Up Your Python Skills » Bạn nghĩ sao? Rate this article Tweet Share Share 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 Commenting Tips. The most useful comments are those written with the goal of learning from or helping out other students. Get tips for asking good questions and get answers to common questions in our support portal What is a nonWhen you make a socket non-blocking by calling setblocking(0) , it will never wait for the operation to complete . So when you call the send() method, it will put as much data in the buffer as possible and return. As this is read by the remote connection, the data is removed from the buffer.
How would I put my socket in nonNon-Blocking socket primer . socket() Create a socket bind() Register the socket listen() Indicate willingness to accept connections accept() Accept a connection request Read request Write response Return to step 4 Is socket send blocking python?In Python, a socket can be placed in the blocking or non-blocking mode . Ở chế độ không chặn, nếu bất kỳ lệnh gọi API nào, chẳng hạn như send() hoặc recv() gặp bất kỳ sự cố nào, lỗi sẽ được đưa ra. However, in the blocking mode, this will not stop the operation.
Is socket IO nonThe callback function is invoked everytime the on() is invoked. NodeJS runs asynchronously and is non-blocking I/O . |