cuốn sách gpt4 ai đã làm

[workerman] uniapp+thinkPHP5 sử dụng GatewayWorker để đạt được khả năng giao tiếp theo thời gian thực

In lại Tác giả: Sahara Thời gian cập nhật: 2024-07-05 19:03:37 58 4
mua khóa gpt4 Nike

Lời nói đầu

Trước đây công ty cần một phần mềm liên lạc nội bộ và nhờ tôi làm. Phần mềm giao tiếp không thể tách rời khỏi giao tiếp, và rồi tôi nghĩ đến những kết nối dài. Ở đây tôi sử dụng khung GatewayWorker.

Khung GatewayWorker là gì?

GatewayWorker là một tập hợp khung ứng dụng kết nối dài TCP được phát triển dựa trên Workerman. Nó triển khai các giao diện như truyền đơn, truyền nhóm và phát sóng. Nó có thư viện lớp mysql tích hợp được chia thành quy trình Gateway và quy trình Worker. Nó hỗ trợ triển khai phân tán và có thể hỗ trợ một số lượng lớn số lượng kết nối.

Cách hoạt động của GatewayWorker

hình ảnh

1. Bắt đầu tất cả các quy trình (GatewayWorker, business, register) 2. Sau khi GatewayWorker và các quy trình nghiệp vụ được khởi động, chúng yêu cầu đăng ký từ thanh ghi 3. Sau khi dịch vụ đăng ký nhận được yêu cầu đăng ký, nó sẽ lưu tất cả các địa chỉ liên lạc của Gateway trong bộ nhớ và đồng thời lưu tất cả các địa chỉ liên lạc trong bộ nhớ. Địa chỉ liên lạc của Gateway được gửi đến doanh nghiệp 4. Quá trình nghiệp vụ lấy tất cả các địa chỉ liên lạc nội bộ của Gateway và kết nối với GatewayWorker. 5. Nếu dịch vụ GatewayWorker mới được đăng ký, danh sách địa chỉ liên lạc nội bộ của Gateway mới sẽ được phát tới tất cả các doanh nghiệp và kết nối sẽ được thiết lập. 6. Nếu GatewayWorker ngoại tuyến, dịch vụ Đăng ký sẽ nhận được thông báo và địa chỉ liên lạc nội bộ. của GatewayWorker sẽ là Địa chỉ bị xóa, sau đó danh sách địa chỉ liên lạc nội bộ mới sẽ được quảng bá tới tất cả các doanh nghiệp 7. Tại thời điểm này, GatewayWorker và doanh nghiệp đã thiết lập kết nối dài 8. Tất cả các sự kiện của khách hàng và dữ liệu nhận được sẽ được GatewayWorker chuyển tiếp đến doanh nghiệp để xử lý.

Cấu trúc thư mục

├── Ứng dụng // Thư mục ứng dụng dự án │ └── YourAppGateway // Tạo thư mục để lưu trữ thợ, với bất kỳ tên nào │ ├── Events.php // Xử lý các tệp nghiệp vụ logic chính, quản lý onConnect onMessage onClose và các phương thức khác │ ├─ ─ start_gateway.php // tập lệnh khởi động quy trình cổng, định cấu hình địa chỉ đăng ký dịch vụ, số cổng, số lượng quy trình và các tham số khác │ ├── start_businessworker.php // Tập lệnh khởi động cho tiến trình người dùng │ └── start_register.php // Tập lệnh khởi động cho dịch vụ đăng ký │ ├── start.php // Tập lệnh khởi động toàn cầu, tập lệnh này sẽ tải Ứng dụng/YourAppGateway/start*.php trong trình tự Bắt đầu tất cả các tập lệnh │ └── nhà cung cấp // thư mục mã nguồn khung GatewayWorker và khung Workerman

Triển khai GatewayWorker

Lấy ngôi chùa làm ví dụ.

1.Cài đặt trình soạn thảo

Đăng nhập vào thiết bị đầu cuối SSH và sử dụng lệnh sau để tải xuống tập lệnh cài đặt Composer:

php -r "copy('https://getcomposer.org/installer', 'composer-setup.php');"

Chạy lệnh sau để cài đặt Composer:

php Composer-setup.php --install-dir=/usr/local/bin --filename=composer

Kiểm tra phiên bản soạn nhạc.

nhà soạn nhạc -v // Kiểm tra phiên bản của nhà soạn nhạc

2. Cài đặt công nhân

Mở thiết bị đầu cuối chùa trong thư mục gốc của dự án và nhập lệnh sau để cài đặt Workman.

nhà soạn nhạc yêu cầu topthink/think-worker

3.Cài đặt GatewayWorker

Mở thiết bị đầu cuối chùa trong thư mục gốc của dự án và nhập lệnh sau để cài đặt GatewayWorker.

nhà soạn nhạc yêu cầu công nhân/công nhân cổng

4. Triển khai mã

Bạn có thể chọn liên kết demo chính thức: http://www.workerman.net/download/GatewayWorker.zip.

Hoặc sử dụng những gì tôi đã điều chỉnh từ bản demo.

Trước tiên, hãy tạo một tệp mới trong thư mục ứng dụng dự án (thường là Ứng dụng) để lưu trữ bốn tệp quy trình sau.

start_gateway.php .

name = 'YourAppGateway'; // số lượng quy trình cổng $gateway->count = 200; / ip máy cục bộ, sử dụng ip mạng nội bộ để triển khai phân tán $gateway->lanIp = '127.0.0.1'; Cổng bắt đầu giao tiếp nội bộ, nếu $gateway->count=4, cổng bắt đầu là 4000 // Sau đó, 4 cổng 4000 4001 4002 4003 thường được sử dụng làm cổng giao tiếp nội bộ $gateway->startPort = 2900; // Địa chỉ đăng ký dịch vụ , port $gateway->registerAddress = '127.0.0.1:1237'; Khoảng nhịp tim //$gateway->pingInterval = 10; //Dữ liệu nhịp tim //$gateway->pingData = '{"type://ping"}' /* //Khi máy khách kết nối, hãy đặt kết nối trênWebSocketConnect, đó là cuộc gọi lại trong quá trình bắt tay websocket $gateway->onConnect = function($connection) { $connection->onWebSocketConnect = function($connection, $http_header) { // Bạn có thể xác định xem nguồn kết nối có hợp pháp hay không tại đây. Nếu không hợp pháp, hãy đóng kết nối // $_SERVER['HTTP_ORIGIN'] xác định liên kết websocket được khởi tạo bởi trang từ trang web nào nếu ($_SERVER['HTTP_ORIGIN'] ! = 'http:// kedou.workerman.net') { $connection->close(); } // $_GET $_SERVER có sẵn trong onWebSocketConnect // var_dump($_GET, $_SERVER); }; }; */ // Nếu nó không được khởi động trong thư mục gốc, hãy chạy phương thức runAll if(!d xác định('GLOBAL_START')) { Worker::runAll();

start_businessworker.php .

name = 'YourAppBusinessWorker'; // Số lượng xử lý bussinessWorker $worker->count = 200; // Địa chỉ đăng ký dịch vụ, cổng $worker->registerAddress = '127.0.0.1:1237'; // Nếu nó không được khởi động trong thư mục gốc , chạy Phương thức runAll if(!d xác định('GLOBAL_START')) { Worker::runAll() }

start_register.php .


Sự kiện.php.
$client_id, 'message'=>'Welcome'.$client_id.'Đăng nhập! ', 'data'=>[] ]; Gateway::sendToAll(json_encode($data)); // Gateway::sendToAll("$client_id login\r\n"); } /** * Khi khách hàng gửi Được kích hoạt khi có tin nhắn đến* @param int $client_id id kết nối * @param đã trộn $message cụ thể tin nhắn*/ public static function onMessage($client_id, $message){ $data=[ 'client_id'=>$client_id, 'message'=>$client_id.' nói: '.$result['message'], 'data'=>$message ]; // Gửi cho mọi người // Gateway::sendToAll("$client_id đã nói $message\r\n"); } /** * Được kích hoạt khi người dùng ngắt kết nối * @param int $client_id id kết nối */ public static function onClose($client_id) { //Gửi cho mọi người // GateWay::sendToAll("$client_id exited!\r\n" );
Sau đó tạo một tệp khởi động mới trong thư mục gốc của dự án.
start_all_workman.php .

Lưu ý sau khi mở port nhớ nhả port nhé! ! ! Ngoài việc phát hành chùa, máy chủ của bạn (Alibaba Cloud/Tencent Cloud, v.v.) cũng nhớ phát hành nó! ! ! .
Bắt đầu công nhân
Mở terminal trong thư mục gốc của dự án và nhập php start_all_workman.php start -d để bắt đầu quá trình daemon. Nếu trang sau xuất hiện, nó sẽ được khởi động thành công.
Nếu bạn muốn tắt tiến trình Workman, hãy nhập php start_all_workman.php stop để tắt.
GatewayWorker sử dụng
Nếu trang web của bạn sử dụng giao thức Https thì WebSocket phải sử dụng giao thức wss. Tuy nhiên, giao thức wss không hỗ trợ định dạng IP:port. Thay vào đó, nó chỉ có thể ghi tên miền + url. Giao thức https và WebSocket không thể kết nối, bạn có thể sử dụng Nginx thực hiện proxy ngược và thêm đoạn mã sau vào máy chủ trong tệp cấu hình trang web.
location /connectWorkman (tên tùy thuộc vào bạn, không sử dụng cùng tên với các proxy ngược khác) { proxy_pass http://127.0.0.1:8283; proxy_http_version 1.1; nâng cấp proxy_set_header Kết nối proxy_set_header; X-Real- IP $remote_addr }
Sử dụng giao diện người dùng (uniapp)
init() { SocketTask = uni.connectSocket({ url: 'wss://chat.gdpaimaihui.com/auction', //Tiêu đề chính thức: { 'content-type': 'application/json' }, thành công: function( res) { console.log('Đã tạo kết nối WebSocket', res); }, failed: function(err) { uni.showToast({ title: 'Ngoại lệ mạng! ', biểu tượng: 'none' }); console.log(err); } }); //sự kiện nghe websocket SocketTask.onOpen((res) => { socketOpen = true canReconnect = true console.log( 'Nghe sự kiện mở kết nối WebSocket. ', res); //Sau khi websocket được kết nối, bạn có thể bắt đầu hẹn giờ và thỉnh thoảng thực hiện đo nhịp tim để ngăn nhịp tim dừng lại và ngắt kết nối này.timer = setInterval(() => { SocketTask.send({ data: 'Heartbeat', Success() { // console.log('Gửi nhịp tim thành công'); } }) }, 2000) }); ( onError) => { console.log('Đang nghe lỗi WebSocket. Thông báo lỗi', onError socketOpen = false if (canReconnect) { this.reconnect() canReconnect); = false } }); SocketTask.onMessage((res) => { console.log('Lắng nghe sự kiện tin nhắn mà WebSocket nhận được từ máy chủ. Tin nhắn được máy chủ trả về', res); } }), / /Kết nối lại kết nối lại( ) { if (!socketOpen) { let count = 0; kết nối lạiInterval = setInterval(() => { console.log("Đang cố gắng kết nối lại") uni.showToast({ title: 'Đang cố gắng kết nối lại', biểu tượng: 'none' }) this.init(); count++ console.log(); // Không còn kết nối lại sau một số lần nhất định if (count >= connectTimes) { clearInterval(reconnectInterval ) uni .showToast({ title: 'Ngoại lệ mạng hoặc lỗi máy chủ', biểu tượng: 'none' }) } }, kết nối lạiDelay) } }
Trên đây là nội dung mình biên soạn khi đang làm phần mềm truyền thông nội bộ cho công ty. Nếu có sai sót xin chỉ giáo. Nếu thấy hay thì hãy nhấn vào để giới thiệu và theo dõi nhé! Cảm ơn bạn~๑·́₃·̀๑ [花][花][花].
Cuối cùng, bài viết này về [workerman] uniapp+thinkPHP5 sử dụng GatewayWorker để đạt được giao tiếp thời gian thực kết thúc tại đây. Nếu bạn muốn biết thêm về [workerman]uniapp+thinkPHP5 sử dụng GatewayWorker để đạt được giao tiếp thời gian thực, vui lòng tìm kiếm bài viết CFSDN. tiếp tục Duyệt các bài viết liên quan, tôi hy vọng bạn sẽ ủng hộ blog của tôi trong tương lai! .
Sử dụng docker để xây dựng giải pháp đồng bộ hóa nhật ký phân tán ELK
bản tin - tin tức/bản tin về lập trình và phát triển phần mềm
Đã đóng. Câu hỏi này không đáp ứng các nguyên tắc của Stack Overflow. Nó hiện không chấp nhận câu trả lời. Bạn muốn cải thiện vấn đề này? Cập nhật câu hỏi để nó được đưa lên đầu trang
https - Giao tiếp https của Neo4j
Có cách nào để chỉ cho phép https chứ không phải http giao tiếp với máy chủ Neo4j không? Ngoài ra, Neo4j Shell sử dụng kênh nào để liên lạc, http hoặc https? Câu trả lời hay nhất đến từ Neo4j
Giao tiếp PHP MYSQL với địa chỉ từ hai bảng
Xin chào, tôi có câu hỏi mới :) Tôi đang xây dựng một bản tin đơn giản có bảng điều khiển để gửi email đến những người dùng đã đăng ký và một địa chỉ email nhận bản tin. Tôi có mã này nhưng bản tin chỉ được gửi cho người dùng đã đăng ký. Có ai có thể cho tôi biết tại sao không? $zapytanie = của tôi
Giao tiếp RS232 C. Làm thế nào để so sánh thời gian CPU?
Lần đầu đăng bài nên có thể có nhiều thông tin hơn mức cần thiết, nhưng tôi muốn nói kỹ: Một trong những bài tập C của chúng ta là tạo chương trình phát và thu để trao đổi dữ liệu với modem null thông qua giao tiếp nối tiếp RS232. Chúng tôi đã sử dụng chương trình cổng ảo (nếu bạn muốn kiểm tra, tôi đã sử dụng
php - JS <---> Giao tiếp PHP
c++ - Giao tiếp qua RS485
Tôi có một máy tính bo mạch đơn được kết nối với một thiết bị khác qua RS485. Máy tính sẽ gửi yêu cầu đến thiết bị và nhận phản hồi (sử dụng các giao thức dành riêng cho thiết bị). Tôi có thể gửi tin nhắn mà không gặp vấn đề gì và thiết bị nhận được chúng (ví dụ: tôi có thể thay đổi các thông số của thiết bị)
c# - Thành phần ActiveX không thể tạo đối tượng? Giao tiếp .NET
Tôi hiện đang cố gắng tham khảo thư viện .NET COM trong ứng dụng Visual Basic 6 của mình. Tôi đã đăng ký nó bằng Regasm và đặt ComVisible thành true trong lớp của tôi. Nhưng
.net - Giao tiếp iOS <-> USB của PC
Đã đóng. Câu hỏi này cần được tập trung hơn. Hiện tại nó không chấp nhận câu trả lời. Bạn muốn cải thiện vấn đề này? Cập nhật câu hỏi để nó chỉ tập trung vào một câu hỏi bằng cách chỉnh sửa bài đăng này
ssl - Giao tiếp Archiva Jenkins qua https
Tôi đang cố gắng thiết lập liên lạc giữa Archiva và Jenkins qua giao thức https nhưng tôi gặp phải lỗi sau: [CẢNH BÁO] Không thể truyền siêu dữ liệu .
java - Máy khách/máy chủ giao tiếp socket đa luồng
Tôi đã hoàn thành chương trình giao tiếp socket máy khách/máy chủ hoạt động tốt. Bây giờ tôi muốn tìm ra cách thực hiện điều này để có thể có nhiều kết nối máy khách đến máy chủ cùng một lúc. Tôi đã xem xét xung quanh và dường như có nhiều cách khác nhau để thực hiện việc này. Vì thế tôi ở đây để nói với bạn
html - Làm cách nào để ngăn Outlook phá vỡ kích thước div? (giao tiếp)
Tôi đang tạo một bản tin trong mailchimp và tôi gặp phải sự cố này khi sử dụng Outlook, nó liên tục can thiệp vào hai cột của tôi như minh họa: Đây là một phần mã:
android - Ghi đè kích thước phông chữ tối thiểu của ứng dụng Gmail cho Android (Giao tiếp)
Tôi đang tạo một bản tin và sau rất nhiều nỗ lực, nó hoạt động ở mọi nơi ngoại trừ ứng dụng gmail dành cho Android. Vấn đề là nó dường như có kích thước phông chữ tối thiểu, khiến bảng của tôi bị hỏng. Có cách nào để khắc phục kích thước phông chữ tối thiểu mà không cần truy vấn phương tiện không
Trình mô phỏng Android (JAVA) và chia sẻ giao tiếp socket C++
C++ với tư cách là Máy khách xem bản rõ sang bản in clipboard? Mã sao chép như sau: // Client.cpp: Xác định mục nhập poi
Sitecore ECM Communications: liên kết đến trang web không hoạt động từ hộp thư đến
Tôi đã tạo một Bản tin ECM chứa một số liên kết trang web (một dự án khác). Trong phiên bản trực tuyến của NewsLetter, liên kết hoạt động tốt nhưng khi tôi gửi NewsLetter này đến email của mình và cố gắng nhấp vào thư của tôi
iphone - Giao tiếp HTML/CSS, truy vấn @media không thay đổi kích thước văn bản trên iPhone
Vì bất kỳ lý do gì, việc thay đổi kích thước văn bản của tôi không hoạt động bình thường trên iPhone nhưng hoạt động tốt trên Android và các định dạng email khác. Dường như không thể thấy bất kỳ sự khác biệt nào giữa hai tập tin. Hình ảnh cũng thay đổi kích thước, có vẻ như đó chỉ là vấn đề với văn bản.
asp.net - Bản tin HTML hàng loạt trong Asp.Net
Tôi đang phát triển một trang web và tôi cần gửi bản tin HTML tới danh sách gửi thư. Tôi đã tạo khung html chứa liên kết "xem trong trình duyệt" và "hủy đăng ký" (lý do sẽ khác nhau). Trong mô-đun quản trị tôi xuất bản html và ht
c - Lỗi giao tiếp I2C B-L072Z-LRWAN (master) và Arduino (slave)
Tôi đang cố gắng thực hiện giao tiếp I2C giữa B-L072Z-LRWAN(Master) và Arduino(Slave). Tôi gửi thành công dữ liệu từ chủ đến nô lệ bằng mã sau: Mã B-L072Z-LRWAN: #
Sitecore ECM Communication: ECM tạo ra các giá trị khác nhau cho các liên kết bên trong tin nhắn khi nhấp vào nút Gửi và Kiểm tra
Tôi có Bản tin ECM chứa một số liên kết đến một trang web (dự án khác). Khi tôi gửi bản tin này đến email của mình bằng cách nhấp vào nút gửi - các liên kết không hoạt động khi tôi nhấp vào chúng từ hộp thư đến email của mình. nó hiển thị 404
Học mẫu thiết kế (2) Mẫu nhà máy-Mẫu nhà máy trừu tượng-6ren
Học mẫu thiết kế (2) Mẫu nhà máy - Mẫu nhà máy vật tượng - Mục lục Bối cảnh Tóm tắt Mẫu nhà máy Ưu điểm và nhược điểm Bài viết tham khảo Bối cảnh Bây giờ tôi cần phát triển một mô-đun vận hành máy ảnh, có thể chạy trên Windows hoặc Linux. Nhà sản xuất
Thời gian cập nhật: 2024-07-05 19:05:35
lý lịch
model house object object
Ưu điểm của point point
Bài viết tham khảo
Bây giờ tôi cần phát triển một mô-đun vận hành máy ảnh, mô-đun này có thể chạy trên Windows hoặc Linux do nhà sản xuất cung cấp. Sự khác nhau giữa SDK trong Windows và SDK trong Linux, nên đối với một máy ảnh thương mại, chúng tôi cần tạo hai lớp để gói gọn API của hai Nền tảng khác nhau này.
Lớp sơ đồ như sau:
Đoạn mã tương ứng (không cần con trỏ thông minh, nếu không sẽ khó vẽ sơ đồ lớp):
class BaslerCamera { public: virtual ~BaslerCamera() = mặc định; bool Virtual OpenCamera() = 0; lớp LinuxBaslerCamera: public BaslerCamera { public: ~LinuxBaslerCamera() ghi đè = mặc định bool OpenCamera() ghi đè { return true; lớp WindowsBaslerCamera : public BaslerCamera { public: ~WindowsBaslerCamera() ghi đè = mặc định; OpenCamera() ghi đè { return true; } }; Lớp CreateBaslerCamera() = 0; LinuxCameraFactory : public CameraFactory { public: BaslerCamera* CreateBaslerCamera() ghi đè { trả về LinuxBaslerCamera new(); } }; lớp WindowsCameraFactory : public CameraFactory { public: BaslerCamera* CreateBaslerCamera() ghi đè { return new WindowsBaslerCamera() } }; //Client int main() { //Nếu bạn thay đổi nền tảng, khách hàng mã hóa chỉ cần sửa CameraFactory* cameraFactory = new LinuxCameraFactory( ); cameraFactory->CreateBaslerCamera(); camera->OpenCamera();
Bây giờ nếu một máy ảnh nhãn hiệu mới được thêm vào: Ốm, thì ý tưởng thiết kế mẫu phương thức nhà máy, lớp nhà vật tượng và lớp nhà máy công cụ tương thích sẽ được tạo cho nó (công cụ có thể bị bỏ qua).
Nhưng phân tích sâu hơn cho thấy rằng đối với mô-đun này, nó chạy trên Windows hoặc Linux. icon BaslerCamera và SickCamera, LinuxBaslerCamera và LinuxSickCamera đều được khởi tạo hoặc WindowsBaslerCamera và WindowsSickCamera được khởi tạo.
Có thể nói, các loại camera khác nhau được chia thành hai sản phẩm: camera Linux và camera Window. cho từng camera hiệu nhãn mà chỉ sử dụng hai Factory là WindowsCameraFactory và LinuxCameraFactory. chúng.
Sau đó, code của lớp máy chủ sẽ như thế này:
lớp CameraFactory { public: virtual ~CameraFactory() = mặc định; virtual BaslerCamera* CreateBaslerCamera() = 0; virtual SickCamera* CreateSickCamera() = 0; }; class LinuxCameraFactory : public CameraFactory { public: BaslerCamera* CreateBaslerCamera() ghi đè { trả lại mới LinuxBaslerCamera(); } Ghi đè SickCamera* CreateSickCamera() { return new LinuxSickCamera(); } }; class WindowsCameraFactory : public CameraFactory { public: BaslerCamera* CreateBaslerCamera() ghi đè { return new WindowsBaslerCamera() } SickCamera* CreateSickCamera(); ghi đè { trả về mới WindowsSickCamera() } };
Điều này dẫn đến mô hình nhà máy vật thể.
Sample Summary Factory cung cấp một giao diện để tạo ra một loạt đối tượng có liên quan hoặc phụ thuộc lẫn nhau mà không có chỉ định các lớp cụ thể của chúng.
sản phẩm sản phẩm ProductA1, ProductA2, ProductB1 và ​​​​ProductB2 là việc phát triển các loại công cụ của hai sản phẩm Vật tượng tương ứng với LinuxBaslerCamera, WindowsBaslerCamera, LinuxSickCamera và WindowsSickCamera trong ví dụ.
Tóm tắtFactory là một lớp cơ sở vật chất của nhà máy, tương thích với CameraFactory trong ví dụ. ConcreteFactory1 và ConcreteFactory2 là các máy cụ thể, tương ứng với LinuxCameraFactory và WindowsCameraFactory trong ví dụ.
Đối với máy khách, một công cụ xuất phiên bản thường có thể được tạo trong mã hóa (phiên bản này tương thích với một dòng sản phẩm) và phiên bản sản xuất này được sử dụng để tạo các sản phẩm cụ thể trong dòng sản phẩm.
Mã khách hàng như sau:
int main() { /* If trên nền windows, chỉ cần thay đổi câu này thành: CameraFactory* cameraFactory = new WindowsCameraFactory(); */ CameraFactory* camera_factory = new LinuxCameraFactory(); ảnh->OpenCamera(); = camera_factory->CreatSickCamera(); disease_Camera->OpenCamera();
Mã hoàn chỉnh như sau:
class BaslerCamera { public: virtual ~BaslerCamera() = mặc định; bool Virtual OpenCamera() = 0; lớp LinuxBaslerCamera: public BaslerCamera { public: ~LinuxBaslerCamera() ghi đè = mặc định bool OpenCamera() ghi đè { return true; lớp WindowsBaslerCamera : public BaslerCamera { public: ~WindowsBaslerCamera() ghi đè = mặc định; OpenCamera() ghi đè { return true; } }; OpenCamera() = lớp CameraFactory { công khai: ảo ~CameraFactory() = mặc định; BaslerCamera Virtual* CreateBaslerCamera() = 0; ; lớp LinuxCameraFactory : public CameraFactory { public: BaslerCamera* CreateBaslerCamera() ghi đè { return new LinuxBaslerCamera() } SickCamera* CreateSickCamera() ghi đè { return new LinuxSickCamera(); } }; class WindowsCameraFactory : public CameraFactory { public: BaslerCamera* CreateBaslerCamera() ghi đè { return new WindowsBaslerCamera() } SickCamera* CreateSickCamera () ghi đè { trả về WindowsSickCamera new(); () { //Nếu trên nền tảng windows, chỉ cần thay đổi câu này thành CameraFactory* cameraFactory = new WindowsCameraFactory(); CameraFactory* camera_factory = new LinuxCameraFactory(); ->OpenCamera(); disease_Camera->OpenCamera();
lợi thế:
Dễ dàng thay đổi dòng sản phẩm
: Quá trình khởi động máy chủ chỉ cần diễn ra một lần trên máy khách, giúp dễ dàng chỉnh sửa.
thiếu sót:
Nhà cung cấp vi phạm quy tắc đóng mở
)
Huaray Camera
WindowsHuarayCamera
LinuxHuarayMáy ảnh
Ngoài ba loại sản phẩm (điều này là cần thiết), bạn cũng phải sửa đổi
Máy ẢnhNhà Máy
Máy chủ Linux ẢnhNhà máy
Máy chủ Windows ẢnhNhà máy
Loại nhà máy này vi phạm nguyên tắc đóng mở.
Nguyên tắc đóng mở trái phép của khách hàng
: Khách hàng yêu cầu ngay từ đầu
CameraFactory* camera_factory = LinuxCameraFactory new();
, nếu muốn chuyển sang nền Windows, bạn cần sửa đổi kiểu khởi động theo cách thủ công, điều này vi phạm nguyên tắc mở và đóng. quả.
Những cải tiến đối với mẫu nhà máy vật thể sẽ được thảo luận trong bài viết tiếp theo.
1. "Mẫu thiết kế Dahua".
Design Pattern Learning (2) Factory Pattern - Mẫu nhà máy vật tượng kết thúc tại đây. Tôi hy vọng bạn sẽ ủng hộ blog của tôi trong tương lai .
Làm cách nào để người mới bắt đầu thử nghiệm hiệu quả càng sớm càng tốt?
Tiêm một dịch vụ (nhà) vào một dịch vụ (nhà) khác, cả hai đều không đồng bộ
Tôi nên làm như sau: Có thể thông báo một dịch vụ/nhà máy, sử dụng API truy vấn $q (async) để lấy một tập dữ liệu lớn về tên Có một dịch vụ khác (cũng không có đồng bộ) sẽ chỉ trả về các phần tử từ nhà máy nếu chúng khớp với một chuỗi mục tiêu phù hợp (tìm kiếm) phù hợp để giảm bớt
Nhà máy C# để phát triển công cụ khai thác cơ sở dữ liệu
Tôi có một lớp cơ sở chung. Tôi có một cơ sở phát triển lớp cơ sở. nhà máy để cung cấp các loại công cụ khác nhau? Ví dụ: lớp công khai ReceptBase trong đó T : IInte
Nhà Ninject cho các loại đường dẫn xuất ra
Tôi đang xem tiện ích mở rộng Ninject Factory tại liên kết sau: http://www.planetgeek.ch/2011/12/31/ninject-extensions-factory-intro
oop - Sự khác biệt giữa nhà cung cấp và dịch vụ?
Sự khác biệt giữa các điều khoản nhà máy, nhà cung cấp và dịch vụ là gì? Vừa phải tìm hiểu về NHibernate và kho lưu trữ mẫu của nó (các lớp POCO, vv). chọn loại dựa trên bất kỳ bối cảnh nào
Nhà Javassist - Cài đặt tải tùy chọn lớp
Sử dụng CGLIB tôi có thể thực hiện var Enhancer = new Enhancer();
Nhà Kotlin dành cho các lớp lồng nhau trong
Tôi đang cố gắng tạo một lớp bên trong lồng nhau trong Kotlin bằng cách sử dụng phương thức xuất xưởng đối tượng Đây là phiên bản mã hóa đơn giản của lớp tôi. OuterClass { var myData:L
Nhà Java với các loại chung
Về cơ bản, dự phòng dự án bao gồm một ứng dụng máy khách và tôi muốn tạo một gói để liên lạc với gói dữ liệu. nội dung. Bây giờ tôi có thể có một vấn đề khác
Nhà máy C++ có tính năng kế thừa
(6 câu trả lời lời) Object sl là gì?
Nhà máy C++.
Tôi muốn mọi ứng dụng bên ngoài sử dụng giao diện của lớp Socket, bao gồm một số lớp (ServerSocketTCP, ClientSocketTCP, ServerSocke
javascript - Nhà máy AngularJS
Tôi chưa quen với Angularjs và tôi đang cố gắng tạo ra một cơ sở dữ liệu nhỏ về phim. Đây là lần đầu tiên tôi sử dụng. nhà máy và tôi muốn chắc chắn rằng đây là cách tiếp cận đúng và cách nào tôi có thể sử dụng nhà máy này trong một chức năng khác như bên dưới?
Java - nhà máy, ví dụ
Câu hỏi này đã có câu trả lời ở đây: Lớp bên trong Java và lớp lồng tĩnh (28 câu trả lời) Đã đóng 5 năm trước lớp. DataFactory công khai
Nhà máy C++ (loại)
Tôi đã xem rất nhiều bài viết về các nhà máy C++, nhưng cho đến nay tôi vẫn chưa tìm ra giải pháp nào cho vấn đề của mình. (Mặc dù tôi có thể thiếu thứ gì đó.) Mẫu điều khiển bảng ứng dụng: #include #include #include
Mẫu đơn máy C++
Đây là một dự án đơn giản C++ đơn giản với 2 thiết kế mẫu: singleton và Factory sigleton cũng là một lớp được tạo mẫu mã, một giao dịch giao diện (IHash) và một lớp (Hash1). Một lớp nhà máy đơn giản (Hash
Nhà máy Java cho các lớp chung
Câu hỏi này tương tự như Factory và generics và có thể có cùng một câu trả lời, nhưng lại khác. được mở rộng bởi các lớp trong một JAR hoàn toàn riêng biệt. nào khác
Máy chủ JavaScript với các tùy chọn tham số
Vấn đề là tôi phải tạo một lớp mới có thể được truyền vào. chấp nhận bất kỳ số lượng đối số nào không? hàm createInstance(ofClass, arg1, arg2, arg3, ...
Nhà máy C++ createObject()
Tôi muốn tạo một phương thức xuất xưởng đơn giản bằng cú pháp C++ đơn giản: void *createObject(const char *str,...) { if(!strcmp("X",str)) retu
php - Di chuyển giữa máy chủ/Nhà vật thể
Sau khoảng 10 tháng học trình cài đặt PHP, giờ tôi đang cố gắng bắt đầu với các nguyên tắc cơ bản OOP và các thiết kế mẫu. Đây là một sở hữu và tôi không có nhiều thời gian để theo đuổi nó, vì vậy xin lỗi ở mức độ thấp của câu hỏi này. Trang web của tôi (hiện tại là chương trình 100%
cơ sở dữ liệu - Nhà Laravel - tạo hoặc động
Tôi có một câu hỏi đơn giản. tôi có một máy đơn giản /**
Angular: Mô-đun tải lười biếng không được gọi đến máy tiêmToken
Tôi đang cố gắng cung cấp mã thông báo APP_BASE_HREF trong mô-đun được tải từng phần, tuy nhiên, phương thức sản xuất vườn hoàn chỉnh không được gọi. Đây https://github.com/MaurizioCascia
Typescript AST Factory - Cách sử dụng chú thích?
Tôi có ast sau: import { Factory as f } from 'TypeScript' const typeDeclaration = f.createTypeAliasDeclara
ELK-6ren
Sử dụng docker để xây dựng giải pháp đồng bộ hóa bản phân phối ELK - ELK là giải pháp đồng bộ hóa bản nhật ký được Hình thức kéo dài ELK được sử dụng phổ biến nhất trong các ngành. nguồn tăng tốc độ trong nước tương đối cũ. nhật ký lưu trữ (-6ren
Thời gian cập nhật: 2024-07-05 19:07:35
Docker Hình do ELK kéo bằng nguồn tăng tốc trong nước tương đối cũ. Sự kiện có thể lấy nguồn từ trang web chính thức. lấy dữ liệu để phân tích trực tiếp API giao diện thông tin của eaticsearch. trình tạo ra với elaticsearch.
Xây dựng Elaticsearch.
docker run -d --name elasticsearch -p 9200:9200 -p 9300:9300 -e "discovery.type=single-node" -e "xpack.security.enabled=false" elasticsearch:8.14.1
Trong số đó, Discovery.type bị bắt buộc, nếu không quá trình khởi động sẽ không thành công. xpack.security.enabled bị sai, vì mặc định giá trị là đúng. Theo yêu cầu mặc định, elaticsearch quyền truy cập được quyền.
Xây dựng kibana.
docker run -d --name kibana --link elasticsearch -p 5601:5601 kibana:7.17.22
Thông số liên kết thông số của docker, no được liên kết với vùng chứa elaticsearch vừa được tạo và mặc định dữ liệu will be link Elaticsearch access data information qua API. điền sai, công việc cần được cấu hình vào lúc này.
Xây dựng một trang Web.
docker run -d --name web -p 5000:80 -v /Logs:/app/Logs -v /etc/localtime:/etc/localtime -e TimeZone=Asia/Shanghai webapplication1:latest
Kéo hình ảnh trang web và vùng khởi động. -v /etc/localtime:/etc/localtime được sử dụng để đồng bộ hóa thời gian của máy chủ và -e TimeZone=Asia/Shanghai được sử dụng để đồng bộ hóa giờ của máy chủ.
-v /Nhật ký:/ứng dụng/Nhật ký Bước này rất quan trọng.
Xây dựng Logstash.
Logstash cần cấu hình các tham số trước khi khởi động máy nhân.
đầu vào { file { path => "/Logs/*.txt" start_position => "bắt đầu" } } lọc { } đầu ra { elasticsearch { máy chủ => ["http://192.168.3.105:9200"] chỉ mục => " logstash-%{+YYYY.MM.dd}" } }
Đầu vào là nguồn đầu vào Chọn tệp. Đầu ra là nguồn đầu ra. điền sai khi xây dựng vùng chứa eaticsearch, bạn cần định cấu hình quyền tại thời điểm này.
docker run -d --name logstash -v /Logs:/Logs -v /root/logstash.conf:/usr/share/logstash/pipeline/logstash.conf logstash:7.17.22
Logstash.conf vào đó.
Nhật ký làm chương trình tạo ra sẽ được đồng bộ hóa với kết nối thông tin máy chủ thông qua kết nối, sau đó được đồng bộ hóa vào vùng chứa logstash sẽ đọc dữ liệu thường xuyên và ghi dữ liệu vào thư viện. for parsing.
Truy cập giao diện trực quan kibana cho phép phân tích đồng bộ hóa nhật ký theo thời gian thực Theo cổng vùng chứa và địa chỉ IP của tôi, địa chỉ trang web kibana của tôi là: http://192.168.3.105:5601.
Các bài viết khác trong loạt bài
Xây dựng hệ thống kiến trúc ứng dụng tích hợp, có thể mở rộng, có tính sẵn sàng cao, an toàn, tự động, có thể theo dõi và tích hợp
Cuối cùng, bài viết này về việc sử dụng docker để xây dựng giải pháp đồng bộ hóa nhật ký phân tán ELK kết thúc tại đây. Nếu bạn muốn biết thêm về cách sử dụng docker để xây dựng giải pháp đồng bộ hóa nhật ký phân tán ELK, vui lòng tìm kiếm các bài viết CFSDN hoặc tiếp tục duyệt các bài viết liên quan. tất cả sẽ ủng hộ blog của tôi trong tương lai! .
Các tình huống có thể áp dụng cho StringBuilder và StringBuffer trong JAVA là gì?
[Java/Log] Khung ghi nhật ký in trạng thái thực thi của mã ghi nhật ký ứng dụng
0 Giới thiệu Tôi thường nghĩ rằng khi định cấu hình cấp độ nhật ký INFO, mã ghi cấp độ gỡ lỗi logger (logger) trong mã ứng dụng sẽ không được thực thi (ví dụ: hàm printTestLog trong Thử nghiệm 1). Nhưng vấn đề trực tuyến ngày nay,
17. Nhật ký cấp độ
Nhật ký Nhật ký là giao diện chính của công cụ xây dựng. Nếu có quá nhiều nhật ký, các cảnh báo và vấn đề thực sự có thể dễ dàng bị ẩn đi. Mặt khác, nếu có sự cố xảy ra, bạn cần tìm hiểu những thông tin liên quan. Gradle xác định 6 cấp độ nhật ký, như được hiển thị trong Bảng 18.1, "Mức nhật ký". Ngoại trừ những người bạn biết
182. Khắc phục sự cố và gỡ lỗi HBase: Nhật ký
Nhật ký Nhật ký quá trình chính như sau... (thay thế bằng người dùng đã khởi động dịch vụ, thay thế bằng tên máy tính) NameNode: $HADOOP_HOME/logs/hadoop- -namenode-.log Da
Nhật ký Git của thay đổi tiếp theo đối với một dòng tệp cụ thể trong nhánh từ xa
Tôi đang khám phá lịch sử git của dự án FFMpeg. Tôi đã thực hiện các thay đổi đối với từng tệp giữa các lần xác nhận 517573a67088b5c7a25c18373434e3448892ee93 và 80bb65fafab1d2f5f.
biểu thức chính quy - nhật ký. Tìm kiếm bằng biểu thức chính quy
Tôi không biết cách tìm kiếm bằng biểu thức chính quy trong loggly. Ví dụ: sử dụng biểu thức /24nonstop.+7554/ để ghi lại nội dung tôi muốn tìm.
Nhật ký API Magento
Có cách nào để bật tính năng ghi nhật ký lệnh gọi API không? Chúng tôi có một ứng dụng của bên thứ ba đang gặp sự cố khi sử dụng cửa hàng của chúng tôi và muốn nhận một số thông tin gỡ lỗi. ~ Tôi đã tìm kiếm bt và không tìm thấy gì. Tôi đang sử dụng 1.7 Câu trả lời hay nhất trong một khoảng thời gian được kiểm soát
Nhật ký SVN cho các đường dẫn cố định trên các bản sao và di chuyển
Tôi đang cố gắng lấy lịch sử nhật ký của một đường dẫn cố định cho tất cả các bản sao/di chuyển/vv trong SVN (đệ quy nếu có thể). Thực ra, tôi đang cố tránh sửa đổi chốt và áp dụng nhật ký cho đường dẫn thay vì đối tượng. Hướng dẫn sử dụng svn hỏi câu hỏi này
nhật ký nant với dữ liệu và dấu thời gian
Làm cách nào tôi có thể chạy tập lệnh NAnt trong dòng lệnh và nhận thời gian của từng tác vụ trong tệp nhật ký? sử dụng nhiệm vụ nant hoặc NAnt -buildfile:testscript.build testnanttarg
Nhật ký tác nhân người dùng Coldfusion?
Có cách nào mặc định để ghi lại tác nhân người dùng nào đã truy cập vào máy chủ của bạn không? Tôi cần lập danh sách các trình duyệt truy cập trang web của chúng tôi để chúng tôi biết những gì chúng tôi có thể hỗ trợ tốt nhất. Cảm ơn! Nhật ký câu trả lời hay nhất CGI.HTTP_USER_AGENT, có thể ở A
mùa xuân - logJavaMailSenderImpl
Tôi đang sử dụng Spring trong ứng dụng của mình để gửi email. Tôi muốn ghi lại hoạt động của máy chủ imap khi gửi email. Tôi cố gắng triển khai đăng nhập vào applicationContext.xml của mình như sau:
Ghi nhật ký Kubernetes - bắt đầu từ đầu
Tôi đã chạy một nhóm được hơn một tuần và chưa khởi động lại nó kể từ đó. Tuy nhiên, tôi vẫn không thể xem nhật ký kể từ khi nó bắt đầu, nó chỉ cung cấp nhật ký của hai ngày qua. Có chính sách xoay vòng nhật ký nào cho vùng chứa không và làm cách nào tôi có thể kiểm soát việc xoay vòng dựa trên kích thước hoặc ngày? Tôi đã thử lệnh sau
elaticsearch - Tất cả dữ liệu nhật ký, số liệu và phân tích nên được nhóm vào một hồ dữ liệu hay được lưu trữ riêng biệt?
Bối cảnh: Tôi đang thiết lập ngăn xếp linh hoạt đầu tiên của mình và mặc dù tôi sẽ bắt đầu đơn giản nhưng tôi muốn đảm bảo rằng mình bắt đầu với một kiến trúc tốt. Cuối cùng tôi muốn có một giải pháp cho: Số liệu được lưu trữ, Nhật ký máy chủ (expressjs APM), Giám sát ứng dụng trang đơn (AP
Nhật ký thủy ngân với một dòng
Lệnh hg log thông thường cung cấp ít nhất 4 dòng đầu ra cho mỗi bộ thay đổi. Ví dụ: tập thay đổi: 238:03a214f2a1cf người dùng: Tên tôi ngày: Th
java - Ghi nhật ký - Cách xóa thông tin cơ sở dữ liệu trong tệp nhật ký
Tôi đang sử dụng khung Spring iBatis trong dự án của mình. Sau đó sử dụng logback để ghi lại. Sau đó khi kiểm tra file log mình thấy cơ sở dữ liệu hệ thống đang sử dụng... Mình muốn ẩn nó đi vì mục đích bảo mật ở đây là log mẫu.. 12:2
Nhật ký thủy ngân giữa hai thẻ
Tôi muốn sử dụng nhật ký hg để tạo nhật ký thay đổi ngắn bao gồm các thay đổi phiên bản mới nhất. Các bản phát hành được đánh dấu bằng tiền tố "v", chẳng hạn như "v0.9.1" hoặc "v1.0". Có thể sử dụng revsets để chọn phạm vi giữa hai thẻ cuối cùng bắt đầu bằng "v", không
PHP - In đối tượng ra bàn điều khiển/nhật ký của chức năng phụ trợ
Tôi mới làm quen với PHP vì vậy xin vui lòng tha thứ cho tôi nếu có câu trả lời đơn giản. Tôi đã tìm kiếm bất kỳ câu hỏi tương tự nào trên stackoverflow nhưng không thể tìm thấy bất kỳ trợ giúp nào. Tôi đang phát triển một ứng dụng dựa trên php hiện có và tôi chỉ cần có khả năng chuyển đổi các đối tượng
Nhật ký RADIUS của Linux
Tôi có một chương trình tên là Radius xác thực thông tin đăng nhập của người dùng. Nhật ký chạy trên máy chủ CentOS nằm trong /var/log/radius.log và chúng như sau: Thứ Hai ngày 24 tháng 7 22:17:08 2017: Tự động
Ghi nhật ký Python - Cách kiểm soát động mức ghi nhật ký
Gần đây tôi đã chuyển từ sử dụng "log" sang "log". Cho đến nay, rất tốt, nhưng tôi đang thiếu một tính năng chính - khả năng thay đổi mức thấp nhất trong thời gian chạy. Trong 'ghi nhật ký', tôi có thể gọi myLogger.setLevel(logging.I
Thiết kế theo dõi/ghi nhật ký cho các hệ thống quan trọng về tốc độ
Giả sử chúng tôi có các hệ thống quan trọng về tốc độ (ví dụ: thống kê/phân tích, lập trình socket, v.v.), làm cách nào để chúng tôi thiết kế theo dõi và ghi nhật ký. Cụ thể hơn, việc ghi nhật ký và theo dõi thường làm giảm hiệu suất (ngay cả khi chúng tôi có cơ chế tắt máy hoặc cơ chế mở rộng quy mô kéo dài). Trong trường hợp này, có lời khuyên nào về cách "đặt"
Học mẫu thiết kế (2) Mẫu nhà máy - Mẫu nhà máy trừu tượng + Sổ đăng ký-6ren
Học mẫu thiết kế (2) Mẫu nhà máy - Mẫu nhà máy trừu tượng + Sổ đăng ký - Mục lục Lời nói đầu Sử dụng Cải tiến nhà máy đơn giản Sử dụng Tài liệu tham khảo cải tiến sổ đăng ký Lời nói đầu Trong bài viết trước, chúng tôi đã đề cập đến một số thiếu sót của phiên bản đầu tiên của mã mẫu nhà máy trừu tượng: ① Khách hàng Kết thúc vi phạm nguyên tắc đóng mở ② Nhà cung cấp vi phạm nguyên tắc open-6ren
Học mẫu thiết kế (2) Mẫu nhà máy - Mẫu nhà máy trừu tượng + Sổ đăng ký
Thời gian cập nhật: 2024-07-09 21:03:39
Sử dụng các cải tiến nhà máy đơn giản
Sử dụng cải tiến đăng ký
Trong bài viết trước, chúng tôi đã đề cập đến một số thiếu sót của phiên bản đầu tiên của mã mẫu nhà máy trừu tượng: ① Máy khách vi phạm nguyên tắc mở và đóng ② Nhà cung cấp vi phạm nguyên tắc mở và đóng. Bài viết này sẽ thảo luận về hai điểm này.
Về thiếu sót ①, chúng ta có thể sử dụng ý tưởng về một nhà máy đơn giản để cải thiện phiên bản đầu tiên của mã nhà máy trừu tượng. Đối với ví dụ trong bài viết trước, chúng tôi đã loại bỏ CameraFactory, BaslerCameraFactory và SickCameraFactory và thay thế chúng bằng lớp SimpleFactory.
Sơ đồ lớp như sau:
Mã này như sau:
// Lớp nhà máy SimpleFactory { public: BaslerCamera* CreateBaslerCamera() { if ("Linux" == os_name_) { return New LinuxBaslerCamera(); } else if ("Windows" == os_name_) { return New WindowsBaslerCamera() } else if ("Windows" == os_name_) { return new WindowsBaslerCamera(); { return nullptr; } } SickCamera* CreateSickCamera() { if ("Linux" == os_name_) { return new LinuxSickCamera(); } else if ("Windows" == os_name_) { return new WindowsSickCamera(); } else { return nullptr; } } public: std::string os_name_ = "Linux" }; /Client int main() { SimpleFactory* camera_factory = new SimpleFactory(); camera_factory->CreateBaslerCamera(); basler_Camera->OpenCamera(); SickCamera* disease_Camera = camera_factory->CreateSickCamera(); disease_Camera->OpenCamera();
Lưu ý rằng mặc dù phương pháp trên đã cải thiện được nhược điểm ① nhưng nhược điểm ② vẫn tồn tại.
Về khuyết điểm ②, bản chất là: khi thêm sản phẩm mới, việc sửa đổi hạng nhà máy vi phạm nguyên tắc đóng mở. Đối với tình huống này, chúng ta có thể tham khảo sổ đăng ký được đề cập trong "Học mẫu thiết kế (2) Mẫu nhà máy - Mẫu phương thức nhà máy + Sổ đăng ký" để loại bỏ các phán đoán nhánh như chuyển đổi hoặc nếu và tách rời khớp nối do các phán đoán nhánh gây ra.
Đối với một sản phẩm cụ thể, chúng ta có thể đăng ký nó như thế này:
lớp LinuxBaslerCamera: public BaslerCamera { public: ~LinuxBaslerCamera() ghi đè = mặc định; bool OpenCamera() ghi đè { return true; } };
Sau đó, mã của lớp nhà máy có thể được đơn giản hóa thành:
class SimpleFactory { public: BaslerCamera* CreateBaslerCamera() { std::string name = os_name_ + "Basler"; return Object::CreateObject
(name); } SickCamera* CreateSickCamera() { std::string name = os_name_ + "Bệnh"; trả về Object::CreateObject
(name); std::string os_name_ = "Linux" };
Bằng cách này, khi thêm dòng sản phẩm (chẳng hạn như thêm HarmonyOS), chúng ta chỉ cần sử dụng ReflectRegister để đăng ký vào tệp tương ứng với lớp sản phẩm bên dưới nó, sau đó thay đổi os_name_ (tất nhiên, os_name_ cũng có thể được thay đổi từ tệp cấu hình khi đang tải, điều này tốt hơn).
Để thêm sản phẩm mới vào dòng sản phẩm hiện có (chẳng hạn như thêm máy ảnh Huaray), chức năng CreateHuarayCamera vẫn cần được thêm vào lớp xuất xưởng.
Cuối cùng, bài viết này về Học mẫu thiết kế (2) Mẫu nhà máy - Mẫu nhà máy trừu tượng + Mẫu đăng ký kết thúc tại đây Nếu bạn muốn biết thêm về Học mẫu thiết kế (2) Mẫu nhà máy - Mẫu nhà máy trừu tượng + Đăng ký cho nội dung của bảng. , vui lòng tìm kiếm các bài viết của CFSDN hoặc tiếp tục duyệt các bài viết liên quan. Tôi hy vọng bạn sẽ ủng hộ blog của tôi trong tương lai! .
Phiên bản MybatisPlus3.X chèn vào phân tích mã nguồn chiến lược IdType.ID_WORKER của id tự tăng
Thuật toán Dotnet và cấu trúc dữ liệu: Hashset, So sánh danh sách
Cách xử lý khi Red Hat không còn duy trì CentOS
Cạm bẫy và câu trả lời khi chuyển các lát Golang làm tham số hàm
Góc nhìn đầy đủ về giao tiếp Docker: nguyên tắc, thực tiễn và hiểu biết kỹ thuật-6ren
Góc nhìn đầy đủ về giao tiếp Docker: nguyên tắc, thực tiễn và hiểu biết kỹ thuật - Bài viết này thảo luận một cách toàn diện và chuyên sâu về công nghệ giao tiếp container Docker, từ các khái niệm cơ bản, mô hình mạng, thành phần cốt lõi đến các ứng dụng thực tế. Nó giới thiệu các chế độ mạng khác nhau và cách triển khai chúng một cách chi tiết, cung cấp chi tiết kỹ thuật và các trường hợp thực tế về giao tiếp container, đồng thời nhằm mục đích cung cấp cho những người hành nghề chuyên nghiệp những hiểu biết sâu sắc về kỹ thuật và thực hành-6ren
Góc nhìn đầy đủ về giao tiếp Docker: nguyên tắc, thực tiễn và hiểu biết kỹ thuật
Thời gian cập nhật: 2024-07-17 10:58:41
Bài viết này thảo luận một cách toàn diện và chuyên sâu về công nghệ truyền thông container Docker, từ các khái niệm cơ bản, mô hình mạng, các thành phần cốt lõi đến các ứng dụng thực tế. Nó giới thiệu các chế độ mạng khác nhau và cách triển khai chúng một cách chi tiết, cung cấp chi tiết kỹ thuật và các trường hợp thực tế về giao tiếp container, đồng thời nhằm mục đích cung cấp cho những người hành nghề chuyên nghiệp những hiểu biết sâu sắc về kỹ thuật và hướng dẫn vận hành thực tế.
Theo dõi [TechLeadCloud] để chia sẻ kiến thức toàn diện về kiến trúc Internet và công nghệ dịch vụ đám mây. Tác giả có hơn 10 năm kinh nghiệm về kiến trúc dịch vụ Internet, kinh nghiệm nghiên cứu và phát triển sản phẩm AI cũng như kinh nghiệm quản lý nhóm. Ông có bằng thạc sĩ tại Đại học Tongji thuộc Đại học Fudan, thành viên của Phòng thí nghiệm Trí tuệ Robot Fudan, kiến trúc sư cấp cao được chứng nhận bởi Alibaba Cloud. , chuyên gia quản lý dự án, nghiên cứu và phát triển các sản phẩm AI với doanh thu hàng trăm triệu người phụ trách.
1. Giới thiệu
Khi kiến trúc điện toán đám mây và vi dịch vụ ngày càng hoàn thiện, Docker, với tư cách là một công nghệ đóng gói nhẹ, đã trở thành thành phần chính trong quá trình phát triển và triển khai phần mềm hiện đại. Bằng cách cung cấp một môi trường chạy biệt lập cho các ứng dụng, các bộ chứa Docker không chỉ cải thiện đáng kể hiệu quả triển khai mà còn nâng cao tính di động và bảo mật của hệ thống. Tuy nhiên, khi các ứng dụng được đóng gói mở rộng về quy mô và độ phức tạp, giao tiếp giữa các container đã trở thành thách thức cốt lõi trong việc xây dựng các dịch vụ đám mây hiệu quả và đáng tin cậy.
Giao tiếp vùng chứa Docker đề cập đến việc trao đổi dữ liệu giữa các phiên bản vùng chứa và giữa các vùng chứa với thế giới bên ngoài (chẳng hạn như các vùng chứa khác, hệ thống máy chủ, tài nguyên Internet). Giao tiếp này là nền tảng của việc xây dựng kiến trúc microservice dựa trên container. Nó hỗ trợ cộng tác và chia sẻ dữ liệu giữa các dịch vụ, đồng thời là cơ sở để hiện thực hóa các tính năng chính như khám phá dịch vụ, cân bằng tải và bảo mật mạng.
Sự phát triển của công nghệ truyền thông
Từ liên kết đơn giản ban đầu đến mô hình mạng tiên tiến hiện tại, công nghệ truyền thông container Docker đã trải qua quá trình phát triển đáng kể. Ban đầu, giao tiếp vùng chứa Docker chủ yếu dựa vào các liên kết, đây là cơ chế giao tiếp cơ bản cho phép các vùng chứa nhận dạng và kết nối trực tiếp với nhau bằng tên. Tuy nhiên, với sự phức tạp ngày càng tăng của các ứng dụng được đóng gói, phương thức giao tiếp đơn giản này không còn có thể đáp ứng được nhu cầu.
Trong những năm gần đây, với sự phát triển và cải tiến liên tục của các chức năng mạng Docker, như Overlay Network và Macvlan, việc liên lạc giữa các container đã trở nên linh hoạt và đáng tin cậy hơn. Các mô hình mạng tiên tiến này cung cấp các khả năng mạng phức tạp hơn, chẳng hạn như giao tiếp giữa các máy chủ, cách ly mạng cũng như quản lý và kiểm soát lưu lượng chi tiết.
Ví dụ: trong ứng dụng thương mại điện tử có kiến trúc microservice, các dịch vụ khác nhau (chẳng hạn như xử lý đơn hàng, quản lý hàng tồn kho, xác thực người dùng) có thể được triển khai trong các vùng chứa khác nhau. Những vùng chứa này cần giao tiếp hiệu quả và an toàn để đảm bảo tính nhất quán của dữ liệu và tính liên tục của quy trình kinh doanh. Trong trường hợp này, mạng lớp phủ của Docker cung cấp khả năng liên lạc giữa các container trên nhiều máy chủ trong khi vẫn đảm bảo tính bảo mật và cách ly lưu lượng mạng.
Tác động của tiến bộ công nghệ
Với sự gia tăng của các công cụ điều phối container như Kubernetes, công nghệ truyền thông container phải đối mặt với những thách thức và cơ hội mới. Kubernetes không chỉ cung cấp khả năng quản lý container mạnh mẽ hơn mà còn giới thiệu các mô hình mạng phức tạp hơn, chẳng hạn như CNI (Giao diện mạng container), thúc đẩy hơn nữa sự phát triển của công nghệ truyền thông container.
2. Tổng quan về giao thông container
Trước khi đi sâu vào cách triển khai và công nghệ cụ thể của giao tiếp vùng chứa Docker, điều quan trọng là phải hiểu các khái niệm và nguyên tắc cơ bản của giao tiếp vùng chứa. Giao tiếp container không chỉ là nền tảng của công nghệ container mà còn là chìa khóa để xây dựng kiến trúc microservice hiệu quả và đáng tin cậy.
Nguyên tắc cơ bản của giao tiếp container
Giao tiếp vùng chứa Docker dựa trên công nghệ mạng, không gian tên và ảo hóa của Linux. Mỗi bộ chứa Docker chạy trong không gian tên mạng riêng, nghĩa là nó có một ngăn xếp mạng độc lập (bao gồm địa chỉ IP, bảng định tuyến, số cổng, v.v.). Giao tiếp giữa các container cần phải đạt được thông qua một loạt giao diện mạng và quy tắc định tuyến.
Phân loại các phương thức truyền thông
Giao tiếp container có thể được chia thành hai loại chính: giao tiếp trực tiếp và giao tiếp gián tiếp.
giao tiếp trực tiếp
Giao tiếp trực tiếp đề cập đến kết nối mạng trực tiếp giữa các container. Ví dụ điển hình nhất là chế độ mạng mặc định của Docker - chế độ cầu nối, trong đó container được kết nối với cầu ảo của máy chủ thông qua giao diện mạng ảo để đạt được giao tiếp giữa các container.
giao tiếp gián tiếp
Truyền thông gián tiếp liên quan đến các cấu trúc mạng phức tạp hơn như mạng lớp phủ. Trong mạng lớp phủ, giao tiếp giữa các vùng chứa đi qua lớp mạng ảo, cho phép các vùng chứa được phân phối trên các máy chủ khác nhau giao tiếp với nhau.
Các thành phần chính của giao tiếp container
Giao tiếp vùng chứa dựa trên một số thành phần chính, bao gồm daemon Docker, không gian tên mạng, cầu nối ảo, giao diện mạng ảo và trình điều khiển mạng.
Trình nền Docker
Trình nền Docker là cốt lõi của kiến trúc Docker và chịu trách nhiệm tạo, chạy và quản lý các vùng chứa. Nó cũng xử lý cấu hình mạng của vùng chứa, đảm bảo rằng vùng chứa có thể kết nối chính xác với mạng được chỉ định.
không gian tên mạng
Không gian tên mạng cung cấp một môi trường mạng biệt lập để mỗi vùng chứa có ngăn xếp mạng độc lập riêng. Tính năng này là chìa khóa để đạt được sự cách ly mạng giữa các vùng chứa.
Cầu ảo và giao diện mạng
Cầu ảo là cầu nối kết nối các giao diện mạng của các container khác nhau, cho phép các container chia sẻ cùng một mạng vật lý. Giao diện mạng ảo (chẳng hạn như cặp veth) là phương tiện để liên lạc giữa vùng chứa và máy chủ.
trình điều khiển mạng
Docker hỗ trợ nhiều trình điều khiển mạng khác nhau, chẳng hạn như cầu nối, lớp phủ, macvlan, v.v. Mỗi trình điều khiển cung cấp các tính năng và chức năng mạng khác nhau.
Những phát triển mới nhất trong công nghệ truyền thông container
Khi công nghệ container tiếp tục phát triển, công nghệ truyền thông container cũng đang phát triển. Ví dụ, một số nghiên cứu gần đây tập trung vào việc cải thiện hiệu suất của mạng container, giảm độ trễ mạng và nâng cao hiệu quả xử lý gói. Ngoài ra, an ninh mạng cũng trở thành chủ đề nghiên cứu nóng, đặc biệt là đảm bảo sự cách ly và bảo mật liên lạc giữa các container trong môi trường nhiều người thuê.
Nghiên cứu điển hình
Lấy một nhà cung cấp dịch vụ đám mây lớn làm ví dụ, họ có thể triển khai hàng nghìn container trong nhiều trung tâm dữ liệu để hỗ trợ các dịch vụ khác nhau. Trong môi trường này, việc giao tiếp hiệu quả giữa các container là rất quan trọng. Mạng lớp phủ đóng một vai trò quan trọng ở đây, không chỉ cung cấp khả năng liên lạc giữa các máy chủ mà còn hỗ trợ cân bằng tải và chuyển đổi dự phòng. Thiết kế mạng như vậy không chỉ đảm bảo tính sẵn sàng cao mà còn cải thiện hiệu suất mạng tổng thể.
3. Mô hình mạng Docker
Hiểu mô hình mạng của Docker là rất quan trọng để thành thạo giao tiếp vùng chứa. Docker cung cấp nhiều mô hình mạng để phù hợp với các nhu cầu triển khai và liên lạc khác nhau. Mỗi mô hình mạng có các đặc điểm và kịch bản sử dụng riêng, đồng thời hiểu rõ các mô hình này là nền tảng để thiết kế và triển khai các ứng dụng được đóng gói hiệu quả.
mạng lưới cầu
Mạng cầu nối là mô hình mạng mặc định của Docker và phù hợp với các container được triển khai trên một máy. Trong mô hình này, Docker tạo một cầu nối mạng ảo (docker0) và tất cả các container chạy trên cùng một máy chủ đều giao tiếp thông qua cầu nối ảo này.
Tính năng và công dụng
Sự cách ly
: Mạng cầu nối cung cấp một không gian tên mạng độc lập cho mỗi vùng chứa.
Dễ sử dụng
: Theo cấu hình mặc định, container có thể được sử dụng ngay mà không cần cấu hình phức tạp.
Các tình huống áp dụng
: Thích hợp cho các ứng dụng nhỏ hoặc môi trường phát triển được triển khai trên một máy.
mạng chủ
Ở chế độ mạng máy chủ, các thùng chứa chia sẻ không gian tên mạng của máy chủ. Điều này có nghĩa là các container giao tiếp không phải qua mạng ảo mà trực tiếp sử dụng giao diện mạng của máy chủ.
hiệu suất
: Cung cấp hiệu suất mạng cao hơn mạng ảo.
Không bị cô lập
: Không có sự cô lập trên mạng, hoạt động mạng của vùng chứa giống như máy chủ.
: Các vấn đề nhu cầu hiệu suất cao, xem xét các ứng dụng hoặc mạng dịch vụ có tải nặng.
No network
Trong mô hình không có mạng, vùng chứa cấu hình không có mạng giao diện. sử dụng yêu cầu bảo mật cao hoặc không yêu cầu mạng tương tác.
: Cung cấp cấp độ bảo mật cực cao vì không có quyền truy cập mạng bên ngoài.
: Các ứng dụng có yêu cầu bảo mật cực cao, có giới hạn như các hoạt động xử lý dữ liệu nhạy cảm.
lớp phủ mạng
Docker Swarm hỗ trợ kết nối container trên nhiều máy chủ Docker. một lớp mạng ảo để các container được phân phối trên các máy chủ khác có thể giao tiếp với nhau.
Giao tiếp giữa các máy chủ
: Hỗ trợ giao tiếp giữa các container chạy trên các máy chủ khác nhau.
: Các ứng dụng quy mô lớn được phát triển trên máy chủ nhiều máy chủ, được coi là kiến ​​trúc microservice.
mạng macvlan
Mạng Macvlan cho phép các container có địa chỉ MAC độc lập và được kết nối với vật lý mạng giống như vật lý thiết bị.
Truy cập trực tiếp vào vật lý mạng
: Các thùng chứa có thể hiển thị trực tiếp trên mạng giống như các vật lý.
: Các vấn đề cần xuất hiện trực tiếp trên vật lý mạng, suy nghĩ về các ứng dụng nhạy cảm các chức năng cần vượt qua mạng hóa ảo hóa.
Tiến bộ công nghệ và trường ứng dụng hợp lý
Với sự phát triển của công nghệ container, mô hình mạng Docker cũng không ngừng phát triển. tập trung cải thiện hoạt động và hiệu suất của mạng mô hình cũng như hỗ trợ các cấu trúc và chính sách network phức tạp hơn.
Trường hợp: Triển khai mô-đun microservice microservice
Trong quy mô microservice kiến ​​trúc lớn hơn, mỗi dịch vụ đều có thể được phát triển trên các máy chủ khác nhau. lớp phủ cung cấp một giải pháp lý tưởng, cho phép các giao tiếp tiếp nối vùng chứa giữa các máy chủ cung cấp cách thức và cần có mạng bảo mật. mà không phải lo lắng về sự phức tạp của cơ sở mạng.
4. Các thành phần cốt lõi của công cụ truyền thông công nghệ
Việc phát triển giao tiếp container phụ thuộc vào công việc cộng tác của nhiều thành phần cốt lõi. Sau đây là các thành phần cốt lõi của bộ chứa công nghệ truyền thông tin, mỗi thành phần đóng một vai trò không thể thiếu.
Trình nền Docker là trung tâm quản lý vòng đời của container. Docker nền chạy ở chế độ nền và tương tác với các dịch vụ và ứng dụng khác thông qua API Docker.
Chức năng cốt lõi
Quản lý vùng chứa
: Kiểm soát việc tạo, bắt đầu, dừng và các vòng đời sự kiện khác của vùng chứa.
: Cấu hình và quản lý cài đặt của vùng chứa mạng, bao gồm mạng chế độ, cổng xạ ảnh, vv
No network name
Không có mạng tên nào là một tính năng của nhân Linux cung cấp môi trường cài đặt đặc biệt cho mỗi vùng chứa. Điều này có nghĩa là mỗi vùng chứa. decan mạng môi trường.
cách thức
: Thực hiện cách ly mạng giữa các container.
Cấu hình độc lập
: Cung cấp cấu hình mạng độc lập cho từng container.
Cầu Đảo
Trọng Docker.
Thiết bị kết nối
: Cho phép nhiều giao tiếp mạng thiết bị trên cùng một mạng.
check Control line
: Quản lý và chuyển tiếp lượng lưu trữ qua bridge.
Virtual Network Interface
Trong giao tiếp tiếp theo vùng chứa, một điểm cuối được đặt bên trong vùng chứa và điểm cuối nhưng lại được kết nối với yêu cầu Ảo của máy chủ.
contact information
: Container kết nối mạng và máy chủ.
Truyền dữ liệu
: Cho phép truyền dữ liệu giữa các vùng chứa và máy chủ.
Network control
Docker cung cấp nhiều mạng điều khiển để hỗ trợ các mạng yêu cầu khác nhau. Hỗ trợ kết nối Chuẩn kết nối mạng được hỗ trợ, vùng liên kết hỗ trợ hỗ trợ lớp điều khiển chứa trên máy chủ và macvlan điều khiển có thể kết nối trực tiếp các vùng chứa với vật lý mạng.
Network model support
: Triển khai các mô hình truyền thông mạng khác nhau.
Cấu hình linh hoạt
: Cung cấp các tùy chọn và chiến lược cấu hình mạng khác nhau.
5. Hộp đựng giao tiếp Thực hành
Sau khi hiểu những điều cơ bản và các thành phần cốt lõi của giao tiếp tiếp theo, điều quan trọng phải áp dụng những lý do này đưa điều này vào các tình huống thực tế. vấn đề và công cụ hoạt động, bao gồm giao tiếp trực tiếp giữa các container, giao tiếp bên ngoài bằng cách sử dụng cổng xạ và kết quả tiếp theo giữa các container thông qua mạng Docker.
bản 1: Giao tiếp trực tiếp giữa các container
Trong kiến ​​trúc microservice đơn giản, dịch vụ A cần giao tiếp trực tiếp với dịch vụ B. Cả hai dịch vụ đều được phát triển khai trong các vùng chứa khác nhau trên cùng một máy chủ.
Thao tác các bước
Tạo mạng do người dùng xác định: Sử dụng docker mạng tạo lệnh để tạo mới kết nối mạng.
Khởi động các container: Sử dụng docker run để khởi động các container của dịch vụ A và dịch vụ B, đồng thời kết nối chúng with the network vừa được tạo.
Định cấu hình quy tắc mạng: Đảm bảo quy tắc mạng của các vùng được phép tiếp tục với nhau.
Kiểm tra giao tiếp: Sử dụng mạng công cụ (chẳng hạn như vòng tròn) trong vùng chứa dịch vụ A để kiểm tra giao tiếp tiếp theo dịch vụ B.
Tình huống 2: Sử dụng ánh xạ cổng để phát triển giao tiếp bên ngoài
Một ứng dụng web được triển khai trong vùng chứa Docker và cần được người dùng bên ngoài cho phép truy cập thông qua cổng của máy chủ.
Chuẩn bị ứng dụng: Chuẩn bị ứng dụng web và đảm bảo ứng dụng có thể chạy bình thường bên trong vùng chứa.
Ánh xạ cổng: Sử dụng lệnh docker run -p để khởi động vùng chứa và ánh xạ một cổng trên máy chủ tới cổng dịch vụ Web của vùng chứa.
Truy cập bên ngoài: Truy cập ứng dụng web từ bên ngoài thông qua địa chỉ IP của máy chủ và cổng được ánh xạ.
Kịch bản 3: Triển khai liên lạc giữa các container thông qua mạng Docker
Trong một ứng dụng phân tán, nhiều dịch vụ được triển khai trên các máy chủ khác nhau và cần phải đạt được sự liên lạc giữa các dịch vụ này.
Tạo mạng lớp phủ: Tạo mạng lớp phủ ở chế độ Docker Swarm.
Triển khai dịch vụ: Sử dụng docker service create để triển khai các dịch vụ khác nhau trên mạng lớp phủ.
Định cấu hình DNS: Sử dụng dịch vụ DNS tích hợp của Docker để đảm bảo rằng vùng chứa có thể phân giải địa chỉ của các dịch vụ khác thông qua tên dịch vụ.
Kiểm tra giao tiếp giữa các máy chủ: Kiểm tra giao tiếp trong vùng chứa của một dịch vụ với vùng chứa của dịch vụ khác.
Theo dõi [TechLeadCloud] để chia sẻ kiến thức toàn diện về kiến trúc Internet và công nghệ dịch vụ đám mây. Tác giả có hơn 10 năm kinh nghiệm về kiến trúc dịch vụ Internet, kinh nghiệm nghiên cứu và phát triển sản phẩm AI cũng như kinh nghiệm quản lý nhóm. Ông có bằng thạc sĩ tại Đại học Tongji thuộc Đại học Fudan, thành viên của Phòng thí nghiệm Trí tuệ Robot Fudan, kiến trúc sư cấp cao được chứng nhận bởi Alibaba Cloud. , chuyên gia quản lý dự án, nghiên cứu và phát triển các sản phẩm AI với doanh thu hàng trăm triệu người phụ trách. Nếu hữu ích, vui lòng chú ý nhiều hơn đến TeahLead KrisChang, hơn 10 năm kinh nghiệm trong ngành Internet và trí tuệ nhân tạo, hơn 10 năm kinh nghiệm quản lý nhóm kỹ thuật và kinh doanh, bằng cử nhân về công nghệ phần mềm tại Tongji, bằng thạc sĩ quản lý kỹ thuật đến từ Fudan, Kiến trúc sư cao cấp về dịch vụ đám mây được chứng nhận của Alibaba Cloud, Trưởng bộ phận kinh doanh sản phẩm AI với doanh thu trên 100 triệu.
Cuối cùng, bài viết này về quan điểm đầy đủ về giao tiếp Docker: nguyên tắc, thực tiễn và hiểu biết kỹ thuật sẽ kết thúc tại đây. Nếu bạn muốn biết thêm về quan điểm đầy đủ về giao tiếp Docker: nguyên tắc, thực tiễn và hiểu biết kỹ thuật, vui lòng tìm kiếm bài viết CFSDN hoặc tiếp tục Duyệt. các bài viết liên quan, hi vọng các bạn sẽ ủng hộ blog của mình trong tương lai! .
Từ DDPM đến DDIM
JavaJVM——12. Tổng quan về lý thuyết thu gom rác
Microsoft công bố tập trung vào .NET Aspire tại hội nghị nhà phát triển
Mẫu thiết kế-C# triển khai mẫu nhà máy đơn giản
docker - docker, docker không kiểm tra địa chỉ IP
Tôi đang sử dụng dockerfile sau: FROM ubuntu:14.04 MAINAINER xxx xxx # SSH RUN apt-get update && apt-get install
docker docker-compose không nhận được hình ảnh bộ đệm liên quan
Tôi đã chạy docker-compose build celery, (sau nhiều giờ thử và kết nối) nó đã hoạt động 80% lần đầu tiên của ứng dụng Dockerfile giống nhau. Nhưng bộ đệm không được sử dụng lại. Từ những gì tôi có thể duyệt,
docker - Tất cả các kho lưu trữ trong đăng ký Docker sẽ bị xóa sau khi docker khởi động lại nền tảng (docker-for-mac)
Tôi có thể tạo thành công dịch vụ đăng ký Docker v2 bằng lệnh sau: docker service create Sau đó, tôi sử dụng docker Push để đưa ra một số hình hình ảnh lên dịch vụ Khi tôi vượt qua Curl localh
docker - Không thể kết nối với docker daemon docker trong hình ảnh docker
gitlab, gitlab, gitlab, gitlab, gitlab, gitlab Đây là kết quả của việc xây dựng
docker - Giảm thiểu thời gian thực thi `docker build` bên trong vùng chứa Docker-in-Docker
Trường hợp sử dụng: Chúng tôi có một số "công việc phát hiện" trong ứng dụng xây dựng và cung cấp hình ảnh Docker của Jenkins sử dụng vào docker đăng ký, cập nhật phiên bản dự án trong nhiều tệp khác nhau và cuối cùng là đưa thẻ phát hành vào G tương thích ứng
docker - Docker của mình dùng
Khi tôi cố gắng xây dựng docker file của mình, docker trả lời lỗi sau: [+] Building 0.0s (1/2)
docker - Cách sử dụng docker trong đường ống jenkins mà không cần sử dụng docker-in-docker
Tác giả của docker-in-docker Khuyên bạn không nên sử dụng hình ảnh này cho CI mục tiêu trong blog này: jpetazzo/Using Docker-in-Docker for your CI or testing en
docker - Chạy Docker trong vùng chứa Docker: Không thể kết nối với daemon Docker
Tôi đã tạo một Dockerfile để chạy Docker trong Docker: FROM ubuntu:16.04 RUN apt-get update && \ apt-get in
docker - Làm cách nào để tìm hình ảnh Docker có thẻ cụ thể trong sổ đăng ký Docker từ Docker lệnh dòng?
Tôi đang cố gắng tìm một thẻ cụ thể để chọn Docker hình ảnh. tránh tải xuống tất cả các hình ảnh và sau đó xóa những hình ảnh tôi không cần thiết. https://registry.hub.do
docker - docker trong docker, đăng lỗi HTTP
Tôi đang chạy docker bên trong docker. muốn kiểm tra hiệu suất của docker khi chạy từ một docker khác. Tôi khởi động docker thông qua boot2docker trên Mac
docker - Docker: Tùy chọn trong docker-compose.yml để tự động phát triển lại hình ảnh mới
bản docker-compose.yml: "3" service: daggr: image: "docker.pvt phiên.com/test/daggr:stable"
docker - Truy cập Docker trong vùng chứa Docker
Trong một số mã, tôi đã khởi động vùng chứa để thu thập dữ liệu trang và truy xuất thông báo mã hóa cho dịch vụ (Gitlab) đang chạy trong vùng. Bây giờ, tôi muốn Dockerize chạy mã của nó. Cụ thể là đại loại như: o
docker - docker soạn thảo tập tin so với docker gói
Câu hỏi này đã được hỏi trước đây nhưng tôi không chắc liệu việc phát triển khai phá docker có thể được thực hiện bằng cách sử dụng các tệp docker-compose tại thời điểm đó hay không. Do sắp xếp bằng cách sử dụng tính năng chỉnh sửa nên tôi không thể hiểu được giá trị của tệp dữ liệu mà tôi kiểm tra.
docker - Sự khác biệt giữa docker pool và docker đăng ký là gì?
Tôi đã hỏi câu hỏi này trong một cuộc phỏng vấn và không thể trả lời được thông tin liên quan. đã thấy.
docker - docker: Làm cách nào để sao chép tất cả các tệp png trong docker vào máy chủ?
Docker cp docker cp docker cp container_name:path/to/file/in/docker/*.png path/o
docker
Nhật ký điều khiển của tôi đã được đặt thành tạp chí. Nhật ký cấp độ trong tệp daemon.json có ảnh hưởng đến nhật ký không? Khi sử dụng nhật ký docker sẽ chỉ cập nhật vùng chứa ký tự ảnh có bị ảnh hưởng không? Ví dụ: docker và jour
docker
Gần đây tôi đã bắt đầu sử dụng Docker + Celery. là một số đoạn mã từ đó giúp giải quyết quan điểm của tôi trong bối cảnh.
docker - docker: Không thể gửi hình ảnh docker được xây dựng
CMD ---> Use buffer ---> efc82ff1ca
docker - Docker + docker-composition + không thể khởi động dịch vụ
Docker-compose.yml chỉnh sửa, chúng tôi đang gặp lỗi sau docker-comp
docker - kho lưu trữ hình ảnh cơ sở docker bên ngoài docker hub?
Tôi mới làm quen với Docker. trên đám mây của bạn thay vì có tài khoản DH Cảm ơn? mình nếu muốn. Có thể tìm thấy ở Depl
Khái niệm cơ bản về phát triển iOS 109-Bảo mật mạng-6ren
iOS Development Basics 109 - Network Security - Trong quá trình phát triển iOS, việc đảm bảo an ninh mạng cho các ứng dụng là một mắt xích rất quan trọng. Sau đây là một số biện pháp bảo mật mạng phổ biến và mã mẫu tương ứng: Phiên bản Swift 1. Sử dụng HTTPS Đảm bảo rằng tất cả các yêu cầu mạng đều sử dụng giao thức HTTPS để mã hóa việc truyền dữ liệu, -6ren
Khái niệm cơ bản về phát triển iOS 109-Bảo mật mạng
Thời gian cập nhật: 2024-07-17 12:58:39
Trong quá trình phát triển iOS, việc đảm bảo an ninh mạng cho ứng dụng là một mắt xích rất quan trọng. Sau đây là một số biện pháp an ninh mạng phổ biến và mã mẫu tương ứng:
Phiên bản Swift
Đảm bảo rằng tất cả các yêu cầu mạng đều sử dụng giao thức HTTPS để mã hóa việc truyền dữ liệu và ngăn chặn các cuộc tấn công trung gian.
Mã mẫu:
Định cấu hình Bảo mật vận chuyển ứng dụng (ATS) trong Info.plist:
NSAppTransportSecurity
NSAllowsArbitraryLoads
2. Ghim SSL
Ghim SSL có thể đảm bảo rằng ứng dụng chỉ tin cậy chứng chỉ máy chủ được chỉ định và ngăn không cho nó bị tấn công vào máy chủ giả mạo.
nhập Lớp nền tảng URLSessionPinningDelegate: NSObject, URLSessionDelegate { func urlSession(_ session: URLSession, didReceive challenge: URLAuthenticationChallenge, CompleteHandler: @escaping (URLSession.AuthChallengeDisposition, URLCredential?) -> Void) { if let serverTrust = challenge.protectionSpace.serverTrust, SecTrustEvaluate(serverTrust, nil) == errSecSuccess, let serverCertificate = SecTrustGetCertificateAtIndex(serverTrust, 0) { let localCertificateData = try? Data(contentsOf: Bundle.main.url(forResource: "your_cert", withExtension: "cer")!) hãy để máy chủCertificateData = SecCertificateCopyData(serverCertificate) as Data if localCertificateData == serverCertificateData { let credential = URLCredential(trust: serverTrust) CompleteHandler(.useCredential, credential) return } } CompleteHandler(.cancelAuthenticationChallenge, nil) } } // Cách sử dụng let url = URL(string: "https://yoursecurewebsite.com")! let session = URLSession(configuration: .default, delegate: URLSessionPinningDelegate(), delegateQueue: nil) let task = session.dataTask(with: url) { data, reply, error in // Xử lý phản hồi } task.resume()
3. Ngăn chặn việc tiêm SQL
Sử dụng các truy vấn được tham số hóa để ngăn chặn các cuộc tấn công tiêm nhiễm SQL khi xử lý thông tin đầu vào của người dùng.
import SQLite3 func queryDatabase(userInput: String) { var db: OpaquePointer? // Mở cơ sở dữ liệu (giả sử dbPath là đường dẫn đến cơ sở dữ liệu của bạn) sqlite3_open(dbPath, &db) var queryStatement: OpaquePointer let query = "SELECT * FROM user WHERE username? = ?" if sqlite3_prepare_v2(db, query, -1, &queryStatement, nil) == SQLITE_OK { sqlite3_bind_text(queryStatement, 1, userInput, -1, nil) while sqlite3_step(queryStatement) == SQLITE_ROW { // Kết quả xử lý } } sqlite3_finalize(queryStatement) sqlite3_close(db) }
4. Mã hóa dữ liệu
Khi lưu trữ dữ liệu nhạy cảm, hãy sử dụng thư viện mã hóa của iOS để mã hóa dữ liệu, chẳng hạn như sử dụng Chuỗi khóa.
import Security func saveToKeychain(key: String, data: Data) -> OSStatus { let query: [String: Any] = [ kSecClass as String: kSecClassGenericPassword, kSecAttrAccount as String: key, kSecValueData as String: data ] SecItemDelete(truy vấn dưới dạng CFDictionary ) // Xóa mọi mục hiện có return SecItemAdd(truy vấn dưới dạng CFDictionary, nil) // Thêm mới item } func LoadFromKeychain(key: String) -> Data? { let query: [String: Any] = [ kSecClass as String: kSecClassGenericPassword, kSecAttrAccount as String: key, kSecReturnData as String: kCFBooleanTrue!, kSecMatchLimit as String: kSecMatchLimitOne ] var dataTypeRef: AnyObject? hãy để trạng thái: OSStatus = SecItemCopyMatching(truy vấn dưới dạng CFDictionary, &dataTypeRef) if status == noErr { return dataTypeRef as?
5. Xác thực và làm sạch đầu vào
Xác thực và vệ sinh đầu vào của người dùng để ngăn chặn XSS (tập lệnh chéo trang) và các cuộc tấn công tiêm nhiễm khác.
func clean(userInput: String) -> String { // Xóa mọi thẻ script hoặc nội dung nguy hiểm tiềm tàng khác return userInput.replacingOccurrences(of: "
", with: "", options: .caseInsensitive) } // Cách sử dụng let userInput = "
" let được vệ sinhInput = vệ sinh(userInput: userInput) print(sanitizedInput) // Kết quả đầu ra: cảnh báo ('xss')
phiên bản OC
#import
@interface URLSessionPinningDelegate : NSObject
@end @implementation URLSessionPinningDelegate - (void)URLSession:(NSURLSession *)session didReceiveChallenge:(NSURLAuthenticationChallenge *)challenge CompleteHandler:(void (^)(NSURLSessionAuthChallengeDisposition, NSURLCredential * _Nullable credential))completionHandler { if ([challenge.protectionSpace.authenticationMethod isEqualToString:NSURLAuthenticationMethodServerTrust]) { SecTrustRef serverTrust = challenge.protectionSpace.serverTrust; = SecTrustGetCertificateAtIndex(serverTrust, 0); NSString *certPath = [[NSBundle mainBundle] pathForResource:@"your_cert" ofType:@"cer"]; *)(SecCertificateCopyData(serverCertificate)); if ([localCertData isEqualToData:serverCertData]) { NSURLCredential *credential = [NSURLCredential credentialForTrust:serverTrust]; CompleteHandler(NSURLSessionAuthChallengeCancelAuthenticationChallenge, nil); } @end // Cách sử dụng NSURL *url = [NSURL URLWithString:@"https://yoursecurewebsite.com"]; NSURLSessionConfiguration *sessionConfig = [NSURLSessionConfiguration defaultSessionConfiguration]; *pinningDelegate = [[URLSessionPinningDelegate alloc] init]; NSURLSession *session = [NSURLSession sessionWithConfiguration:sessionConfig delegate:pinningDelegate delegateQueue:nil]; NSURLSessionDataTask *task = [session dataTaskWithURL:url CompleteHandler:^(NSData *data, NSURLResponse *response, NSError *error) { if (error == nil) { // Xử lý phản hồi } }] [tiếp tục nhiệm vụ];
- (void)queryDatabase:(NSString *)userInput { sqlite3 *db; // Mở cơ sở dữ liệu (giả sử dbPath là đường dẫn đến cơ sở dữ liệu của bạn) if (sqlite3_open([dbPath UTF8String], &db) == SQLITE_OK) { câu lệnh sqlite3_stmt *; const char *query = "CHỌN * TỪ người dùng Ở ĐÂU tên người dùng = ?"; if (sqlite3_prepare_v2(db, query, -1, &statement, NULL) == SQLITE_OK) { sqlite3_bind_text(statement, 1, [userInput UTF8String], -1, SQLITE_TRANSIENT); while (sqlite3_step( câu lệnh) == SQLITE_ROW) { // Kết quả xử lý } } sqlite3_finalize(câu lệnh); sqlite3_close(db);
- (OSStatus)saveToKeychainWithKey:(NSString *)key data:(NSData *)data { NSDictionary *query = @{(__bridge id)kSecClass: (__bridge id)kSecClassGenericPassword, (__bridge id) kSecAttrAccount: khóa, (__bridge id)kSecValueData: data}; SecItemDelete((__bridge CFDictionaryRef)query); // Xóa mọi mục hiện có return SecItemAdd((__bridge CFDictionaryRef)query, NULL); // Thêm mục mới } - (NSData *)loadFromKeychainWithKey:(NSString *)key { NSDictionary *query = @{(__bridge id)kSecClass: (__bridge id)kSecClassGenericPassword, (__bridge id)kSecAttrAccount: key, (__bridge id)kSecReturnData: (__bridge id)kCFBooleanTrue, (__bridge id)kSecMatchLimit: (__bridge id)kSecMatchLimitOne}; trạng thái OSStatus = SecItemCopyMatching((__bridge CFDictionaryRef)query, &dataTypeRef ); if (status == noErr) { return (__bridge_transfer NSData *)dataTypeRef; } else { return nil; }
- (NSString *)sanitize:(NSString *)userInput { // Xóa mọi thẻ tập lệnh hoặc nội dung nguy hiểm tiềm tàng khác NSString *sanitizedInput = [userInput stringByReplacingOccurrencesOfString:@"
" withString:@"" options:NSCaseInsensitiveSearch range:NSMakeRange(0,sanitizedInput.length)]; return cleanedInput; } // Cách sử dụng NSString *userInput = @"
"; NSString *sanitizedInput = [tự vệ sinh:userInput]; NSLog(@"%@", được vệ sinhInput); // Kết quả đầu ra: cảnh báo ('xss')
Thông qua các biện pháp này, bạn có thể cải thiện đáng kể tính bảo mật mạng của ứng dụng iOS của mình. Dựa trên nhu cầu của dự án, các công nghệ này được sử dụng linh hoạt để đảm bảo an toàn cho dữ liệu người dùng.
Cuối cùng, bài viết về iOS Development Fundamentals 109 - Network Security kết thúc tại đây. Nếu bạn muốn biết thêm về iOS Development Fundamentals 109 - Network Security, vui lòng tìm kiếm các bài viết về CFSDN hoặc tiếp tục duyệt các bài viết liên quan. tương lai blog của tôi! .
Trực quan hóa—gojs có nhiều chia sẻ kinh nghiệm thực tế (3)
Trình trang trí DjangoDRF@action
Giải mã bản đồ triển khai xsync
Nguyên tắc tổng hợp bảng tính có hiệu suất cao: Tiết lộ sự kỳ diệu của phản hồi cấp hai thuần túy của giao diện người dùng đối với hàng triệu hàng dữ liệu
io - IO được ánh xạ bộ nhớ - Làm thế nào để thiết bị IO biết giá trị đã thay đổi?
Làm thế nào để một thiết bị IO biết rằng giá trị trong bộ nhớ thuộc về nó đã thay đổi trong IO được ánh xạ vào bộ nhớ? ? Ví dụ: giả sử rằng địa chỉ bộ nhớ 0 được dành riêng để giữ màu nền của thiết bị VGA. Khi chúng ta thay đổi giá trị trong bộ nhớ[0], VGA
Lỗi đăng nhập Facebook iOS iOS SDK
Tôi hiện đang phát triển một ứng dụng iOS sử dụng sdk Facebook để đăng nhập (thông qua FBLoginView). Mọi thứ đều hoạt động tốt ngoại trừ những người có phiên bản facebook cũ hơn. Khi họ nhấn nút "Đăng nhập bằng Facebook", anh ấy
ios ios nsrange char từ cuối
Giả sử tôi có: đây - là một - ví dụ - với một số - dấu gạch ngangNSRange sẽ chọn phiên bản đầu tiên của "-" bằng cách sử dụng `rangeOfString:@"-", nhưng nếu tôi chỉ muốn phiên bản cuối cùng
Làm cách nào để lấy tên quốc gia từ SDK card.io? -iOS
Card.io SDK cung cấp các thông tin chi tiết sau: số thẻ, ngày hết hạn, tháng, năm, CVV và mã bưu chính. Làm cách nào tôi có thể lấy tên quốc gia từ SDK này. - (void)userDidProvideCreditCardInfo:(Ô tô
Làm cách nào để ứng dụng iOS tải xuống hình ảnh từ dịch vụ web và cài đặt chúng trên thiết bị iOS của người dùng trong khi cài đặt?
Làm cách nào để ứng dụng iOS tải xuống hình ảnh từ dịch vụ web và cài đặt chúng trên thiết bị iOS của người dùng trong quá trình cài đặt? Có thể được không? Câu trả lời hay nhất Bạn không có quyền kiểm soát việc cài đặt ứng dụng trên thiết bị của người dùng, do đó không thể tải xuống dữ liệu bổ sung trong quá trình cài đặt. Chỉ cần khởi chạy ứng dụng lần đầu tiên sau khi cài đặt
Sự khác biệt giữa Ứng dụng iOS Enterprise và Ứng dụng bán lẻ iOS
Tôi đã từng phát triển một sản phẩm iOS dành cho doanh nghiệp mà công ty chúng tôi đã bán cho các doanh nghiệp lớn để nhân viên của họ sử dụng. Ứng dụng này có sẵn thông qua AppStore và người dùng doanh nghiệp được cung cấp hồ sơ dành riêng cho công ty (chứa hồ sơ ứng dụng) để cho phép
Tích hợp Card.io ios với bản địa hóa
Tôi đang cố gắng tích hợp SDK Card.io vào ứng dụng iOS của mình. Tôi muốn thực hiện một bản địa hóa đơn giản cho giao diện người dùng CardIO, chẳng hạn như thay đổi tiêu đề nút hủy hoặc văn bản nhắc "Giữ thẻ tín dụng của bạn ở đây". Tôi tìm thấy cái này trên github
ios - Tên quét Card.Io iOS
Tôi đang sử dụng các lớp CardIOView và CardIOViewDelegate và không có BOOL nào có thể được đặt thành CÓ để quét collCardholderName. Tôi có thể thấy nó trong CardIOP
Làm cách nào để đặt trường tên cho ứng dụng ios gốc gần đây? -iOS
Tôi có một ứng dụng voip được tích hợp với bộ công cụ gọi điện. Mỗi lần tôi gọi từ ứng dụng voip của mình, một bản ghi cuộc gọi mới gần đây sẽ được tạo trong ứng dụng điện thoại gốc. Tôi cũng có danh bạ tùy chỉnh trong ứng dụng voip (điện thoại nên
Làm cách nào để ứng dụng iOS biết bàn phím đã ở trên màn hình hay chưa khi ứng dụng đang mở (đa nhiệm iOS)
Làm cách nào để ứng dụng iOS biết đã có bàn phím trên màn hình khi ứng dụng được mở? Sau khi ứng dụng đang chạy, nó có thể nhận được thông báo hiển thị/ẩn bàn phím. Tuy nhiên, nếu ứng dụng được mở dưới dạng ứng dụng phụ ở chế độ chia đôi màn hình và ứng dụng chính đã hiển thị bàn phím thì ứng dụng phụ sẽ không hiển thị
Lỗi IO hình ảnh trên iOS
Tôi gặp lỗi sau trong trình mô phỏng: ImageIO: CGImageReadSessionGetCachedImageBlockData *** CGImageReadSessionGetCachedIm
ios - Thiết bị iOS giao tiếp với các thiết bị không phải iOS
Như được trình bày trong tài liệu của Apple, việc giao tiếp với các phụ kiện được chứng nhận (được Apple chứng nhận) có thể được thực hiện thông qua EAAccessory Framework. Nhưng tôi hơi bối rối vì một số bài đăng cho tôi biết nó cũng hoạt động qua CoreBluetoo
ios - (iOS) Cách xem thông điệp tường trình trực tiếp trên thiết bị iOS?
Mặc dù các trình gỡ lỗi ngày nay rất tốt nhưng đôi khi cách tốt nhất để tìm hiểu những gì đang diễn ra trong ứng dụng của bạn vẫn là NSLog cũ. Việc này thật dễ dàng khi bạn kết nối với máy tính; Xcode sẽ giúp bật lên bảng Log Viewer và bạn đã sẵn sàng. khi bạn không ở nơi làm việc
ios - Kontakt.io iOS - Xác định các cảnh báo theo tên
Trong ứng dụng iOS của tôi, tôi xác định một số điểm ưa thích. Một số trong số chúng có tên là đèn hiệu Kontakt.io, được liên kết với một PoI cụ thể (ý tôi là tên thường được gắn vào nhãn đèn hiệu). Bây giờ tôi muốn khám phá các đèn hiệu gần đó,
Plugin Trigger.io iOS trả về dữ liệu từ cuộc gọi lại
Tôi đang tạo plugin trigger.io để nhận lời nhắc cảnh báo. Cố gắng trả lại dữ liệu từ lời nhắc cảnh báo. Đây là mã của tôi: // Nhắc + (void)show_Prompt:(ForgeTask*)task{
ios - Thông báo đẩy khác nhau như thế nào trong iOS 4, iOS 5 và iOS 6?
Xin chào, tôi mới làm quen với Apple iOS. Mình đã đọc và tìm kiếm rất nhiều bài viết về thông báo đẩy nhưng không tìm thấy thông tin nào về các bản cập nhật mới của APNS từ io4 lên ios 6. Ai có thể cung cấp cho tôi APNS cách thực hiện trong ios không
Chiều cao của UITabBar trên iOS 8, iOS 9, iOS 10 và iOS 11 là bao nhiêu?
Chiều cao của UITabBar dường như đã thay đổi giữa iOS 7 và 8/9/10/11. Tôi đăng câu hỏi này để giúp người khác dễ dàng tìm thấy câu trả lời. Sau đó: iOS 8/9/10/11 trên iPhone và iPad
ios - các phương pháp hay nhất. Làm cho ứng dụng iOS trở nên phổ biến bằng cách hỗ trợ giao diện người dùng iOS 5, iOS 6 và iOS 7
Tôi nghĩ tôi có thể sử dụng các Bảng phân cảnh khác nhau cho các phiên bản iOS khác nhau. Do có sự khác biệt về UI nên mình sẽ tạo Storyboard tiếp theo: Main_iPhone.storyboard Main_iPad.st
Làm cách nào để chọn một phần của bản âm thanh trong ios bằng điều khiển trực quan trong iOS?
Tôi đang viết nội dung nào đó trong đó tôi sẽ sử dụng một phần bản âm thanh từ thư viện iTunes của thiết bị để phủ lên sự kết hợp của 2 video, ví dụ: AVMutableComposition* mixComposition = [[AVMutableC
Tệp tiêu đề tồn tại trong trình mô phỏng iOS nhưng không tồn tại trên thiết bị iOS...?
Tôi đã tạo một chương trình iOS đơn giản có khả năng biên dịch mượt mà và chạy tốt trên trình mô phỏng iPad. Chương trình tương tự không biên dịch được khi tôi yêu cầu XCode 4 sử dụng thiết bị iPad được kết nối của mình. Có vẻ như vấn đề xảy ra khi tôi cố gắng sử dụng iPad kèm theo
Hình dung—gojs có nhiều kinh nghiệm thực tế chia sẻ (3)-6ren
Trực quan hóa - gojs có nhiều chia sẻ kinh nghiệm rất thực tế và rất thực tế (3) - Thư mục 32.go.Palette Hai liên tiếp 33.go.Palette Cách sử dụng cơ bản 34. Tạo kết nối của riêng bạn trỏ đến chính bạn 35. Đặt nhómTemplate và -6ren khác nhau
Thời gian cập nhật: 2024-07-17 13:02:39
32.go.Palette hai liên tiếp
33.go.Palette cách sử dụng cơ bản
34. Tạo kết nối của riêng bạn trỏ đến chính bạn
35. Đặt nhómTemplate và linkTemplate khác nhau
36. Nghe click chuột phải vào GraphObject
37. Xác định menu chuột phải trên nền nút/kết nối/canvas
38. Khi kéo động một kết nối từ một nút, hãy xác định xem hướng của nó là trái hay phải?
Giá trị định tuyến 39.linkTemplate
40. Thay đổi vị trí của tất cả các điểm khi di chuyển kết nối
go.Palette là một thành phần trong thư viện GoJS hiển thị một tập hợp các thành phần đồ họa được xác định trước mà người dùng có thể chọn và kéo và thả vào khung vẽ. Nếu bạn muốn hiển thị hai go.Palette liên tiếp, .
1. Bạn có thể sử dụng HTML và CSS để kiểm soát bố cục của chúng. Sử dụng display: inline-block để sắp xếp các phần tử div theo chiều ngang trong cùng một dòng.
Hình dung—gojs có nhiều kinh nghiệm thực tế chia sẻ (4)-6ren
Trực quan hóa - gojs có nhiều chia sẻ kinh nghiệm thực tế (4) - Mục lục 41. Nghe sự kiện sau khi kéo và thả kết nối hoàn tất 42. Nghe sự kiện sửa đổi canvas 43. Nghe sự kiện gọi lại sau khi nút bị xóa bởi del (dùng để thực hiện giao diện gọi thực hiện một số thao tác xóa Real) 44. Màn hình nút mouse-6ren
Trực quan hóa—gojs có nhiều chia sẻ kinh nghiệm thực tế (4)
Thời gian cập nhật: 2024-07-18 13:10:42
41. Theo dõi các sự kiện sau khi quá trình kéo và thả kết thúc
42. Nghe sự kiện sửa đổi của canvas
43. Nghe sự kiện gọi lại sau khi nút bị xóa bởi del (dùng để thực hiện giao diện gọi để thực hiện một số thao tác xóa thực tế)
44. Nghe các sự kiện di chuyển chuột vào và ra của nút và hiển thị các phần tử cụ thể sau khi di chuột
45. Bản đồ cây nghe thực hiện chức năng mở rộng hoặc thu gọn các nút con bằng cách nhấp vào chính nút đó thay vì nhấp vào nút khác.
46. Nghe sự kiện gọi lại sau khi chỉnh sửa khối văn bản hoàn tất (dùng để triển khai giao diện gọi để thực hiện một số thao tác chỉnh sửa và sửa đổi thực tế)
47. Sau khi soạn thảo văn bản xong, trạng thái chỉnh sửa có thể bị hủy sau khi nhấn Enter
Mô tả các thuộc tính/phương thức được sử dụng:
1. go.LinkingTool.prototype.doActivate
2. thuộc tính có thể định hình lại và phân đoạn lại
3. Vai trò của makeTwoWay trong go.Binding("text", "name").makeTwoWay() mới
4. Cách sử dụng Point cơ bản
5. Hàm dragTool.gridSnapCellSize
6.initialPosition tọa độ ban đầu
7. Sửa đổi kiểu mặc định của nút
8. Phóng to hoặc thu nhỏ, khôi phục và làm lại
9. Tìm các phần tử nút dựa trên các giá trị khóa và tìm các phần bên trong các phần tử
10.toolManager.hoverDelay
Bạn có thể sử dụng công cụ LinkingTool để theo dõi các sự kiện sau khi quá trình kéo kết nối kết thúc. Các bước cụ thể như sau:
Tạo một
Công cụ liên kết
dụ và đặt nó làm công cụ mặc định của biểu đồ:
myDiagram.toolManager.linkingTool = go.LinkingTool mới();
màn hình
doCancel()
doActivate()
Cách thực hiện các thao tác tương ứng sau khi kéo kết nối xong:
myDiagram.toolManager.linkingTool.doCancel = function () { // Sẽ được gọi khi người dùng hủy thao tác kéo và thả liên kết console.log("Đã hủy liên kết"); ; myDiagram.toolManager.linkingTool.doActivate = function () { // Sẽ được gọi là console.log("Liên kết đã hoàn thành"); go.LinkingTool.prototype.doActivate.call(this); };
Trong mọi trường hợp gojs, sẽ có một đoạn mã như vậy. Phương thức myDiagram.addDiagramListener('Modified', function() {...}) được sử dụng để lắng nghe sự kiện sửa đổi của canvas. được sửa đổi, hàm gọi lại tương ứng sẽ được thực thi. Tuy nhiên, phương pháp này không phù hợp để theo dõi liên tục, có nghĩa là nó chỉ có thể được kích hoạt sau khi mỗi sửa đổi được lưu.
// khi tài liệu được sửa đổi, thêm "*" vào tiêu đề và bật nút "Save" myDiagram.addDiagramListener("Modified", function (e) { var Button = document.getElementById("SaveButton"); if ( nút) nút.disabled = !myDiagram.isModified; var idx = document.title.indexOf("*"); console.log(111); if (myDiagram.isModified) { if (idx < 0) document.title += "*"; } else { if (idx >= 0) document.title = document.title.substr(0, idx } }); ;
Nếu bạn muốn theo dõi mọi thay đổi của khung vẽ và thực hiện thay đổi JSON tương ứng, sự kiện này sẽ được kích hoạt mỗi khi mô hình được sửa đổi và bạn có thể lấy dữ liệu JSON mới nhất trong hàm gọi lại. Nếu việc sửa đổi diễn ra thường xuyên và các thao tác tiếp theo phức tạp thì nên thêm một lớp chống rung vào chức năng sửa đổi.
myDiagram.addChangedListener((e) => { //Thực hiện thao tác thay đổi JSON tương ứng var jsonData = myDiagram.model.toJson(); });
Tên sự kiện để xóa các nút là SelectionDeleting. Bạn có thể sử dụng đoạn mã sau để nghe sự kiện xóa một nút và gọi giao diện:
myDiagram.addDiagramListener("SelectionDeleting", (e) => { const đã xóaObj = e.subject.first(); const deleteKey = đã xóaObj.part.data.key; });
Cơ chế xử lý sự kiện của GoJS được sử dụng để thực hiện chức năng hiển thị nút thêm nút khi chuột di chuột vào nút cây. Các bước triển khai cụ thể như sau:
Thêm thành phần nút vào mẫu nút để hiển thị nút thêm nút.
Thêm chức năng xử lý sự kiện di chuột vào mẫu nút. Khi chuột di chuột qua nút, nút thêm nút sẽ được hiển thị.
Thêm chức năng xử lý sự kiện di chuột ra trong mẫu nút. Khi chuột di chuyển ra khỏi nút, nút thêm nút sẽ bị ẩn.
Thêm chức năng xử lý sự kiện nhấp chuột vào mẫu nút thêm nút để thêm nút mới.
myDiagram.nodeTemplate = $( go.Node, "Auto", { mouseEnter: function (e, node) { // Khi chuột di chuột qua nút, nút thêm nút được hiển thị var addButton = node.findObject("addButton ") ; if (addButton) addButton.visible = true; }, mouseLeave: function (e, node) { // Khi chuột di chuyển ra khỏi nút, ẩn nút thêm nút var addButton = node.findObject("addButton"); , $(go.Shape, "RoundedRectangle", { fill: "white" }), $(go.TextBlock, { lề : 8 }, new go.Binding("text", "name")), $( go.Panel, "Horizontal", { căn chỉnh: go.Spot.BottomRight, dòng: 4 }, $( "Button", { name: "addButton",visible: false, click: (e, obj) => {} }, $(go.TextBlock, "+" ) ) ) );
// MyDiagram.addDiagramListener('ObjectSingleClicked', (e, obj) { var part = e.subject.part if (part instanceof go.Node) { if (part .isTreeExpanded ) { part.collapseTree() } else { part.expandTree() } } })
Bạn có thể sử dụng sự kiện TextEdited của lớp DiagramEvent để gọi lại hàm ở cuối quá trình chỉnh sửa văn bản. Sự kiện này được kích hoạt khi trình soạn thảo chỉnh sửa văn bản đã hoàn tất và bị đóng.
myDiagram.addDiagramListener("TextEdited", (e) => { const editText = e.subject.text; const key = e.subject.part.data.key; console.log("Nội dung đã chỉnh sửa: " + editText ) ; console .log("Khóa nút:", khóa });
Theo mặc định, sau khi người dùng chỉnh sửa xong khối văn bản. trình chỉnh sửa trạng thái của khối văn bản đang được chỉnh sửa và phím mặc định được nhấn Enter được coi là ngắt dòng.
Enter, tức là thao tác chỉnh sửa đã hoàn tất chứ không phải thay đổi dòng nên cần thay đổi một thuộc tính. để hoàn tất thao tác chỉnh sửa.
$( go.TextBlock, { editable: true, // Liệu nó có thể được chỉnh sửa hay không isMultiline: false, // Liệu nó có thể là nhiều dòng hay không, false }, new go.Binding("text", "tên") );
Phương thức này sẽ được gọi khi người dùng nhấp vào nút liên kết công cụ hoặc nhấn phím tắt công cụ liên kết.
Thuộc tính có thể định cấu hình lại: Cho biết nút dữ liệu có thể được định cấu hình lại hoặc không thể đặt thành true để có thể cấu hình lại nút. thay đổi hình dạng bằng cách kéo các cạnh hoặc góc.
được đặt thành đúng, kết nối của nút có thể được thêm hoặc xóa bằng cách kéo dài giữa các nút. kết nối của nút sẽ không thay đổi.
Phương thức makeTwoWay được sử dụng để đặt hai chiều liên kết thành liên kết trong GoJS, liên kết đến các liên kết. thuộc tính có mối liên hệ lại trong mô hình dữ liệu với các thuộc tính thuộc tính của đồ họa phần tử, hãy thực hiện khi một thuộc tính được thay đổi trong dữ liệu mô hình thì các thuộc tính của đồ họa phần tử cũng thay đổi tương thích ứng.
Khi bạn sử dụng phương thức makeTwoWay, link sẽ trở thành hai chiều, có nghĩa là khi thuộc tính của phần đồ họa tử tử đã thay đổi, các thuộc tính trong dữ liệu mô hình cũng thay đổi tương ứng. màn hình dữ liệu và đồ họa các phần tử sẽ trở nên thuận tiện và hiệu quả hơn.
Điểm là một lớp trong GoJS được sử dụng để thể hiện một điểm có thể được định nghĩa trên Sản phẩm hai chiều. được tìm thấy trong API GoJS tài liệu.
Trong GoJS, bạn có thể sử dụng go.Point(x, y) mới để tạo một Point đối tượng, trong đó x và y lần biểu tượng bùng nổ độ và độ của điểm. Ví dụ:
var point = go.Point mới(100, 200);
Bạn cũng có thể sử dụng phương thức Point.parse(str) để phân tích một chuỗi thành đối tượng Point.str là một chuỗi biểu tượng mode của một điểm.
var str = "100 200"; var point = go.Point.parse(str);
dragTool.gridSnapCellSize là một trong những thuộc tính thuộc tính của công cụ kéo trong gojs. while hold. bố cục gọn gàng và đẹp mắt hơn. Ví dụ: nếu bạn đặt dragTool.gridSnapCellSize thành 20, phần tử sẽ được kéo dài gắn vào đường viền 20 pixel. lưới.
myDiagram = $(go.Diagram, "myDiagramDiv", { "draggingTool.gridSnapCellSize": new go.Size(1, 5), });
Khi gojs tạo bản vẽ, đồ họa được đặt ở giữa khung vẽ theo mặc định. gojs được bố trí ở giữa. bạn muốn bản vẽ bắt đầu từ góc trên bên trái, bạn có thể:
var myDiagram = $(go.Diagram, "myDiagramDiv", { initPosition: new go.Point(0, 0), // Vị trí thư giãn ban đầu});
$( "Button", { width: 15, Height: 15, "ButtonBorder.fill": "green", // Thay đổi màu thành mặc định _buttonFillOver: "red", // Màu tô khi di chuột // _buttonStrokeOver: " #000", //Màu đường viền di chuột}, $(go.TextBlock, "Nút văn bản") );
// Phóng to myDiagram.scale += 0,1; // Giảm myDiagram.scale -= 0,1; // Khôi phục myDiagram.commandHandler.undo(); // Làm lại myDiagram.commandHandler.redo();
// Tìm các phần tử dựa trên khóa giá trị const node = diagram.findNodeForKey("key value"); // Tìm các phần tử trong phần tử: Tìm các phần có phần tên tử: TEXT và thay đổi màu phông chữ chữ thành màu đỏ node.findObject("TEXT") .đột ngột = "đỏ";
tính toolManager.hoverDelay chuột qua một biểu tượng thành phần.
Nếu it was set to 200, điều đó có nghĩa là sự kiện di chuột sẽ không được kích hoạt khi chuột di chuột qua Đồ họa phần tử trong 200 mili giây.
myDiagram = $(go.Diagram, "myDiagramDiv", { "toolManager.hoverDelay": 200, // delay});
Thời gian địu ToolTip mặc định được hiển thị bằng cách di chuột. Định nghĩa hơi dài.
$( go.TextBlock, { width: 100, maxLines: 1, tràn: go.TextBlock.OverflowEllipsis, }, new go.Binding("text", "name").makeTwoWay(), { toolTip: $("ToolTip ", $(go.TextBlock, new go.Binding("text", "name"))), } );
Nếu bạn muốn biết các bài viết liên quan tôi hy vọng bạn sẽ ủng hộ blog của tôi trong tương lai .
Nâng cao ComfyUI: Plug-in Comfyroll (3)
Cách viết vòng lặp trên Google Earth Engine bằng cách nôn ra máu.
Về cách sử dụng trực tiếp EFCore để thực hiện tạo bản cập nhật khổng lồ, kiểm tra người dùng, đồng thời liên lạc auto, delete phần mềm và truy vấn cây (Phần 1)
CSS: Bố cục linh hoạt (display:flex)
phương pháp công khai thinkphp5 để tải lên hình ảnh và tạo hình thu nhỏ (chia sẻ)
Tiếp theo tải lên mã, liệu có thể viết dưới dạng tệp công khai phổ biến và kế thừa lớp cơ bản để dễ dàng gọi không?
Hướng dẫn đồ họa về thiết lập môi trường máy chủ PHP (chia sẻ)
1. Xây dựng môi trường máy chủ PHP Cài đặt môi trường máy chủ 1.php trọng)\dl_learning\tải xuống các tài nguyên quan trọng\apache
Phím tắt PHPstorm (chia sẻ)
Như được hiển thị bên dưới: Phím tắt Eclipse Ctrl+1 Chỉnh sửa nhanh Ctrl+D: Xóa dòng hiện tại Ctrl+Alt+↓ Sao chép dòng hiện tại tại sang dòng tiếp theo (sao chép và tăng) Ctrl+Alt+↑ Sao chép dòng hiện tại sang dòng trước đó (sao chép và tăng)
Ví dụ về viết ứng dụng giao diện bằng php và trả về dữ liệu json (chia sẻ)
Bước đầu tiên: file conn.PHP, dùng để kết nối với cơ sở dữ liệu và xác định giao diện có định dạng, mã như sau: php" id="highlighter_808731">
Tổng hợp một số câu hỏi phỏng vấn kinh nghiệm bằng ngôn ngữ C trên Linux (chia sẻ)
Bài viết này đã tổng hợp một số câu hỏi phỏng vấn cổ điển về ngôn ngữ C trong Linux. nhiều người hiểu rõ hơn về ngôn ngữ C trong Linux. trình biên dịch GCC để thực hiện chương trình này trên Linux thì kết quả là gì?
Giải quyết nhanh chóng lỗi boost link thư viện (share)
Sau khi cài đặt thư viện Boost mới nhất, có một câu trong hướng dẫn chính thức: Cuối cùng, cài đặt $ ./b2 sẽ để lại các tệp nhị phân Boost trong thư mục con lib/
Ví dụ hoàn chỉnh MyBatis tích hợp mùa xuân (chia sẻ)
Để sắp xếp nội dung của "mybatis tích hợp mùa xuân (maven+mysql) 1" và "mybatis tích hợp mùa xuân (maven+mysql) 2" đã được nghiên cứu trước đó, tôi sẽ làm một ví dụ hoàn chỉnh để hoàn thành một chức năng quản lý thư viện đơn giản .
Mẹo kiểm soát giá trị trang website (chia sẻ)
Chất lượng nội dung website chỉ là một trong số điểm toàn diện của trang, dù thuật toán có thay đổi, điều chỉnh như thế nào thì công cụ tìm kiếm cũng sẽ không loại bỏ điểm toàn diện của trang web. Trong trường hợp thông thường, chúng tôi chia điểm toàn diện của trang thành 8 điểm: 1. Cài đặt tiêu đề (cài đặt tiêu đề phải là duy nhất)
Thông tin cơ bản về Android: Sử dụng các mảnh để thích ứng với các màn hình và độ phân giải khác nhau (Chia sẻ)
Gần đây mọi thứ rất bận rộn, tôi đang gấp rút khởi động một dự án mới, nhưng nhiều chức năng cần phải làm lại. Tôi đang viết mã và gỡ lỗi. Hôm nay, một chương trình mới cần được thực hiện bằng cách sử dụng các mảnh vỡ trước đây, nhưng hôm nay tôi chưa nghiên cứu kỹ về chúng.
Quy ước đặt tên tài nguyên Android (chia sẻ)
Thông số kỹ thuật đặt tên tài nguyên Android Trong những tháng gần đây, có rất nhiều công việc liên quan đến tài nguyên Android. Đối với các ứng dụng phức tạp, quy ước đặt tên tài nguyên là cần thiết. Ngoài các nhà phát triển, các nhà thiết kế giao diện người dùng (hoặc những người liên quan đến việc cắt sơ đồ) cũng cần phải nhận thức rất rõ về nơi sử dụng tài nguyên.
Một số thông tin chi tiết dựa trên bản đồ Mybaits (chia sẻ)
Tôi đã sử dụng Hibernate trước đây và về cơ bản chưa bao giờ sử dụng Mybatis. Tôi cần tạo các mối quan hệ ánh xạ tại nơi làm việc. Cả hai đều hỗ trợ một-một, một-nhiều và nhiều-nhiều. Chương này giới thiệu ngắn gọn cách sử dụng một-một và những điểm cần lưu ý.
Thảo luận ngắn gọn về phạm vi của các kiểu dữ liệu cơ bản trong java (chia sẻ)
Như được hiển thị bên dưới: ? 1
Chia sẻ phương pháp thiết lập bố cục View to FrameLayout tùy chỉnh của Android để hiện thực hóa hiển thị đa thành phần
Nếu bạn muốn hiển thị Button và các thành phần View khác trên View tùy chỉnh, bạn cần hoàn thành các tác vụ sau 1. Ghi đè xây dựng lớp cha trong lớp View tùy chỉnh (lưu ý là 2 tham số Sao chép mã như sau). : quán rượu
Ví dụ về triển khai kéo bảng tr trong java (share)
Chức năng thực hiện: thực hiện kéo bảng tr và lưu mức độ thay đổi do kéo mã jsp?
Bản demo đơn giản về Hẹn giờ và Hẹn giờ của Java (chia sẻ)
Mã: lớp kiểm tra java" id="highlighter_819000">?
Dựa trên nguyên tắc hoạt động chèn cây đỏ đen và phương pháp triển khai java (chia sẻ)
Cây đỏ là cây tìm kiếm cân bằng nhị phân. or black.
Demo dom4j vận hành xml (chia sẻ)
Không còn dòng dài nữa, hãy đi thẳng vào mã 1?
Mẹo cho phép chỉ định mức tối đa và tối thiểu trong Python (chia sẻ)
Khi mã hóa, nhân đôi khi bạn cần chỉ định các giá trị riêng theo phép so sánh kích thước: ?
Hướng dẫn cài đặt và sử dụng Git (chia sẻ)
Trong quá trình phát triển dự án thực tế, chúng tôi thường sử dụng một số phiên bản điều khiển để lưu trữ Hôm nay, chúng tôi sẽ tắt cách sử dụng Git có liên quan. trên github thông qua Git 1. Tải xuống và cài đặt Git 1. Tải xuống
Một lớp mã xác minh php đẹp (chia sẻ)
Tải trực tiếp mã hóa lên: Sao chép mã như sau: //Mã xác minh lớp lớp ValidateCode { Private $charset = 'abcdefghkmnprstuvwxyzABC
Cách lấy apple uid an toàn, imei-6ren
Cách lấy udid của Apple một cách an toàn, imei-[Nhấp để kiểm tra https://authapi.applekuid.com](https://authapi.applekuid.com/) Có nhiều cách để lấy udid ở Trung Quốc, ví dụ như Dandelion và các nơi khác trên web -6ren
Cách lấy apple uid, imei an toàn
Thời gian cập nhật: 2024-07-20 11:00:42
[Nhấp để kiểm tra https://authapi.applekuid.com](https://authapi.applekuid.com/) .
Hiện tại, có nhiều cách để lấy udid ở Trung Quốc. Về cơ bản bản văn, họ có thể vượt qua quá trình xác thực thông tin để ngụy trang để chắc chắn rằng thiết bị đó có thật.
## Làm thế nào để Apple có được sự thực sự đúng đắn?
Không có dưới một bài viết được tìm kiếm trên Baidu, nhưng không có bài nào an toàn hoặc có thể nói là an toàn để ngăn chặn udid giả.
1. Hướng dẫn người dùng cài đặt udid mô tả tệp 2. Sau khi cài đặt Đặt mô tả tệp, điện thoại di động sẽ gửi mẫu imei udid và các thông tin khác đến máy chủ.
Nhưng làm sao bạn biết nó đúng hay sai?
##Làm sao để biết nó đúng hay sai?
Rất tiếc, hiện tại không có phần mềm nào trên thị trường. Có nhiều phần mềm ngụy trang udid. sửa đổi thông tin qua phần mềm fiddler và nhiều phần mềm khác được duy trì bởi một số nhóm mà không có tác dụng gì.
Thực sự không thể ngăn chặn việc ngụy trang sao?
##Thật sự không thể ngăn chặn việc ngụy trang sao?
Tiếp theo, chúng ta hãy thử xem xét các phương pháp phổ biến để lấy uid.
1. Chuẩn bị Apple .mobileconfig mô tả tệp.
```.

Nội dung tải trọng
URL
http://xxx/app/uuid
Thiết bị thuộc tính
UDID
IMEI
ICCID
PHIÊN BẢN
SẢN PHẨM
Tổ chức tải trọng
www.yun-bangshou.com
Tên hiển thị tải trọng
xxx
Phiên bản tải trọng
Tải trọngUUID
8C7AD0B8-3900-44DF-A52F-3C4F92921807
Mã định danh tải trọng
com.yun-bangshou.profile-service
Mô tả tải trọng
Lấy số UDID của thiết bị iOS hiện tại
Loại tải trọng
Profile service
``` .
2. Đặt tệp trên web máy chủ.
3. Hướng dẫn tải liên kết người dùng.
4. Sau khi người dùng cài đặt thiết bị, thiết bị sẽ gửi thiết bị thông tin http://xxx/app/uu toid.
```
12 123456 123456 7
iPhone4,1
b59769e6c28b73b1195009d4b21cXXXXXXXXXXXX
9B206
Nhưng chỉ thế thôi là chưa đủ.
## Lấy nó có thực sự an toàn không?
Bằng cách chụp gói tin ([https://authapi.applekuid.com](https://authapi.applekuid.com/)) được yêu cầu 4 lần và cơ sở dữ liệu đã được mã hóa.
Cuối cùng, bài viết về cách lấy Apple uid và imei một cách hoàn toàn cuối cùng tại đây. cách an toàn, vui lòng tìm kiếm bài viết CFSDN hoặc tiếp tục duyệt các bài viết liên quan blog tương lai!
Kiến trúc máy ảo tuyệt vời-AQ
Wails phát triển khai bot Tencent Yuanqi
12 công cụ không mã nguồn mở hàng đầu theo số Sao GitHub
Xây dựng một Applet tâm lý dựa trên JavaSpringBoot và Uniapp: Hướng dẫn đầy đủ từ 0 đến 1
c# - task no clock
Đã nhận VS HttpResponseMessage Đã nhận
Tôi cần sự giúp đỡ của bạn với những điều sau đây. một tháng. và tất cả chúng đều hoạt động như mong đợi: public Htt
Không thể lấy URI từ URL, nhận giá trị rỗng?
Tôi có mẫu tệp (.xls) trong tệp thực thi của mình. (Sẽ được thêm vào sau).
javascript - Mô hình thu thập nguyên mẫu (nguyên mẫu) của Backbone so với thu thập xương sống
Tôi đang xem mô hình mã hóa của trang web và có câu hỏi về nguyên mẫu. đây...define([], function () { "sử dụng
javascript - Bắt ScrollTop, got offsetHeight và getStyle mất nhiều thời gian
Ba thao tác hàng đầu ảnh hưởng đến hiệu suất của tôi là: Nhận thanh cuộn Nhận chiều cao bù trừ Ext.getStyle Để giải thích tôi đang làm việc Hết mọi thứ nội dung của mạng, nó sẽ hoạt động
Nhận URL tham số chức năng, nhận giá trị của url phần hoặc trả về true nếu có nhưng không có giá trị?
URL. hàm gup(tên, url) { name = name.replace(/[\[]/, '\\\[').replace(/[\]]/ ,
c - MacOS sử dụng sysctl() để lấy HW_MACHINE_ARCH để nhận "không có tệp hoặc thư mục như vậy"
HW_MACHINE_ARCH. Tôi đang sử dụng HW_MACHINE, tôi cũng nghĩ vậy
Cung cấp (đưa) kênh YouTube của tôi vào ứng dụng iOS của tôi
đóng cửa. Câu hỏi này không tuân thủ các nguyên tắc của Stack Overflow. Hiện tại nó không chấp nhận câu trả lời. Đóng cửa 9 năm trước Các câu hỏi yêu cầu mã phải thể hiện sự hiểu biết tối thiểu về vấn đề đang được giải quyết. Bao gồm các giải pháp đã thử và tại sao
webpack: Cách lấy JavaScript từ "bower_comComponents" thay vì "node_modules"
Vì sử dụng main-bower-files như một phần của tác vụ biên dịch bằng Gulp, nên tôi không thể sử dụng webpack trong node_modules để yêu cầu module code> dir vì tôi sẽ làm rối mã
Javascript - Nhận "mon" từ "Thứ Hai" hoặc "thứ ba" từ "Thứ Ba", v.v.
đóng cửa. Câu hỏi này cần tập trung hơn. Hiện tại nó không chấp nhận câu trả lời. Bạn muốn cải thiện câu hỏi này? Đã cập nhật câu hỏi để tập trung vào một vấn đề chỉnh sửa bài đăng này Đã đóng 5 năm trước. Cải thiện câu hỏi này
Java: Không thể áp dụng Gridlayout cho Jscrollpane. Nhận java.lang.ClassCastException
Tôi đang sử dụng Gridlayout để đặt 4 phần tử liên tiếp. Đầu tiên, tôi có JPanel và mọi thứ đều hoạt động tốt. Đối với những trường hợp số lượng hàng ngày càng lớn và tôi phải cuộn xuống, tôi đã thực hiện một số thay đổi đối với nó. Bây giờ tôi đã thêm J vào JPanel của mình
python — Cách lấy VolumeId từ khóa BlockDeviceMappings (boto3 lấy thông tin về âm lượng ec2)
Tôi muốn lưu giá trị của VolumeId vào một biến vì những lý do sau: #!/usr/bin/env python import boto3 import json import argparse import
Angularjs - Không sử dụng AcacquiTokensilent để nhận mã thông báo mà sử dụng trình duyệt Msal AcacquiTokenpopup để nhận mã thông báo
Tôi đang cập nhật MSAL phiên bản 1.x lên trình duyệt MSAL cho Angular. Vì vậy, tôi đang cố gắng di chuyển từ phiên bản 1.x sang 2.XI và đã có thể thay thế mã thành công và nó hoạt động tốt. Nhưng tôi đã gặp có đượcT
python - Lấy mức trung bình của Pandas bằng GroupBy - Lấy DataError: Không có loại số nào để tổng hợp -
Tôi biết có rất nhiều câu hỏi về vấn đề này như Lấy số trung bình hàng ngày với gấu trúc và Làm thế nào để lấy giá trị trung bình hàng tháng của gấu trúc bằng cách sử dụng nhóm nhưng tôi đã gặp phải
Không thể lấy DATETIME từ QueryString trong phương thức mvc getController (từ Uri())
Đây là chuỗi truy vấn mà tôi nhận được trong URL đầu ra: /demo/analysis/test?startDate=Sat+
ubuntu - Tải Geoserver từ OpenLayer 3 nhận '500 (Lỗi máy chủ nội bộ)'
Tôi đang cố gắng truy cập lớp Geoserver var gkvrtWmsSource =new ol.source.ImageWMS({ u
javascript - Nhận thông tin API Ecobee bằng XMLHttpRequest. Nhận 500 (Lỗi 1: "Xác thực không thành công. Cần có mã thông báo.")
API yêu cầu tiêu đề chứa mã ủy quyền. Đây là những gì tôi có cho đến nay: var fullUrl = 'https://api.ecobee.com/1/thermostat?json=\{"s
c# - Nhận/xóa ký tự cuối cùng của tệp mà không tải vào bộ nhớ
Làm cách nào tôi có thể lấy ký tự cuối cùng trong một tệp và nếu đó là một ký tự nhất định, hãy xóa nó mà không tải toàn bộ tệp vào bộ nhớ? Đây là những gì tôi có hiện tại. sử dụng (var fileStream = new FileStream("file.t
JSP lấy/đặt tham số của toàn bộ đối tượng
Tôi mới tham gia cộng đồng này và nghĩ ra câu hỏi đầu tiên của mình. Tôi đang làm việc với JSP và tôi đã tạo thành công các Trang web JSP đang sử dụng jsp:setParameter và jsp:getParameter bằng một chuỗi duy nhất.
đa luồng - thu thập/giải phóng ngữ nghĩa
Để trả lời cho việc sắp xếp lại StoreStore xảy ra khi biên dịch C++ cho x86 @Peter Cordes đã viết For Acquire/Release se
javascript - Nhận kết quả của các hàm được sử dụng trong .on
Tôi có một hàm, hãy gọi nó là X1, hàm này trả về biến Y. Hàm này được sử dụng trong hành động .on("focusout", X1). Làm thế nào để có được biến Y? Kết quả của X1 sau khi thực thi .on là gì? Câu trả lời hay nhất Bạn có thể thay đổi phạm vi của Y để nó nằm trong hàm
rên rỉ thực hiện Tencent Yuanqi bot-6ren
Wails triển khai bot Tencent Yuanqi - một mô-đun của công cụ ghi âm đơn giản. Lệnh gọi API phụ trợ được đăng nhập vào Tencent Yuanqi để tạo đại lý. Bạn có thể tạo nó theo nhu cầu của riêng mình và chờ xem xét sau khi xuất bản. Sau khi phát hành xong, hãy nhấp để gọi api. Tại đây bạn có thể thấy user_id,-6ren.
Thời gian cập nhật: 2024-07-20 11:02:42
Một mô-đun cho các công cụ ghi nhật ký đơn giản.
phía sau
Lệnh gọi API
Sau khi đăng nhập vào Tencent Yuanqi, hãy tạo một đại lý và tạo nó theo nhu cầu của riêng bạn. Sau khi xuất bản, bạn phải chờ xem xét.
Sau khi phát hành xong, hãy nhấp để gọi api. Tại đây, bạn có thể xem các thông số user_id, Assistant_id và mã thông báo.
Sử dụng thư viện được đóng gói github.com/chenmingyong0423/go-yuanqi để gọi API. Theo cách sử dụng bản demo (ở đây, tương tác API không phát trực tuyến được sử dụng làm ví dụ), bạn nên chú ý đến một thay đổi ban đầu. chat.Chat() Đối với chat.Session() (bản demo của tác giả chưa kịp cập nhật), cụ thể như sau:
gói nhập chính ( "context" "fmt" "github.com/chenmingyong0423/go-yuanqi" "log" "time" ) /** * @Author Lockly * @Description * @Date 2024/7/1 **/ func main() { trò chuyện := yuanqi.NewChat("assistant_id", "user_id", "token", yuanqi.WithAssistantVersion(""), yuanqi.WithTimeOut(10*time.Second)) // Điền các thông số trên theo thứ tự := chat.Session().WithStream(false).WithChatType("published") textContent := yuanqi.NewContentBuilder().Text("hi").Build() // Tin nhắn hình ảnh yêu cầu phải bật plug-in nên tin nhắn không được sử dụng := yuanqi.NewMessageBuilder(). Vai trò("người dùng"). Nội dung(textContent).Build() resp, err := session.AddMessages(message).Request(context.Background()) if err != nil { log.Fatal (err) } // Nếu bạn chỉ muốn nhận câu trả lời của ai fmt.Println(resp.Choices[0].Message.Content) }
Chỉ cần gói gọn nó, chuyển câu hỏi để nhận câu trả lời và ba tham số trên được lấy từ cấu hình. Nói một cách đơn giản, hãy xác định phương thức trong wails' app.go (giống như các phương thức đã đăng ký khác). Sau khi bắt đầu dòng lệnh wails dev, wailsjs sẽ tự động được thêm vào để gọi giao diện người dùng.
Chỉ cần xác định ngắn gọn:
func (a *App) ChatWithAI(chuỗi nội dung, config *share.Config) chuỗi { resp, err := service.Chat(content, a.config) if err != nil { log.Logger.Error("ERR Nhận AI Trả lời không thành công") return err.Error() } return resp }
giao diện người dùng
giao diện
Để gọi giao diện người dùng, hãy nhập {ChatWithAI} từ "../../../wailsjs/go/cli/App"; sau đó hiển thị thành phần giao diện người dùng đơn giản. Để định cấu hình, bạn có thể thêm một trang (Khung phương thức). và ngăn kéo có thể được sửa đổi) và những thứ cần thiết khác có thể được thêm vào nếu cần.
Cấu hình
Lưu
Xóa
❗Hiện chỉ hỗ trợ Tencent Yuanqi
Màn hình trò chuyện sử dụng thành phần n-log, được sử dụng để hiển thị nhật ký và đẩy các câu hỏi cũng như câu trả lời. Điều quan trọng là hỗ trợ đánh dấu.
Xác định const msg ở đây: string[] = []; const chatData = ref(showMsg('', false)). Hàm showMsg chỉ cần đẩy nội dung vào msg rồi thêm \n dòng mới để hiển thị thông báo. Xử lý các điểm nổi bật.
Điểm nổi bật
Không có highlight.js tích hợp trong ui ngây thơ, vì vậy trước khi sử dụng nó, bạn cần giới thiệu import hljs from 'highlight.js/lib/core' và đặt trước:
Có một số ngôn ngữ được tích hợp trong hljs, nhưng nó không hoạt động khi tôi thử. Ví dụ: đăng ký markdown và sau đó sử dụng markdown trong n-log. Khi mã được ai trả lời sử dụng cú pháp markdown ```` để tải. mã, nó sẽ không được đánh dấu, điều tương tự không hoạt động với ngôn ngữ tương ứng.
nhập markdown từ 'highlight.js/lib/linguage/markdown' hljs.registerLanguage('markdown ', markdown )
Tuy nhiên, các ví dụ được cung cấp trên trang web chính thức là các ngôn ngữ được tùy chỉnh để thực hiện các chức năng tương ứng, chẳng hạn như làm nổi bật tất cả các số:
nhập hljs từ 'highlight.js/lib/core' hljs.registerLanguage('naive-log', () => ({ contains: [ { className: 'number',begin: /\d+/ } ] }))
Tương tự, bạn có thể sử dụng tính năng khớp thông thường để khớp các ký tự để đặt các danh mục nhằm điều chỉnh kiểu, chẳng hạn như tiếng Trung và tiếng Anh cũng như các ký hiệu tôi muốn đánh dấu các đoạn hội thoại ở đây»:
hljs.registerLanguage('naive-log', () => ({ contains: [ { className: 'number',begin: /\d+/ }, { className: 'chinese',begin: /[一-饥]/ , // Phạm vi ký tự tiếng Trung (Phạm vi mã hóa Unicode) mức độ liên quan: 10 }, { className: 'english', Begin: /[A-Za-z]/, mức độ liên quan: 0 }, { className: 'bot',begin: /[\w\s]+»\s*/, // Khớp bất kỳ từ nào, dấu cách cho đến » theo sau là mức độ liên quan của dấu cách: 1, }, ] }))
ClassName ở đây có thể được xác định một cách ngẫu nhiên, miễn là nó dễ phân biệt và sau đó xác định nó trong style.css trong wails: (Những cái mới khác có thể được thêm vào bên dưới).
.n-code, .n-layout-content, .n-layout-header, .n-layout, .terminal .t-window { font-family: "Giao diện người dùng Microsoft YaHei", system-ui } .n-code; .hljs-attr, .n-code .hljs-biến, .n-code .hljs-template-biến, .n-code .hljs-type, .n-code .hljs-selector-class, .n-code .hljs-selector-attr, .n-code .hljs-selector-pseudo, .n-code .hljs-number { color: # 078585; họ phông chữ: "Giao diện người dùng Microsoft YaHei", system-ui } .n-code; .hljs-log-info {color: #25c9ab;} .n-code .hljs-log-debug {color: #13778a;} .n-code .hljs-log-error {color: #931023;} .n- mã .hljs-log-warn {color: #0d705e;} .n-code .hljs-chinese {color: rgba(19, 19, 19, 0.89);} .n-code .hljs-english {color: rgba(31, 32, 33, 0.89);} .n-code .hljs-bot {color: #11c5a4;}
Cuối cùng, thêm một hộp đầu vào và hai nút. Hộp đầu vào đặt thuộc tính @keydown.enter="send" và nhấn Enter để kích hoạt phương thức gửi. Phương thức này được sử dụng để gọi ChatWithAI trước đó. có thể được hiển thị trong hộp nhập và nhật ký. Cả hai đều đặt thuộc tính :loading để chờ tải và hộp nhập phải bị tắt trong thời gian chờ.
Hiệu ứng cuối cùng như sau (mã hoàn chỉnh sẽ được mở nguồn sau):
Cuối cùng, bài viết về việc triển khai bot Tencent Yuanqi của Wails kết thúc tại đây. Nếu bạn muốn biết thêm về việc triển khai bot Tencent Yuanqi của Wails, vui lòng tìm kiếm bài viết CFSDN hoặc tiếp tục duyệt các bài viết liên quan. blog tương lai! .
[rCore Study Notes 016] Triển khai ứng dụng
vue.js - go get wails không được cài đặt đúng cách
Đã thử sử dụng...golang và wails...nhưng sau này...hãy truy cập github.com/wailsapp/wails/cmd/wails Tôi hiểu rồi. ../../github.com/w
go - Nguyên nhân gây ra lỗi "no such file: mshtmhst.h" khi sử dụng Wails trên Windows?
Tôi đang cố gắng sử dụng Wails trên máy Windows nhưng tôi nhận được: Trong tệp được bao gồm từ C:\Go\external\pkg\mod\github.com\wailsapp\wa
Kiến trúc bộ nhớ máy ảo tuyệt vời-AQ-6ren
Kiến trúc bộ nhớ máy ảo tuyệt vời-AQ-Liên kết nguồn: https://www.axa6.com/zh/an-excellent-virtual-machine-memory-architecture Giới thiệu Kiến trúc bộ nhớ máy ảo ảnh hưởng trực tiếp đến hiệu suất của máy ảo và- 6 nhân
Thời gian cập nhật: 2024-07-20 12:58:41
Liên kết nguồn: https://www.axa6.com/zh/an-excellent-virtual-machine-memory-architecture.
Kiến trúc bộ nhớ máy ảo ảnh hưởng trực tiếp đến hiệu suất và khả năng chiếm dụng của máy ảo. Thiết kế một kiến trúc xuất sắc có thể cải thiện hiệu suất và hiệu quả một cách hiệu quả. Bài viết này sẽ giới thiệu kiến trúc bộ nhớ được sử dụng bởi máy ảo AQ và các tiêu chuẩn chi tiết về bộ nhớ máy ảo AQ. Bằng cách tối ưu hóa kiến trúc bộ nhớ máy ảo, nó giúp máy ảo chạy hiệu quả hơn và giảm chiếm dụng. Nếu có thể, bạn nên cân bằng cả hai càng nhiều càng tốt để máy ảo của bạn đạt được hiệu suất tốt nhất.
Trong một số trường hợp, việc phát triển phải được thực hiện khác nhau tùy theo nhu cầu đặc biệt của máy ảo. Ví dụ: Trong trường hợp bộ nhớ hạn chế như vi điều khiển, cần giảm chiếm dụng càng nhiều càng tốt. Trong các tình huống nhạy cảm về hiệu suất như tính toán song song, bạn cần tập trung vào việc tối ưu hóa hiệu suất.
ý tưởng thiết kế
kiến trúc bộ nhớ
Kiến trúc bộ nhớ cơ bản
AQ áp dụng kiến trúc bộ nhớ cơ bản của các thanh ghi, nhưng nó khác với kiến trúc thanh ghi tiêu chuẩn và đã thực hiện một số cải tiến và tối ưu hóa đối với kiến trúc thanh ghi.
Các thanh ghi ở đây không phải là các thanh ghi trong CPU mà là các thanh ghi ảo được mô phỏng trong bộ nhớ.
Lý do chọn đăng ký
So với các máy ảo ngôn ngữ chính thống như JAVA và Python, sử dụng kiến trúc ngăn xếp, lý do AQ quyết định áp dụng kiến trúc đăng ký là để tối ưu hóa hiệu suất và làm cho mã byte dễ hiểu hơn. Mặc dù kiến trúc ngăn xếp thường được coi là dễ chuyển và ghi hơn, nhưng sẽ có một số tổn thất về hiệu suất thực tế và việc truy cập nhiều lần vào bộ nhớ sẽ làm chậm nó, điều này là không thể tránh khỏi và khó tối ưu hóa hoàn toàn. Do đó, để giải quyết tình trạng giảm hiệu suất ở đây, AQ áp dụng kiến trúc đăng ký. Đồng thời, từ góc độ mã byte, mã byte của kiến trúc thanh ghi dễ hiểu hơn và các hướng dẫn của nó tương tự như phương thức tham số của hàm, thay vì trực tiếp đối mặt với nhiều thao tác của ngăn xếp.
đăng ký
Sự khác biệt về kiến trúc
Kiến trúc thanh ghi tiêu chuẩn
Trong kiến trúc thanh ghi tiêu chuẩn, các thanh ghi bao gồm:
kiểu dữ liệu
- Kiểu dữ liệu mà thanh ghi sẽ lưu trữ (chẳng hạn như int, float, double, v.v.)
dữ liệu
- Giá trị của dữ liệu mà thanh ghi sẽ lưu trữ
(tùy chọn) thẻ - Thẻ cho dữ liệu mà thanh ghi sẽ lưu trữ (ví dụ: biến, hàm, lớp, v.v.)
(tùy chọn) tham chiếu - tham chiếu đến dữ liệu mà thanh ghi sẽ lưu trữ (chẳng hạn như địa chỉ của một đối tượng, v.v.)
Mặc dù kiến trúc bộ nhớ của máy ảo ở các ngôn ngữ khác nhau có thể khác nhau nhưng thông tin này thường được lưu trữ.
Kiến trúc này đã được sử dụng trong quá trình phát triển AQ, nhưng sau khi thử nghiệm, nó chiếm một lượng lớn bộ nhớ.
Sau đây là mã register.h được AQ sử dụng:
// Bản quyền của tác giả AQ 2024, Mọi quyền được bảo lưu. // Chương trình này được cấp phép theo Giấy phép AQ. Bạn có thể tìm thấy giấy phép AQ trong // thư mục gốc. { // VIỆC CẦN LÀM(Đăng ký): Đang chờ sự cải thiện của sổ đăng ký. sự đoàn kết AqvmMemoryRegister_Value { // TODO(Register): Đang chờ cải thiện thanh ghi. const int int_value; const int const_int_value; const float const_float_value; const double long_value; const_character_value; boolean_value; const bool const_boolean_value }; struct AqvmMemoryRegister_Register { enum AqvmMemoryRegister_ValueType; liên kết giá trị AqvmMemoryRegister_Value };
Như có thể thấy từ đoạn mã trên, ngay cả khi chỉ giữ lại nội dung cần thiết, vì kiểu enum AqvmMemoryRegister_ValueType chiếm 4 byte và kiểu kết hợp AqvmMemoryRegister_Value chiếm 8 byte, nên bản thân kiểu cấu trúc sẽ chiếm 12 byte bộ nhớ.
Đồng thời, do tối ưu hóa trình biên dịch C, kiểu enum trong kiểu cấu trúc AqvmMemoryRegister_Register là bộ nhớ được căn chỉnh theo giá trị kiểu kết hợp, do đó 4 byte bộ nhớ đệm được thêm vào. Đặt AqvmMemoryRegister_Register thuộc loại cấu trúc chiếm 16 byte.
Nếu bạn sử dụng loại không phải 8 byte như int, 4 byte bộ nhớ đệm sẽ bị lãng phí, dẫn đến mất bộ nhớ. Vì vậy sẽ có 4-8 byte bộ nhớ bị lãng phí trong tất cả các thanh ghi.
AQ
Cấu trúc thanh ghi của
Để giải quyết vấn đề chiếm chỗ của kiến trúc thanh ghi truyền thống, AQ kết hợp các đặc điểm bảng biến cục bộ của khung ngăn xếp JVM và tối ưu hóa kiến trúc bộ nhớ, giảm đáng kể vấn đề chiếm chỗ.
Sau đây là ba lựa chọn thay thế:
// kế hoạch 1: struct AqvmMemoryRegister_Register{ uint8_t type; void* value_ptr; }; void* value; AqvmMemoryRegister_Register array[]; // kế hoạch 2: giá trị void*; 0 cho chỉ số 1 là // float, v.v. size_t type[] // plan 3: struct AqvmMemoryRegister_Register { giá trị uint32_t*; kích thước size_t };
Do con trỏ chiếm 4-8 byte nên bản thân dữ liệu cũng chiếm 1-8 byte, cộng với byte loại 1 nên phương án 1 chiếm 6-17 byte và có thể có sự căn chỉnh bộ nhớ nên phương án 1 cũng sẽ gây ra sự mất bộ nhớ rất lớn. . Trên thực tế, khi cần lưu giữ thông tin loại bộ nhớ, gói 2 có mức sử dụng bộ nhớ cao nhất, nhưng gói 2 không thể duy trì sự gắn kết của các loại dữ liệu khác nhau trong cùng một cấu trúc dữ liệu (chẳng hạn như cấu trúc), điều này có thể làm mất hiệu lực một số con trỏ. hoạt động. Do đó, kế hoạch 2 không được sử dụng để đảm bảo an toàn cho bộ nhớ. Trong một số trường hợp (tập lệnh máy ảo bao gồm các loại), phương án 3 cũng có thể đáp ứng nhu cầu lưu trữ bộ nhớ, nhưng do nhu cầu tập lệnh rút gọn nên thông tin loại không có trong hướng dẫn nên không thể đáp ứng được nhu cầu. hoạt động của máy ảo.
Do đó, chúng tôi áp dụng thiết kế sau để đảm bảo sử dụng bộ nhớ và cải thiện đáng kể vấn đề sử dụng bộ nhớ.
Bộ nhớ của AQ trực tiếp sử dụng con trỏ void* để lưu trữ dữ liệu, bộ lưu trữ size_t chiếm kích thước bộ nhớ và sử dụng kiểu lưu trữ mảng uint8_t. Vì uint8_t chiếm 8 bit nên để giảm dung lượng chiếm chỗ, 4 bit được sử dụng cho mỗi byte để lưu trữ loại. Do đó, một biến uint8_t có thể lưu trữ 2 loại. 4 bit đầu tiên của mỗi biến uint8_t được sử dụng cho loại byte chẵn và 4 bit cuối cùng được sử dụng cho loại byte lẻ.
// Cấu trúc lưu trữ thông tin về bộ nhớ. // |type| là một con trỏ tới một mảng lưu trữ kiểu của mỗi byte trong bộ nhớ //. Mỗi byte sử dụng 4 bit để lưu trữ kiểu này. / lưu trữ 2 loại. 4 bit đầu tiên của biến uint8_t được sử dụng cho loại byte chẵn và 4 bit tiếp theo được sử dụng cho loại byte lẻ. |data| là một con trỏ kiểu void* tới bộ nhớ lưu trữ dữ liệu // |size| là kích thước của bộ nhớ. // LƯU Ý: Cấu trúc AqvmMemory_Memory chỉ lưu trữ thông tin của bộ nhớ. bởi hàm bytecode khi lưu trữ bytecode. // Bộ nhớ của |memory| và |type| là một phần của dữ liệu bytecode struct AqvmMemory_Memory { uint8_t* void*; kích thước size_t;
Vì lý do bộ nhớ, việc truy cập kiểu yêu cầu sử dụng chính xác. Loại uint8_t yêu cầu 8 bit, nhưng nó vượt quá nhu cầu lưu trữ của loại, vì vậy 4 bit không chỉ có thể đáp ứng nhu cầu lưu trữ của loại mà còn giảm mức sử dụng bộ nhớ. Nhưng cần có các chức năng đặc biệt để duy trì quyền truy cập kiểu.
// Đặt loại dữ liệu tại |index| byte trong |memory| thành |type|. // phải nhỏ hơn 4 bit. Trả về 0 nếu thành công. . Trả về -2 // nếu con trỏ kiểu là NULL. Trả về -3 nếu chỉ mục nằm ngoài phạm vi. Trả về // -4 nếu kiểu nằm ngoài phạm vi. Bộ nhớ AqvmMemory_Memory*, chỉ mục size_t, loại uint8_t) { if (bộ nhớ == NULL) { AqvmRuntimewindow_OutputReport("\"ERROR\"", "\"AqvmMemory_SetType_NullMemoryPointer\"", "\"Con trỏ bộ nhớ là NULL.\"", NULL); trả về -1; } nếu (bộ nhớ->loại == NULL) { AqvmRuntimewindow_OutputReport("\"ERROR\"", "\"AqvmMemory_SetType_NullTypePointer\"", "\"Con trỏ loại là NULL.\"", NULL return -2 }; (chỉ mục > bộ nhớ-> kích thước) { AqvmRuntimewindow_OutputReport( "\"ERROR\"", "\"AqvmMemory_SetType_OutOfMemoryRange\"", "\"Chỉ mục nằm ngoài phạm vi bộ nhớ.\"", NULL); return -3; } if (type > 0x0F) { AqvmRuntimewindow_OutputReport("\ "LỖI\"", "\"AqvmMemory_SetType_OutOfTypeRange\"", "\"Loại nằm ngoài phạm vi.\"", NULL); return -4; } // Đặt loại dữ liệu tại |index| byte trong bộ nhớ. // Vì Aqvm lưu trữ dữ liệu loại chiếm 4 bit và uint8_t. chiếm 8 bit, // mỗi vị trí loại uint8_t lưu trữ hai loại dữ liệu. // (4 bit cao, 4 bit thấp) được đặt theo tính chẵn lẻ của |index|. các bit cao của (|index| / 2) và số lẻ được // lưu trữ trong các bit thấp của (|index| / 2). = (bộ nhớ->loại [chỉ mục / 2] & 0xF0) | loại; } else { bộ nhớ->loại [chỉ mục / 2] = (bộ nhớ->loại [chỉ mục / 2] & 0x0F) | (type << 4); } return 0; } // Lấy loại dữ liệu tại |index| byte trong |memory|. // Trả về loại nhỏ hơn 4 bit (0X0F) nếu thành công. / nếu con trỏ bộ nhớ là NULL. Trả về 0x12 nếu con trỏ loại là NULL // Trả về 0x13 nếu chỉ mục nằm ngoài phạm vi bộ nhớ uint8_t. AqvmMemory_GetType(struct AqvmMemory_Memory* bộ nhớ, chỉ mục size_t) { if (bộ nhớ == NULL) { AqvmRuntimewindow_OutputReport("\"ERROR\"", "\"AqvmMemory_GetType_NullMemoryPointer\"", "\"Con trỏ bộ nhớ là NULL.\"", NULL); trả về 0x11 } nếu (bộ nhớ->loại == NULL) { AqvmRuntimewindow_OutputReport("\"ERROR\"", "\"AqvmMemory_GetType_NullTypePointer\"", "\"Con trỏ loại là NULL.\"", NULL trả về 0x12; chỉ mục > bộ nhớ-> kích thước) { AqvmRuntimewindow_OutputReport( "\"ERROR\"", "\"AqvmMemory_GetType_OutOfMemoryRange\"", "\"Chỉ mục nằm ngoài phạm vi bộ nhớ.\"",NULL); return 0x13; } // Lấy loại dữ liệu tại |index| byte trong bộ nhớ // Vì Aqvm lưu trữ loại dữ liệu chiếm 4 bit và uint8_t chiếm 8 bit, // mỗi vị trí loại uint8_t lưu trữ hai loại dữ liệu. Các vị trí lưu trữ // (4 bit cao, 4 bit thấp) được đặt theo tính chẵn lẻ của |index|. 2) và các số lẻ được // lưu trữ ở các bit thấp của (|index| / 2). if (index % 2 != 0) { return Memory->type[index / 2] & 0x0F; bộ nhớ->loại [chỉ mục / 2] & 0xF0) >> 4;
Tuy nhiên, sử dụng thiết kế này có yêu cầu cao hơn về việc lưu trữ dữ liệu, do độ dài của dữ liệu không cố định nên cần có các chức năng đặc biệt để hoạt động với bộ nhớ.
// Ghi dữ liệu |data_ptr| trỏ đến có kích thước |size| vào dữ liệu tại // |index| byte trong |memory|. // Trả về 0 nếu thành công. -2 // nếu con trỏ kiểu là NULL. Trả về -3 nếu chỉ mục nằm ngoài phạm vi. Trả về // -4 nếu con trỏ dữ liệu là NULL. Bộ nhớ AqvmMemory_Memory*, chỉ mục size_t, void* data_ptr, size_t size) { if (memory == NULL) { AqvmRuntimewindow_OutputReport( "\"ERROR\"", "\"AqvmMemory_WriteData_NullMemoryPointer\"", "\"Con trỏ bộ nhớ là NULL. \"", NULL); trả về -1 } nếu (bộ nhớ->loại == NULL) { AqvmRuntimewindow_OutputReport("\"ERROR\"", "\"AqvmMemory_WriteData_NullTypePointer\"", "\"Con trỏ loại là NULL.\"", NULL trả về -2 }; (chỉ mục > bộ nhớ-> kích thước) { AqvmRuntimewindow_OutputReport( "\"ERROR\"", "\"AqvmMemory_WriteData_OutOfMemoryRange\"", "\"Chỉ mục nằm ngoài phạm vi bộ nhớ.\"", NULL); return -3; } if (data_ptr == NULL) { AqvmRuntimewindow_OutputReport(" \"LỖI\"", "\"AqvmMemory_WriteData_NullDataPointer\"", "\"Con trỏ dữ liệu là NULL.\"", NULL); return -4; } // Vì void* không có kích thước cụ thể nên việc di chuyển con trỏ cần phải được // chuyển đổi trước đó di chuyển. memcpy((void*)((uintptr_t)memory->data + index), data_ptr, size return 0;
Ngoài việc giảm mức sử dụng bộ nhớ, điều quan trọng không kém là tránh chiếm dụng bộ nhớ thứ cấp. Do đó, chúng tôi sử dụng lại bộ nhớ của bytecode, lưu trữ dữ liệu bộ nhớ và các loại trong phần bộ nhớ của bytecode và sử dụng bộ nhớ được cấp phát trước trong tệp bytecode (tệp bytecode chứa dữ liệu và loại của bộ nhớ) để triển khai Để sử dụng bộ nhớ hiệu quả. Bởi vì nếu bạn lưu trữ hai phần riêng biệt, bạn cần có hai phần dữ liệu và loại bộ nhớ lặp lại. Một phần nằm trong phần bộ nhớ và phần còn lại, phần mã byte, sẽ không được sử dụng. để giảm thiểu Loại bỏ lãng phí bộ nhớ do dữ liệu và loại bộ nhớ gây ra. Tuy nhiên, việc triển khai chức năng đặc biệt là cần thiết và cần lưu ý rằng việc phân bổ và giải phóng dữ liệu bộ nhớ cũng như các loại bộ nhớ được quản lý bởi các chức năng liên quan đến mã byte.
// Hàm sẽ phân tích cấu trúc AqvmMemory_Memory và sao chép |data|, // |type| và |size| tới cấu trúc nếu // thành công. Trả về NULL nếu việc tạo struct AqvmMemory_Memory* AqvmMemory_CreateMemory(void* data, type void*, size size_t) { struct AqvmMemory_Memory* Memory_ptr = (struct AqvmMemory_Memory*)malloc(sizeof(struct AqvmMemory_Memory)); if (memory_ptr == NULL) { AqvmRuntimewindow_OutputReport( "\"ERROR\"", "\"AqvmMemory_CreateMemory_MemoryAllocationFailure\"", "\"Không thể cung cấp bộ nhớ.\"", NULL); trả về NULL } bộ nhớ_ptr->data = bộ nhớ_ptr->type = bộ nhớ_ptr->size = kích size; } // Giải thích bộ nhớ của |memory_ptr|. // Ý: Hàm giải phóng cấu trúc bộ nhớ chỉ. được con trỏ tới // bởi các con trỏ tới dữ liệu và nhập vào cấu hình không được giải phóng. các hàm liên kết đến byte mã hóa.
Ngoài ra, hãy xác định loại trong một số hệ thống khác với AQ tiêu chuẩn để thiết kế các chức năng liên kết Nếu hệ thống khác với tiêu chuẩn thì phải thiết kế đặc biệt cho hệ thống this system.
// Trả về số lượng cảnh báo. int AqvmMemory_CheckMemoryConditions() { int Warning_count = 0; != 4) { AqvmRuntimewindow_OutputReport( "\"WARNING\"", " \"AqvmMemory_CheckMemoryConditions_IntLengthWarning\"", "\"Yêu cầu về độ dài cho kiểu int không thêm theo định nghĩa " "type " ", NULL); ++warning_count; } if (sizeof(aqlong) != 8) { AqvmRuntimewindow_OutputReport( "\" WARNING\"", "\"AqvmMemory_CheckMemoryConditions_LongLengthWarning\"", "\"Yêu cầu về độ dài cho loại dài không theo định nghĩa " ", NULL); ++warning_count; } if (sizeof(aqfloat) != 4) { AqvmRuntimewindow_OutputReport( "\"WARNING\"", "\" AqvmMemory_CheckMemoryConditions_FloatLengthWarning\"", "\"Yêu cầu về độ dài cho loại float không kèm theo " " định nghĩa loại.\"", NULL); ++warning_count } if (sizeof(aqdouble) != 4) { AqvmRuntimewindow_OutputReport( "\"CẢNH BÁO\"", "\"AqvmMemory_CheckMemoryConditions_DoubleLengthWarning\"", "\"Yêu cầu về độ dài cho loại kép không kèm theo định nghĩa loại " ".\"", NULL); ++warning_count; } if (sizeof(aqchar) != 1) { AqvmRuntimewindow_OutputReport( "\"WARNING\"", "\"AqvmMemory_CheckMemoryConditions_CharLengthWarning\"", "\"Yêu cầu về độ dài cho loại char không. thủ theo định nghĩa " "type " ".\", NULL); ++warning_count; } if (sizeof(aqbool) != 1) { AqvmRuntimewindow_OutputReport( "\"WARNING\"", "\"AqvmMemory_CheckMemoryConditions_BoolLengthWarning\"" , "Yêu cầu về độ dài cho loại bool không phù hợp với loại " " định nghĩa.", NULL); ++warning_count; } if (warning_count == 0) { AqvmRuntimewindow_OutputReport("\"INFO\"", "\"AqvmMemory_CheckMemoryConditions_CheckNormal\"", "\"Không có cảnh báo điều kiện bộ nhớ.\"", NULL } return Warning_count }
Chi tiết tiêu chuẩn:
Mã cho bộ nhớ nằm trong /aqvm/memory. Chứa nhiều mã hóa tập tin.
CMakeLists.txt
- File build CMake in this folder
bộ nhớ.h
- Bộ nhớ cấu trúc và các liên kết chức năng
bộ nhớ.c
- Thực hiện các chức năng liên quan đến bộ nhớ
loại.h
- Định nghĩa các loại bộ nhớ
AqvmMemory_Memory
|type| là một con trỏ tới một kiểu lưu trữ từng byte trong bộ nhớ. byte sử dụng 4 bit để lưu trữ loại. Do đó, một biến uint8_t có thể lưu trữ 2 loại. Danh sách các loại có trong type.h. |data| là một kẻ lừa đảo con trỏ void* tới bộ nhớ nơi lưu trữ dữ liệu |size| là kích thước của bộ nhớ. |bộ nhớ| và | bộ nhớ là một phần của bộ nhớ nhớ byte mã hóa.
struct AqvmMemory_Memory { uint8_t* data size void*;
AqvmMemory_CheckMemoryĐiều kiện
Kiểm tra bộ nhớ điều kiện trong hệ thống. Trả về cảnh báo số lượng.
int AqvmMemory_CheckMemoryConditions() { int Warning_count = 0; if (sizeof(aqint) != 4) { AqvmRuntimewindow_OutputReport( "\"WARNING\"", "\"AqvmMemory_CheckMemoryConditions_IntLengthWarning\"", "\"Yêu cầu độ dài cho kiểu int không phù hợp với " "loại" "định nghĩa.\"", NULL); ++warning_count; } if (sizeof(aqlong) != 8) { AqvmRuntimewindow_OutputReport( "\"WARNING\"" , "\"AqvmMemory_CheckMemoryConditions_LongLengthWarning\"", "\"Yêu cầu về độ dài đối với loại dài không cộng theo định nghĩa " " loại " ".\"", NULL); ++warning_count; } if (sizeof(aqfloat) != 4) { AqvmRuntimewindow_OutputReport( "\"WARNING\"", "\"AqvmMemory_CheckMemoryConditions_FloatLengthWarning\"", "\" thủ thuật tới " " định nghĩa kiểu.\"", NULL); } if (sizeof(aqdouble) != 4) { AqvmRuntimewindow_OutputReport( "\"WARNING\"", "\"AqvmMemory_CheckMemoryConditions_DoubleLengthWarning\"", "\"Yêu } if (sizeof(aqchar) != 1) { AqvmRuntimewindow_OutputReport( "\"CẢNH BÁO\"", "\"AqvmMemory_CheckMemoryConditions_CharLengthWarning\"", "\"Yêu cầu về độ dài cho loại char không cộng theo định nghĩa " "type " ".\"", NULL ); ++warning_count } if (sizeof(aqbool) != 1) { AqvmRuntimewindow_OutputReport( "\"WARNING\"", "\"AqvmMemory_CheckMemoryConditions_BoolLengthWarning\"", "Yêu cầu về độ dài cho loại bool không bổ sung theo loại " " định nghĩa.", NULL); = 0) { AqvmRuntimewindow_OutputReport("\"INFO\"", "\"AqvmMemory_CheckMemoryConditions_CheckNormal\"", "\"Không có cảnh báo điều kiện nhớ.\"", NULL } return Cảnh báo_count }
AqvmMemory_TạoBộ nhớ
Tạo cấu trúc AqvmMemory_Memory chứa |data|, |type| và |size|. Hàm này phân bổ cấu trúc AqvmMemory_Memory và sao chép |data|, |type| và |size| vào cấu trúc đó. Trả về một con trỏ tới cấu trúc này. Trả về NULL nếu việc tạo không thành công.
struct AqvmMemory_Memory* AqvmMemory_CreateMemory(void* data, void* type, size_t size) { struct AqvmMemory_Memory* Memory_ptr = (struct AqvmMemory_Memory*)malloc(sizeof(struct AqvmMemory_Memory)); if (memory_ptr == NULL) { AqvmRuntimewindow_OutputReport( "\"ERROR\"", "\"AqvmMemory_CreateMemory_MemoryAllocationFailure\"", "\"Không thể cấp phát bộ nhớ.\"", NULL trả về NULL } Memory_ptr->data = data; ; bộ nhớ_ptr->size = kích thước trả về bộ nhớ_ptr }
AqvmMemory_FreeMemory
Giải phóng bộ nhớ của |memory_ptr|. Không có giá trị trả lại. Lưu ý: Chức năng này chỉ giải phóng bộ nhớ của cấu trúc. Bộ nhớ được trỏ tới bởi con trỏ tới dữ liệu và kiểu trong cấu trúc sẽ không được giải phóng. Những bộ nhớ này được quản lý bởi các hàm liên quan đến mã byte.
void AqvmMemory_FreeMemory(struct AqvmMemory_Memory* Memory_ptr) { free(memory_ptr }
AqvmMemory_SetType
Đặt kiểu dữ liệu ở byte |index| trong |memory| thành |type|. |loại| phải ít hơn 4 chữ số. Trả về 0 khi thành công. Nếu con trỏ bộ nhớ là NULL, -1 được trả về. Nếu con trỏ chỉ mục là NULL, -2 được trả về. Nếu chỉ số nằm ngoài phạm vi, -3 sẽ được trả về. Nếu loại nằm ngoài phạm vi, -4 sẽ được trả về.
int AqvmMemory_SetType(const struct Bộ nhớ AqvmMemory_Memory*, size_t index, uint8_t type) { if (memory == NULL) { AqvmRuntimewindow_OutputReport("\"ERROR\"", "\"AqvmMemory_SetType_NullMemoryPointer\"", "\"Con trỏ bộ nhớ là NULL.\"", NULL); trả về -1; } if (bộ nhớ->loại == NULL) { AqvmRuntimewindow_OutputReport("\"ERROR\"", "\"AqvmMemory_SetType_NullTypePointer\"", "\"Con trỏ kiểu là NULL.\"", NULL); trả về -2 } if (chỉ mục> bộ nhớ-> kích thước) { AqvmRuntimewindow_OutputReport( "\"ERROR\"", "\"AqvmMemory_SetType_OutOfMemoryRange\"", "\"Chỉ mục nằm ngoài phạm vi bộ nhớ.\"", NULL return -3; "\"LỖI\"", "\"AqvmMemory_SetType_OutOfTypeRange\"", "\"Loại nằm ngoài phạm vi.\"", NULL); return -4; } // Đặt loại dữ liệu tại |index| lưu trữ dữ liệu loại chiếm 4 bit và uint8_t chiếm 8 bit, // mỗi vị trí loại uint8_t lưu trữ hai loại dữ liệu Vị trí lưu trữ // (4 bit cao, thấp. 4 bit) được thiết lập theo tính chẵn lẻ của |index|. // Số chẵn được lưu ở bit cao của (|index| / 2) và số lẻ được // được lưu ở bit thấp của (|index| / 2) ). if (index % 2 != 0) { bộ nhớ->type[index / 2] = (bộ nhớ->type[index / 2] & 0xF0) | loại; 2] = (bộ nhớ->loại [chỉ mục / 2] & 0x0F) | (loại << 4);
AqvmMemory_GetType
Lấy kiểu dữ liệu tại |index| byte trong |memory|. Loại nhỏ hơn 4 bit (0X0F) được trả về thành công. Nếu con trỏ bộ nhớ là NULL thì trả về 0x11. Nếu con trỏ chỉ mục là NULL thì trả về 0x12. Nếu chỉ số vượt quá phạm vi bộ nhớ, 0x13 sẽ được trả về.
uint8_t AqvmMemory_GetType(struct AqvmMemory_Memory* bộ nhớ, size_t chỉ mục) { if (bộ nhớ == NULL) { AqvmRuntimewindow_OutputReport("\"ERROR\"", "\"AqvmMemory_GetType_NullMemoryPointer\"", "\"Con trỏ bộ nhớ là NULL.\"" , KHÔNG); trả về 0x11; } if (bộ nhớ->loại == NULL) { AqvmRuntimewindow_OutputReport("\"ERROR\"", "\"AqvmMemory_GetType_NullTypePointer\"", "\"Con trỏ loại là NULL.\"", NULL trả về 0x12); ; } if (chỉ mục > bộ nhớ-> kích thước) { AqvmRuntimewindow_OutputReport( "\"ERROR\"", "\"AqvmMemory_GetType_OutOfMemoryRange\"", "\"Chỉ mục nằm ngoài phạm vi bộ nhớ.\"", NULL return 0x13; chỉ mục| byte trong bộ nhớ. // Vì Aqvm lưu trữ loại dữ liệu chiếm 4 bit và uint8_t chiếm 8 bit bit, // mỗi vị trí loại uint8_t lưu trữ hai loại dữ liệu. Các vị trí lưu trữ // (4 bit cao, 4 bit thấp) được đặt theo tính chẵn lẻ của |index|. |index| / 2) và các số lẻ được // lưu trữ ở các bit thấp của (|index| / 2). if (index % 2 != 0) { return Memory->type[index / 2] & 0x0F; } else { return (memory->type[index / 2] & 0xF0) >> 4;
AqvmMemory_WriteData
Ghi dữ liệu có kích thước |size| được trỏ bởi |data_ptr| vào dữ liệu tại |index|. Trả về 0 khi thành công. Nếu con trỏ bộ nhớ là NULL, -1 được trả về. Nếu con trỏ chỉ mục là NULL, -2 được trả về. Nếu chỉ số vượt quá phạm vi bộ nhớ, -3 sẽ được trả về. Nếu con trỏ dữ liệu là NULL, -4 được trả về.
int AqvmMemory_WriteData(struct AqvmMemory_Memory* bộ nhớ, size_t index, void* data_ptr, size_t size) { if (memory == NULL) { AqvmRuntimewindow_OutputReport( "\"ERROR\"", "\"AqvmMemory_WriteData_NullMemoryPointer\"", "\"Bộ nhớ con trỏ là NULL.\"", NULL); trả về -1; } if (bộ nhớ->loại == NULL) { AqvmRuntimewindow_OutputReport("\"ERROR\"", "\"AqvmMemory_WriteData_NullTypePointer\"", "\"Con trỏ kiểu là NULL.\"", NULL); trả về -2 } if (chỉ mục> bộ nhớ-> kích thước) { AqvmRuntimewindow_OutputReport( "\"ERROR\"", "\"AqvmMemory_WriteData_OutOfMemoryRange\"", "\"Chỉ mục nằm ngoài phạm vi bộ nhớ.\"", NULL return -3 } if (data_ptr == NULL) { AqvmRuntimewindow_OutputReport ("\"LỖI\"", "\"AqvmMemory_WriteData_NullDataPointer\"", "\"Con trỏ dữ liệu là NULL.\"", NULL); return -4; } // Vì void* không có kích thước cụ thể nên việc di chuyển con trỏ cần phải được // chuyển đổi trước đó di chuyển. memcpy((void*)((uintptr_t)memory->data + index), data_ptr, size return 0;
Mã hoàn chỉnh:
// Bản quyền của tác giả AQ 2024, Mọi quyền được bảo lưu. // Chương trình này được cấp phép theo Giấy phép AQ. Bạn có thể tìm thấy giấy phép AQ trong // thư mục gốc.
#include "aqvm/memory/types.h" // Cấu trúc lưu trữ thông tin về bộ nhớ // |type| bộ nhớ //. Vì vậy, một biến uint8_t có thể // lưu trữ 2 loại, 4 bit đầu tiên của biến uint8_t được sử dụng cho byte loại chẵn và 4 bit tiếp theo được sử dụng cho loại danh sách byte // có dạng.h. // |data| là một kiểu con trỏ void* tới bộ nhớ. lưu trữ dữ liệu. struct AqvmMemory_Memory chỉ lưu trữ thông tin của bộ nhớ // Bộ nhớ được bổ sung bởi hàm bytecode khi lưu trữ bytecode // Bộ nhớ của |memory| và |type| là một phần của dữ liệu bytecode bộ nhớ; void* size; system. // Trả về số lượng cảnh báo. , và |size|. // Hàm sẽ phân tích AqvmMemory_Memory Structure và sao chép |data|, // |type|, và |size| architecture. Trả về một con trỏ tới cấu trúc nếu // thành công. AqvmMemory_CreateMemory(void* data, void* type, size_t size); // Lưu Ý: Hàm giải phóng bộ nhớ chỉ của struct. do con trỏ tới dữ liệu và nhập vào struct không được giải phóng. // được quản lý bởi các hàm liên kết. đến byte mã hóa void AqvmMemory_FreeMemory(struct AqvmMemory_Memory* Memory_ptr); // Đặt loại dữ liệu tại |index| phải nhỏ hơn 4 bit. thành công. Trả về -1 nếu bộ nhớ con trỏ là NULL. phạm vi. int AqvmMemory_SetType(const struct AqvmMemory_Memory* bộ nhớ, size_t index, uint8_t type); // Lấy dữ liệu tại byte chỉ mục| // Trả về 0x12 nếu loại con trỏ là NULL. 0x13 if mục nằm ngoài phạm vi bộ nhớ // Ghi dữ liệu |data_ptr| tới kích thước |size| if thành công Trả về -1 nếu bộ nhớ con trỏ là NULL. phạm vi. Trả về // -4 if con trỏ dữ liệu là NULL.int AqvmMemory_WriteData(struct AqvmMemory_Memory* bộ nhớ, size_t chỉ mục, void* data_ptr, size size_t);
// Chương trình này được cấp phép theo AQ Giấy phép. Bạn có thể tìm thấy AQ giấy phép trong // thư mục gốc #include "aqvm/memory/memory.h" #include
#include "aqvm/memory/types.h" #include "aqvm/runtime/window/window.h" int AqvmMemory_CheckMemoryConditions() { int Warning_count = 0; if (sizeof(aqint) != 4) { AqvmRuntimewindow_OutputReport( "\" CẢNH BÁO\"", "\"AqvmMemory_CheckMemoryConditions_IntLengthWarning\"", "\"Yêu cầu về độ dài đối với kiểu int không kèm theo định nghĩa " "type ", NULL); (sizeof(aqlong) != 8) { AqvmRuntimewindow_OutputReport( "\"WARNING\"", " \"AqvmMemory_CheckMemoryConditions_LongLengthWarning\"", "\"Yêu cầu về độ dài cho loại dài không thêm vào " "type " " định nghĩa.\", NULL); ++warning_count; } if (sizeof(aqfloat) != 4) { AqvmRuntimewindow_OutputReport( "\"WARNING\"", "\"AqvmMemory_CheckMemoryConditions_FloatLengthWarning\"", " \"Yêu cầu độ dài cho kiểu float không phù hợp với kiểu " " định nghĩa.\", NULL); } if (sizeof(aqdouble) != 4) { AqvmRuntimewindow_OutputReport( "\"WARNING\"", "\"AqvmMemory_CheckMemoryConditions_DoubleLengthWarning\"", "\"Yêu cầu về độ dài cho loại kép không cộng theo định nghĩa loại " ".\"", NULL); (sizeof(aqchar) != 1) { AqvmRuntimewindow_OutputReport( "\"WARNING\"", "\"AqvmMemory_CheckMemoryConditions_CharLengthWarning\"", "\"Yêu cầu về độ dài cho loại char không có nhiều theo " "gõ " " định nghĩa.\"", NULL); ++warning_count; } if (sizeof(aqbool) != 1) { AqvmRuntimewindow_OutputReport( "\"WARNING\"", "\"AqvmMemory_CheckMemoryConditions_BoolLengthWarning\"", "Yêu cầu về độ dài cho loại bool không đóng theo định nghĩa loại " ".", NULL ); ++warning_count; } if (warning_count == 0) { AqvmRuntimewindow_OutputReport("\"INFO\"", "\"AqvmMemory_CheckMemoryConditions_CheckNormal\"", "\"Không có cảnh báo điều kiện bộ nhớ.\"", NULL); } return Warning_count } struct AqvmMemory_Memory* AqvmMemory_CreateMemory(void* data, void* type; , kích thước size_t) { struct AqvmMemory_Memory* Memory_ptr = (struct AqvmMemory_Memory*)malloc(sizeof(struct AqvmMemory_Memory)); if (memory_ptr == NULL) { AqvmRuntimewindow_OutputReport( "\"ERROR\"","\"AqvmMemory_CreateMemory_MemoryAllocationFailure\"", "\"Không thể cung cấp bộ nhớ phát hiện.\"", NULL); trả về NULL } bộ nhớ_ptr->data = dữ liệu bộ nhớ_ptr->type = bộ nhớ_ptr->size = kích thước; } void AqvmMemory_FreeMemory(struct AqvmMemory_Memory* Memory_ptr) { free(memory_ptr); } int AqvmMemory_SetType(const struct AqvmMemory_Memory* bộ bộ nhớ, size_t chỉ mục,loại uint8_t) { if (bộ nhớ == NULL) { AqvmRuntimewindow_OutputReport("\"ERROR\"", "\"AqvmMemory_SetType_NullMemoryPointer\"", "\"Con trỏ bộ nhớ là NULL.\"", NULL return - 1; } nếu (bộ nhớ->loại == NULL) { AqvmRuntimewindow_OutputReport("\"ERROR\"", "\"AqvmMemory_SetType_NullTypePointer\"", "\" Loại bỏ con trỏ là NULL.\"", NULL trả về -2; } nếu như (chỉ mục > bộ nhớ-> kích thước) { AqvmRuntimewindow_OutputReport( "\"ERROR\"", "\"AqvmMemory_SetType_OutOfMemoryRange\"", "\"Chỉ mục ngoài phạm vi bộ nhớ.\"", NULL); return -3; } if (type > 0x0F) { AqvmRuntimewindow_OutputReport("\"ERROR\"", "\"AqvmMemory_SetType_OutOfTypeRange\"", "\" Out of range.\" ", trả về NULL -4 } // index| byte trong bộ nhớ // Vì loại dữ liệu lưu trữ Aqvm sử dụng 4 bit và uint8_t sử dụng 8 bit, // mỗi vị trí loại uint8_t lưu trữ hai loại dữ liệu. Các vị trí lưu trữ // (cao 4 bit, thấp 4 bit) được đặt theo tính chất chẵn của |index|. và các số lẻ được // lưu trữ ở các bit thấp của (|index| / 2). if (index % 2 != 0) { Memory->type[index / 2] = (memory->type[index / 2] & 0xF0) | loại } else { bộ nhớ->type[index / 2] = (bộ nhớ->type[index / 2] & 0x0F) | (loại << 4); } trả về 0; bộ nhớ AqvmMemory_Memory*, size mục_t) { (bộ nhớ == NULL) { AqvmRuntimewindow_OutputReport("\"ERROR\"", "\"AqvmMemory_GetType_NullMemoryPointer\"", "\"Con trỏ bộ nhớ là NULL.\"", NULL trả về 0x11 } if (bộ nhớ->loại == NULL) { AqvmRuntimewindow_OutputReport ("\"LỖI\"", "\"AqvmMemory_GetType_NullTypePointer\"", "\"Con trỏ kiểu là NULL.\"", NULL); return 0x12; (chỉ mục > bộ nhớ->kích thước) { AqvmRuntimewindow_OutputReport( "\"ERROR\"", "\ "AqvmMemory_GetType_OutOfMemoryRange\"", "\"Chỉ mục đã hết phạm vi bộ nhớ.\"", NULL); return 0x13; } // Lấy loại dữ liệu tại |index| byte trong bộ nhớ // Vì Aqvm archive loại dữ liệu sử dụng 4 bit và uint8_t sử dụng 8 bit, // mỗi loại uint8_t. vị trí lưu trữ hai loại dữ liệu // (cao 4 bit, thấp 4 bit) được thiết lập theo tính năng lẻ của |index|. // lưu trữ ở bit thấp của (|index| /. 2) và số lẻ được // lưu trữ ở bit thấp của (|index| /. 2). (chỉ mục % 2 != 0) { return bộ nhớ->type[index / 2] & 0x0F; else { return (memory->type[index / 2] & 0xF0) >> 4; } } int AqvmMemory_WriteData(struct AqvmMemory_Memory * bộ nhớ, size_t chỉ mục, void* data_ptr, size_t size) { if (bộ nhớ == NULL) { AqvmRuntimewindow_OutputReport( "\"ERROR\"", "\"AqvmMemory_WriteData_NullMemoryPointer\""," \"Ký ức con trỏ là NULL.\"", NULL); trả về -1; } if (bộ nhớ->loại == NULL) { AqvmRuntimewindow_OutputReport("\"ERROR\"", "\"AqvmMemory_WriteData_NullTypePointer\ "", "\"Cuộn con trỏ là NULL.\", NULL); trả về -2 } if (chỉ mục > bộ nhớ-> kích thước) { AqvmRuntimewindow_OutputReport( "\"ERROR\"", "\"AqvmMemory_WriteData_OutOfMemoryRange\"", "\"Chỉ mục nằm ngoài phạm vi bộ nhớ.\"", NULL return -3 } if (data_ptr == NULL) { AqvmRuntimewindow_OutputReport ("\"LỖI\"", "\"AqvmMemory_WriteData_NullDataPointer\"", "\"Con trỏ dữ liệu là NULL.\"", NULL); return -4; } // Vì void* không có công cụ kích thước nên việc chuyển con trỏ memcpy((void*)((uintptr_t)memory->data + index), data_ptr, trả về kích thước 0;memcpy((void*)((uintptr_t)memory->data + index), data_ptr, size return 0 }memcpy((void*)((uintptr_t)memory->data + index), data_ptr, size return 0 }
Thông qua tác phẩm này, một Aqvm kiến ​​trúc đã được hoàn thành, giúp giảm bớt sức mạnh của bộ nhớ Aqvm.
Chúng tôi đang làm việc chăm chỉ hơn trên máy ảo AQ. trang web chính thức của chúng tôi: https://www.axa6.com và Github: https://github.com/aq-org/AQ.
Bài viết này được xuất bản dựa trên Giấy phép AQ: https://github.com/aq-org/AQ/blob/main/LICENSE. lại theo AQ Giấy phép.
Cuối cùng, bài viết về kiến ​​trúc máy xuất sắc máy ảo - AQ end tại đây. trúc bộ nhớ máy ảo xuất sắc - AQ, vui lòng tìm kiếm các bài viết CFSDN hoặc tiếp tục duyệt các bài viết liên quan, tôi hy mong bạn sẽ ủng hộ blog của tôi trong tương lai .
Hiệu ứng gradient viền văn bản CSS rất dễ dàng!
vmware - máy ảo
Tôi đang cố gắng tìm hiểu cách thức hoạt động của VMware (đặc biệt là khi cài đặt Linux) và tôi có hai câu hỏi: Điều gì xảy ra khi VMware gặp một lệnh như push cs?
máy ảo Gửi lệnh đến đầu thiết bị?
Tôi đang cố gắng định cấu hình vim làm chương trình mã hóa chính của mình. Nhưng khi tôi thực hiện chương trình này từ vim, tôi liên tục nhận được mã lỗi 127. Tôi có bí danh trên hộp của mình là ./a.out, Nhưng khi tôi bắt đầu từ vim
Javascript máy ảo
Tôi muốn biết liệu bạn có sử dụng máy ảo javascript hay có ý tưởng gì không! sử dụng trong trình duyệt như V8 của chrome, tôi muốn thực thi java trên máy chủ linux.
Cổng kết nối tiếp Ubuntu trên VirtualBOX (máy ảo)
đóng cửa câu hỏi này. cập nhật câu hỏi để nó phù hợp với chủ đề về Stack Overflow. Đóng cửa 10 năm trước.
Máy ảo Azure - đích đến của tài khoản lưu trữ
Tôi đang tìm cách sử dụng tài khoản lưu trữ trong Azure. tài khoản lưu trữ, hình như tôi cũng đã dùng rồi nhưng không biết tại sao, tôi nghĩ mình không cần thiết. tài khoản lưu trữ và dịch vụ đám mây. Tôi muốn tạo một cái khác
java - máy ảo: không thể mở
Error - JVM - Trình mô phỏng BlackBerry 9800 ----------------------------------------- - -- JVM: không thể mở được
Máy ảo/giả lập Javascript?
Thật khó để nói những gì để hỏi ở đây. không thể trả lời hợp lý ở dạng hiện tại. truy cập vào trung tâm trợ giúp.
linux - máy ảo - thiết lập centos làm bộ định tuyến
Đây là vấn đề của tôi. ảo...
Máy ảo Java không cần hệ điều hành?
Tôi biết BEA đang phát triển LiquidVM không yêu cầu hệ điều hành cơ bản nhưng tôi tự hỏi liệu có ai trong cộng đồng nguồn mở đang phát triển thứ gì đó tương tự hay không. Lý tưởng nhất là tôi muốn tìm một triển khai trong đó VM được tải trực tiếp bởi bộ tải khởi động hệ điều hành. Câu trả lời hay nhất là với
Hướng dẫn đồ họa chi tiết từng bước về cài đặt Vmware (máy ảo) trong hệ thống Linux
Hướng dẫn cài đặt Vmware trên hệ thống Linux. Do nhu cầu của dự án, việc ảo hóa Windows trên Linux là cần thiết. Sau khi tìm kiếm một số thông tin, tôi thấy rằng có thể đạt được điều đó với VMware. có thể được sử dụng, chẳng hạn như Win4lin và bochs.
sharepoint - Cách đổi tên máy ảo SharePoint
Tôi đang sử dụng máy ảo để phát triển nhưng mỗi khi cần một máy ảo mới, tôi lại sao chép các tệp và tạo một máy chủ mới nhưng tôi cần một tên máy chủ mới để thêm nó vào mạng của chúng tôi. Sau khi đổi tên server, trang Sharepoint có nhiều
Cách kết nối với máy ảo Cassandra
Nếu Cassandra và mã nằm trên cùng một máy, đoạn mã sau sẽ hoạt động: sử dụng System; sử dụng không gian tên CassandraInsertTest {
vmware - Làm cách nào để tắt máy ảo VMware mà không chết?
đóng cửa. Câu hỏi này không đáp ứng các nguyên tắc của Stack Overflow. Hiện tại nó không chấp nhận câu trả lời. Bạn muốn cải thiện vấn đề này? Câu hỏi được cập nhật để làm cho câu hỏi trở thành chủ đề cho Stack Overflow. Đóng cửa 7 năm trước Cải thiện điều này
CUDA/OpenCL trong máy ảo/trình ảo hóa
đóng cửa. Câu hỏi này không tuân thủ các nguyên tắc của Stack Overflow. Hiện tại nó không chấp nhận câu trả lời. Bạn muốn cải thiện câu hỏi này? Đã cập nhật câu hỏi theo chủ đề cho Stack Overflow. Đóng cửa 3 năm trước. Cải thiện câu hỏi này
azure - Lỗi ghi nhật ký vào máy ảo Azure?
Tôi đang chuyển ứng dụng web của mình, hãy thử bắt các thông báo theo dõi lỗi ngoại lệ vào thư mục C:\Temp trên máy chủ web. Nhưng khi ứng dụng web của tôi chạy trên Azure, tôi muốn chạy nó trên Azure VM c.
azure - Cách định cấu hình máy ảo Azure cho môi trường nhiều người dùng
Chúng tôi cung cấp phần mềm ERP dành cho máy tính để bàn cho khách hàng của mình. Phần mềm được cài đặt trong máy ảo Azure. Mỗi công ty có tập tin cơ sở dữ liệu riêng của mình. Tôi cần tối ưu hóa hiệu suất nhưng tôi có một số nghi ngờ và không thể tìm thấy câu trả lời. Ví dụ: đối với 2 công ty: 1-Mua 2 VM nhỏ (2
Azure - Không thể truy cập máy ảo Azure
Tôi đang cố gắng thay đổi địa chỉ số mạng của máy ảo trên Azure thành cùng mạng với một máy ảo khác trên nhóm Azure, khi tôi nhấp vào "lưu" trên card mạng thì nó bị kẹt và không hoạt động thông qua máy tính để bàn từ xa hoặc bất cứ cách nào khác. Xin hãy giúp đỡ. Câu trả lời hay nhất: Đừng thử
azure - Chia sẻ máy ảo Azure
Có thể thiết lập một máy ảo trên Azure và có cùng một phiên bản của máy ảo hiển thị cho nhiều người dùng không? Chúng tôi là một ISV. Người dùng của chúng tôi nằm rải rác trên toàn cầu. Chúng tôi muốn sử dụng máy ảo Azure để hướng dẫn người dùng thiết lập phần mềm của chúng tôi. Lý tưởng nhất là bàn trợ giúp của chúng tôi sẽ có mặt tại
azure - Không thể kết nối với máy ảo Azure
Tôi đã tạo một máy ảo bằng hình ảnh Ubuntu và tải sẵn Discourse từ kho lưu trữ Azure. Sau khi thiết lập tự động hoàn tất, tôi thấy máy ảo đang chạy nhưng không thể kết nối để xem máy từ xa. Tôi không thấy bất kỳ cài đặt nào giải quyết được vấn đề này cho tôi
[rCore Study Notes 016] Triển khai ứng dụng-6ren
[rCore Study Notes 016] Ứng dụng triển khai - Viết ở phía trước Bài luận này được viết bởi một người mới học rất giỏi. Nếu bạn có bất kỳ câu hỏi nào, xin vui lòng hỏi họ kịp thời. Bạn có thể liên hệ: 1160712160@qq.com GitHhub: https://github.com/WindDevil (Hiện tại không có gì -6ren
Thời gian cập nhật: 2024-07-20 13:00:42
viết ở phía trước
Bài luận này được viết bởi một người rất mới. Nếu bạn có bất kỳ câu hỏi nào, xin vui lòng hỏi họ kịp thời.
Bạn có thể liên hệ: 1160712160@qq.com.
GitHhub: https://github.com/WindDevil (Hiện tại không có gì.
phương pháp thiết kế
Trên thực tế, sau khi hiểu cơ chế cấp đặc quyền, nếu muốn thiết kế một ứng dụng, bạn cần đảm bảo rằng nó đáp ứng các yêu cầu của chế độ U và không truy cập các chức năng ở chế độ S. Sau đó, những điểm chính khi triển khai nó là.
Bố cục bộ nhớ ứng dụng
Cuộc gọi hệ thống do ứng dụng đưa ra
thiết kế cụ thể
Những tính năng cần bổ sung
Trong quá trình thực hiện cụ thể, việc thiết kế cũng phải được thực hiện theo các điểm chính được đưa ra trong phương pháp thiết kế.
Đặt vị trí nhập của thư viện người dùng
linker.ld
File, thiết lập người dùng khó khăn
rom
địa chỉ ở
Việc thực hiện có thể gọi
gọi lại
Các ứng dụng cần triển khai
Ứng dụng được biên dịch riêng để tạo tệp ELF và cắt nó thành tệp .bin. Để gọi nó, bạn chỉ cần liên kết nó với kernel trước rồi kernel sẽ tải nó vào bộ nhớ vào thời điểm thích hợp. để thực hiện nó trong phần giới thiệu của phần này
xin chào thế giới
 : In một dòng lên màn hình 
Xin chào thế giới từ chương trình chế độ người dùng!
cửa hàng_lỗi
 : Truy cập vào một địa chỉ vật lý bất hợp pháp để kiểm tra xem hệ thống xử lý hàng loạt có bị ảnh hưởng bởi lỗi này hay không.
quyền lực
 : Liên tục chuyển đổi cấp độ đặc quyền giữa các thao tác tính toán và thao tác in chuỗi
Tạo dự án
Đảm bảo rằng vị trí hiện tại là không gian làm việc.
cd -/không gian làm việc
Sử dụng hàng hóa để tạo dự án và tạo thư mục người dùng trong thư mục dự án để lưu trữ mã và giao diện chế độ người dùng.
hàng hóa mới ./user
Đã có user/src trong tệp dự án để lưu thư viện người dùng. Tiếp theo, tạo user/src/bin để lưu ứng dụng.
người dùng mkdir/src/bin
Thực hiện cấu hình bố trí bộ nhớ
Tạo tệp liên kết linker.ld trong user/src.
liên kết liên kết.ld
Vì địa chỉ mục nhập của lớp người dùng ứng dụng là 0x80400000 nên linker.ld được cung cấp trong Chương 1 cần được sửa đổi và BASE_ADDRESS được đặt thành 0x80400000.
OUTPUT_ARCH(riscv) ENTRY(_start) BASE_ADDRESS = 0x80400000; SECTIONS { . = BASE_ADDRESS; skernel = .; stext = .; (4K); etext = .; .rodata : { *(.rodata .rodata.*) *(.srodata .srodata.*) } = ALIGN(4K); erodata = .; sdata = .; ) *(.sdata .sdata.*) } = ALIGN(4K); edata = .bss : { *(.bss.stack) sbss = .; *(.bss .bss.*) *(.sbss .sbss.*) } . = ALIGN(4K); ebss = .; *(.eh_frame) } }
Bố cục bộ nhớ được thể hiện bằng tệp liên kết này như trong hình. Hãy chú ý đến vị trí của địa chỉ thấp và địa chỉ cao trong hình.
Phân đoạn dữ liệu được khởi tạo lưu trữ dữ liệu toàn cục được khởi tạo trong chương trình và được chia thành 
.rodata
 Và 
.data
 Hai phần. Cái trước lưu trữ dữ liệu toàn cầu chỉ đọc, thường là một số hằng số hoặc chuỗi không đổi, v.v. trong khi cái sau lưu trữ dữ liệu toàn cầu có thể sửa đổi.
Phân đoạn dữ liệu chưa được khởi tạo 
.bss
 Lưu dữ liệu chung chưa được khởi tạo trong chương trình, dữ liệu này thường được khởi tạo bằng 0 bởi trình tải của chương trình, nghĩa là xóa vùng này theo từng byte;
 Vùng (heap) được sử dụng để lưu trữ dữ liệu được phân bổ động khi chương trình đang chạy. Ví dụ: dữ liệu được phân bổ bởi malloc/new trong C/C++ được đặt trong vùng heap và nó sẽ tăng dần lên các địa chỉ cao hơn;
chồng
 Vùng (ngăn xếp) không chỉ được sử dụng để lưu và khôi phục ngữ cảnh lệnh gọi hàm mà các biến cục bộ trong phạm vi của từng hàm cũng được trình biên dịch đặt trong khung ngăn xếp của nó và nó phát triển về các địa chỉ thấp hơn.
Nhớ lại hướng dẫn mà chúng tôi đã sử dụng để flash tệp nhị phân vào QEMU, chúng tôi thực sự đã đặt kernel đã biên dịch ở 0x80200000, đây là phần .text.
qemu-system-riscv64 \ -machine virt \ -nographic \ -bios ../bootloader/rustsbi-qemu.bin \ -device Loader,file=target/riscv64gc-unknown-none-elf/release/os.bin,addr= 0x80200000
Đặt .text.entry trong đó _start nằm ở đầu toàn bộ chương trình. Nghĩa là, hệ thống hàng loạt đã nhập điểm vào của thư viện người dùng miễn là nó nhảy tới 0x80400000 sau khi tải và sẽ chuyển đến ứng dụng sau khi khởi tạo Logic chính...
Ở đây lưu ý rằng ENTRY(_start) là lối vào chương trình cài đặt. Nhìn lại nội dung của entry.asm trong Chương 1, .section .text.entry được đặt ở đây và Global_asm!(include_str!("entry. asm" )), trích dẫn mã này
# os/src/entry.asm .section .text.entry .globl _start _start: la sp, boot_stack_top gọi Rust_main .section .bss.stack .globl boot_stack_low_bound boot_stack_low_bound: .space 4096 * 16 .globl boot_stack_top boot_stack_top:
Cung cấp địa chỉ bắt đầu và kết thúc của phần .bss của tệp thực thi được tạo cuối cùng để hỗ trợ việc sử dụng hàm clear_bss.
Quan sát ~/App/rCore-Tutorial-v3/user/src/linker.ld
OUTPUT_ARCH(riscv) ENTRY(_start) BASE_ADDRESS = 0x80400000; SECTIONS { . = BASE_ADDRESS; .text : { *(.text.entry) *(.text .text.*) } .rodata : { *(.rodata .rodata. *) *(.srodata .srodata.*) } .data : { *(.data .data.*) *(.sdata .sdata.*) } .bss : { start_bss = .; *(.bss .bss.*) *(.sbss .sbss.*) end_bss = .; /DISCARD/ : { *(.eh_frame) *(.debug*) } }
Bạn có thể thấy rằng so với file link.ld mà chúng ta xây dựng theo file thì có ít mô tả về xxx(label) = .; và offset của = ALIGN(4K); hơn.
xxx(label) = .; được sử dụng để xác định ký hiệu xxx và đặt vị trí con trỏ hiện tại cho anh ta.
. = ALIGN(4K) được sử dụng để kiểm tra xem vị trí liên kết hiện tại có được căn chỉnh theo ranh giới 4K hay không. Nếu vị trí liên kết hiện tại không phải là bội số của ranh giới 4K, trình liên kết sẽ lấp đầy đủ byte cho đến ranh giới 4K tiếp theo.
Do đó, chúng ta có thể biết rằng trong linker.ld gốc, một số nhãn cần được đặt để chúng ta có thể lấy các con trỏ này thông qua extern C để biết kích thước của từng phần sau khi biên dịch. Và mỗi khi một phần được đặt, nó cần. được kiểm tra để phù hợp với ranh giới 4K ..
chi tiết (vui lòng đọc kỹ phần này, đặc biệt là BỎ QUA)
OUTPUT_ARCH(riscv)
: Xác định rằng kiến trúc đầu ra mục tiêu là RISC-V.
NHẬP(_bắt đầu)
: Chỉ định điểm vào của chương trình là
_bắt đầu
chức năng. Đây là nơi thực hiện chương trình bắt đầu.
BASE_ADDRESS = 0x80200000;
: Đặt địa chỉ cơ sở của chương trình thành 0x80200000, đây là địa chỉ bắt đầu của chương trình được tải vào bộ nhớ.
PHẦN
: Bắt đầu xác định bố cục của phân đoạn bộ nhớ.
. = CƠ SỞ_ĐỊA CHỈ;
: Đặt địa chỉ hiện tại làm địa chỉ cơ sở.
da = .;
: Ghi lại địa chỉ bắt đầu của phân đoạn kernel.
văn bản = .;
: Ghi địa chỉ bắt đầu của đoạn văn bản (đoạn mã).
.chữ
: Xác định một đoạn văn bản, chứa mã thực thi.
*(.text.entry)
*(.text .text.*)
có nghĩa là tất cả
.chữ.*
Nội dung phần được liên kết ở đây.
. = CĂN HỘ(4K);
: Căn chỉnh địa chỉ hiện tại theo ranh giới 4K (4096 byte).
etext = .;
: Ghi địa chỉ cuối của đoạn văn bản.
srodata = .;
: Ghi lại địa chỉ bắt đầu của phân đoạn dữ liệu chỉ đọc.
: Xác định phân đoạn dữ liệu chỉ đọc, bao gồm các hằng số và dữ liệu chỉ đọc.
*(.rodata .rodata.*)
*(.srodata .srodata.*)
.srodata
erodata = .;
: Ghi lại địa chỉ cuối của phân đoạn dữ liệu chỉ đọc.
sdata = .;
: Ghi lại địa chỉ bắt đầu của đoạn dữ liệu khởi tạo.
: Xác định phân đoạn dữ liệu khởi tạo, bao gồm các biến toàn cục được khởi tạo.
*(.data .data.*)
*(.sdata .sdata.*)
.sdata
edata = .;
: Ghi lại địa chỉ cuối của đoạn dữ liệu khởi tạo.
: Xác định phân đoạn dữ liệu chưa được khởi tạo (phân đoạn BSS), bao gồm các biến toàn cục chưa được khởi tạo.
*(.bss.stack)
*(.bss .bss.*)
cũng như
*(.sbss .sbss.*)
.sbss
.bss.stack
sss = .;
Ghi lại địa chỉ bắt đầu của phân đoạn BSS.
ebss = .;
: Ghi lại địa chỉ cuối của đoạn dữ liệu chưa được khởi tạo.
hạt nhân = .;
: Ghi lại địa chỉ cuối của toàn bộ phân đoạn kernel.
/BỎ BỎ/
: Xác định phần loại bỏ để loại trừ các phần không cần thiết, ở đây quy định là không bao gồm
.eh_frame
phần này, thông thường phần này chứa thông tin khung xử lý ngoại lệ.
Tương ứng với việc tạo các chức năng nhập và khởi tạo hệ thống
Tạo mô-đun lib.rs
chạm vào lib.rs
Giống như main.rs của os, khi tạo mục nhập hàm, hãy sử dụng #[no_mangle] để đảm bảo tên hàm không được tối ưu hóa và sử dụng macro mới #[link_section = ".text.entry"] để tạo _start mã này. mã hợp ngữ đã biên dịch được đặt trong một tệp có tên .text.entry Trong đoạn mã, thuận tiện cho chúng ta điều chỉnh vị trí của nó trong quá trình liên kết tiếp theo để nó có thể đóng vai trò là lối vào thư viện người dùng. Ở đây cần lưu ý rằng chúng ta vẫn chỉ có thể sử dụng thư viện lõi nên chúng ta phải sử dụng. #![no_std] macro
#![no_std] #[no_mangle] #[link_section = ".text.entry"] pub extern "C" fn _start() -> ! { clear_bss(); sys_exit!"); }
Tương ứng với Chương 1, bạn cũng cần xóa phần .bss và sử dụng macro hoảng loạn!
#![feature(panic_info_message)] fn clear_bss() { extern "C" { fn start_bss(); fn end_bss(); } (start_bss as usize..end_bss as usize).for_each(|addr| không an toàn { (addr as *mut u8).write_volatile(0); } }
Và dùng giao diện exit để gọi hàm main. Giao diện exit ở đây chỉ có thể thực hiện được thông qua ecall sau này đối với hàm main nếu có ký hiệu main trong thư mục bin thì chương trình có thể liên kết bình thường, nhưng khi đó chúng ta không thể liên kết được. tìm chính, chúng tôi cũng cần phải có một Đảm bảo, điều này liên quan đến các liên kết yếu. Nếu không tìm thấy chính, hãy liên kết đến chính.
#![feature(linkage)] #[linkage = "weak"] #[no_mangle] fn main() -> i32 { hoảng loạn!("Không thể tìm thấy main!" }
Tạo mô-đun cuộc gọi hệ thống
Tạo mô-đun syscall. Tệp này được tạo trong tệp người dùng/src.
touchsyscall.rs
Chúng tôi sử dụng mã hợp ngữ nhúng của Rust để gọi ecall nhằm bắt đầu các cuộc gọi hệ thống ở chế độ người dùng.
Khi một tiến trình thực thi lệnh ecall, bộ xử lý sẽ kích hoạt một ngoại lệ, khiến điều khiển chuyển sang trình xử lý ngoại lệ kernel đặt trước. Tại thời điểm này, kernel có thể kiểm tra ngữ cảnh đã kích hoạt ecall và cung cấp các dịch vụ phù hợp dựa trên các tham số được truyền vào, chẳng hạn như mở tệp, tạo tiến trình, phân bổ bộ nhớ, v.v.
Bản thân lệnh ecall không mang bất kỳ tham số nào, nhưng nó có thể truy cập các giá trị trong các thanh ghi chung và chuyển chúng vào kernel dưới dạng tham số. Thông thường, các thanh ghi sau được sử dụng để truyền tham số:
x10
(a0): tham số đầu tiên
x11
(a1): tham số thứ hai
x12
(a2): Tham số thứ ba
x13
(a3): Tham số thứ tư
x14
(a4): Tham số thứ năm
x15
(a5): Tham số thứ sáu
x16
(a6): Tham số thứ bảy
x17
(a7): Tham số thứ tám, cũng đóng vai trò là số cuộc gọi hệ thống
Sau đó, bạn có thể tạo giao diện trong tệp syscall.rs
// user/src/syscall.rs use core::arch::asm; fn syscall(id: usize, args: [usize; 3]) -> isize { let mut ret: isize không an toàn { asm!( " ecall ", inlateout("x10") args[0] => ret, in("x11") args[1], in("x12") args[2], in("x17") id } ret }
Format macro asm!
Đầu tiên, dòng 6 chính là đoạn mã hợp nhất mà chúng tôi muốn chèn ở đây, chúng tôi chỉ chèn một dòng. 
 hướng dẫn, nhưng nó có thể hỗ trợ chèn nhiều hướng dẫn cùng một lúc.
Bắt đầu từ dòng 7, chúng tôi liên kết các biến đầu vào/đầu ra với các thanh ghi với sự trợ giúp của trình biên dịch dịch.
Ví dụ: dòng 8 
trong ("x11") tranh luận [1]
 Có nghĩa là các thông số sẽ được nhập 
lập luận[1]
 kill with 
 ghi đầu vào 
 Instant setting 
a1
 , trình biên dịch sẽ tự động chèn các lệnh liên quan và chắc chắn rằng 
 đăng ký trước khi thực hiện lệnh này 
 Giá trị của 
 như nhau.
Theo cách tương tự, chúng tôi có thể đặt các tham số đầu vào 
lập luận[2]
 Liên kết với các thanh ghi tương ứng 
a2
a7
 ở giữa.
Điều đặc biệt ở đây là 
a0
 Thanh ghi, đóng vai trò vừa đầu vào vừa là đầu ra, vì vậy chúng ta sẽ 
 Change thành công 
vào sau
 và trong phần biến ở dòng cuối cùng, hãy sử dụng 
{in_var} => {out_var}
 format, ở đâu 
{in_var}
{out_var}
 Giao diện cho các biến đầu vào và đầu ra biến trong bối cảnh tương ứng.
Trong chương trình này, hai lệnh gọi hệ thống sau đây được thống nhất giữa chương trình ứng dụng và hệ thống xử lý hàng loạt theo API cấu hình:
/// Chức năng: Ghi dữ liệu vào bộ nhớ đệm vào tệp /// Tham số: `fd` đại diện cho tệp mô tả của file. được ghi; /// `buf` đại diện cho địa chỉ bắt đầu của bộ đệm trong bộ nhớ /// `len` đại diện cho chiều dài; /// ID tòa nhà: 64 fn sys_write(fd: usize, buf: *const u8, len: usize) -> isize; /// Chức năng: Thoát khỏi ứng dụng và thông báo cho hệ thống xử lý hàng hóa về giá trị trả về /// Tham số: `exit_code` biểu tượng /// ID tòa nhà: 93 fn sys_exit(exit_code: useize) -> !;
Tương tự như vậy, chúng tôi có thể sử dụng syscall để phát triển API này
// user/src/syscall.rs const SYSCALL_WRITE: usize = 64; const SYSCALL_EXIT: usize = 93; pub fn sys_write(fd: usize, buffer: &[u8]) -> isize { syscall(SYSCALL_WRITE, [fd, buffer .as_ptr() as usize, buffer.len()]) } pub fn sys_exit(xstate: i32) -> isize { syscall(SYSCALL_EXIT, [xstate as usize, 0, 0]) }
Lưu ý rằng sys_write sử dụng lát lát &[u8] để mô tả bộ đệm, đó là một con trỏ béo (Con trỏ béo), chứa cả địa chỉ chỉ bắt đầu bộ đệm và độ dài của bộ đệm. ứng dụng và sử dụng chúng để tạo ra một tham số gọi hệ thống thực tế một cách độc lập.
Đóng gói bổ sung giao diện

Sự kiện.php.

$client_id, 'message'=>'Welcome'.$client_id.'Đăng nhập! ', 'data'=>[] ]; Gateway::sendToAll(json_encode($data)); // Gateway::sendToAll("$client_id login\r\n"); } /** * Khi khách hàng gửi Được kích hoạt khi có tin nhắn đến* @param int $client_id id kết nối * @param đã trộn $message cụ thể tin nhắn*/ public static function onMessage($client_id, $message){ $data=[ 'client_id'=>$client_id, 'message'=>$client_id.' nói: '.$result['message'], 'data'=>$message ]; // Gửi cho mọi người // Gateway::sendToAll("$client_id đã nói $message\r\n"); } /** * Được kích hoạt khi người dùng ngắt kết nối * @param int $client_id id kết nối */ public static function onClose($client_id) { //Gửi cho mọi người // GateWay::sendToAll("$client_id exited!\r\n" );

Sau đó tạo một tệp khởi động mới trong thư mục gốc của dự án.

start_all_workman.php .


Lưu ý sau khi mở port nhớ nhả port nhé! ! ! Ngoài việc phát hành chùa, máy chủ của bạn (Alibaba Cloud/Tencent Cloud, v.v.) cũng nhớ phát hành nó! ! ! .
Bắt đầu công nhân
Mở terminal trong thư mục gốc của dự án và nhập php start_all_workman.php start -d để bắt đầu quá trình daemon. Nếu trang sau xuất hiện, nó sẽ được khởi động thành công.
Nếu bạn muốn tắt tiến trình Workman, hãy nhập php start_all_workman.php stop để tắt.
GatewayWorker sử dụng
Nếu trang web của bạn sử dụng giao thức Https thì WebSocket phải sử dụng giao thức wss. Tuy nhiên, giao thức wss không hỗ trợ định dạng IP:port. Thay vào đó, nó chỉ có thể ghi tên miền + url. Giao thức https và WebSocket không thể kết nối, bạn có thể sử dụng Nginx thực hiện proxy ngược và thêm đoạn mã sau vào máy chủ trong tệp cấu hình trang web.
location /connectWorkman (tên tùy thuộc vào bạn, không sử dụng cùng tên với các proxy ngược khác) { proxy_pass http://127.0.0.1:8283; proxy_http_version 1.1; nâng cấp proxy_set_header Kết nối proxy_set_header; X-Real- IP $remote_addr }
Sử dụng giao diện người dùng (uniapp)
init() { SocketTask = uni.connectSocket({ url: 'wss://chat.gdpaimaihui.com/auction', //Tiêu đề chính thức: { 'content-type': 'application/json' }, thành công: function( res) { console.log('Đã tạo kết nối WebSocket', res); }, failed: function(err) { uni.showToast({ title: 'Ngoại lệ mạng! ', biểu tượng: 'none' }); console.log(err); } }); //sự kiện nghe websocket SocketTask.onOpen((res) => { socketOpen = true canReconnect = true console.log( 'Nghe sự kiện mở kết nối WebSocket. ', res); //Sau khi websocket được kết nối, bạn có thể bắt đầu hẹn giờ và thỉnh thoảng thực hiện đo nhịp tim để ngăn nhịp tim dừng lại và ngắt kết nối này.timer = setInterval(() => { SocketTask.send({ data: 'Heartbeat', Success() { // console.log('Gửi nhịp tim thành công'); } }) }, 2000) }); ( onError) => { console.log('Đang nghe lỗi WebSocket. Thông báo lỗi', onError socketOpen = false if (canReconnect) { this.reconnect() canReconnect); = false } }); SocketTask.onMessage((res) => { console.log('Lắng nghe sự kiện tin nhắn mà WebSocket nhận được từ máy chủ. Tin nhắn được máy chủ trả về', res); } }), / /Kết nối lại kết nối lại( ) { if (!socketOpen) { let count = 0; kết nối lạiInterval = setInterval(() => { console.log("Đang cố gắng kết nối lại") uni.showToast({ title: 'Đang cố gắng kết nối lại', biểu tượng: 'none' }) this.init(); count++ console.log(); // Không còn kết nối lại sau một số lần nhất định if (count >= connectTimes) { clearInterval(reconnectInterval ) uni .showToast({ title: 'Ngoại lệ mạng hoặc lỗi máy chủ', biểu tượng: 'none' }) } }, kết nối lạiDelay) } }
Trên đây là nội dung mình biên soạn khi đang làm phần mềm truyền thông nội bộ cho công ty. Nếu có sai sót xin chỉ giáo. Nếu thấy hay thì hãy nhấn vào để giới thiệu và theo dõi nhé! Cảm ơn bạn~๑·́₃·̀๑ [花][花][花].
Cuối cùng, bài viết này về [workerman] uniapp+thinkPHP5 sử dụng GatewayWorker để đạt được giao tiếp thời gian thực kết thúc tại đây. Nếu bạn muốn biết thêm về [workerman]uniapp+thinkPHP5 sử dụng GatewayWorker để đạt được giao tiếp thời gian thực, vui lòng tìm kiếm bài viết CFSDN. tiếp tục Duyệt các bài viết liên quan, tôi hy vọng bạn sẽ ủng hộ blog của tôi trong tương lai! .
Sử dụng docker để xây dựng giải pháp đồng bộ hóa nhật ký phân tán ELK
bản tin - tin tức/bản tin về lập trình và phát triển phần mềm
Đã đóng. Câu hỏi này không đáp ứng các nguyên tắc của Stack Overflow. Nó hiện không chấp nhận câu trả lời. Bạn muốn cải thiện vấn đề này? Cập nhật câu hỏi để nó được đưa lên đầu trang
https - Giao tiếp https của Neo4j
Có cách nào để chỉ cho phép https chứ không phải http giao tiếp với máy chủ Neo4j không? Ngoài ra, Neo4j Shell sử dụng kênh nào để liên lạc, http hoặc https? Câu trả lời hay nhất đến từ Neo4j
Giao tiếp PHP MYSQL với địa chỉ từ hai bảng
Xin chào, tôi có câu hỏi mới :) Tôi đang xây dựng một bản tin đơn giản có bảng điều khiển để gửi email đến những người dùng đã đăng ký và một địa chỉ email nhận bản tin. Tôi có mã này nhưng bản tin chỉ được gửi cho người dùng đã đăng ký. Có ai có thể cho tôi biết tại sao không? $zapytanie = của tôi
Giao tiếp RS232 C. Làm thế nào để so sánh thời gian CPU?
Lần đầu đăng bài nên có thể có nhiều thông tin hơn mức cần thiết, nhưng tôi muốn nói kỹ: Một trong những bài tập C của chúng ta là tạo chương trình phát và thu để trao đổi dữ liệu với modem null thông qua giao tiếp nối tiếp RS232. Chúng tôi đã sử dụng chương trình cổng ảo (nếu bạn muốn kiểm tra, tôi đã sử dụng
php - JS <---> Giao tiếp PHP
c++ - Giao tiếp qua RS485
Tôi có một máy tính bo mạch đơn được kết nối với một thiết bị khác qua RS485. Máy tính sẽ gửi yêu cầu đến thiết bị và nhận phản hồi (sử dụng các giao thức dành riêng cho thiết bị). Tôi có thể gửi tin nhắn mà không gặp vấn đề gì và thiết bị nhận được chúng (ví dụ: tôi có thể thay đổi các thông số của thiết bị)
c# - Thành phần ActiveX không thể tạo đối tượng? Giao tiếp .NET
Tôi hiện đang cố gắng tham khảo thư viện .NET COM trong ứng dụng Visual Basic 6 của mình. Tôi đã đăng ký nó bằng Regasm và đặt ComVisible thành true trong lớp của tôi. Nhưng
.net - Giao tiếp iOS <-> USB của PC
Đã đóng. Câu hỏi này cần được tập trung hơn. Hiện tại nó không chấp nhận câu trả lời. Bạn muốn cải thiện vấn đề này? Cập nhật câu hỏi để nó chỉ tập trung vào một câu hỏi bằng cách chỉnh sửa bài đăng này
ssl - Giao tiếp Archiva Jenkins qua https
Tôi đang cố gắng thiết lập liên lạc giữa Archiva và Jenkins qua giao thức https nhưng tôi gặp phải lỗi sau: [CẢNH BÁO] Không thể truyền siêu dữ liệu .
java - Máy khách/máy chủ giao tiếp socket đa luồng
Tôi đã hoàn thành chương trình giao tiếp socket máy khách/máy chủ hoạt động tốt. Bây giờ tôi muốn tìm ra cách thực hiện điều này để có thể có nhiều kết nối máy khách đến máy chủ cùng một lúc. Tôi đã xem xét xung quanh và dường như có nhiều cách khác nhau để thực hiện việc này. Vì thế tôi ở đây để nói với bạn
html - Làm cách nào để ngăn Outlook phá vỡ kích thước div? (giao tiếp)
Tôi đang tạo một bản tin trong mailchimp và tôi gặp phải sự cố này khi sử dụng Outlook, nó liên tục can thiệp vào hai cột của tôi như minh họa: Đây là một phần mã:
android - Ghi đè kích thước phông chữ tối thiểu của ứng dụng Gmail cho Android (Giao tiếp)
Tôi đang tạo một bản tin và sau rất nhiều nỗ lực, nó hoạt động ở mọi nơi ngoại trừ ứng dụng gmail dành cho Android. Vấn đề là nó dường như có kích thước phông chữ tối thiểu, khiến bảng của tôi bị hỏng. Có cách nào để khắc phục kích thước phông chữ tối thiểu mà không cần truy vấn phương tiện không
Trình mô phỏng Android (JAVA) và chia sẻ giao tiếp socket C++
C++ với tư cách là Máy khách xem bản rõ sang bản in clipboard? Mã sao chép như sau: // Client.cpp: Xác định mục nhập poi
Sitecore ECM Communications: liên kết đến trang web không hoạt động từ hộp thư đến
Tôi đã tạo một Bản tin ECM chứa một số liên kết trang web (một dự án khác). Trong phiên bản trực tuyến của NewsLetter, liên kết hoạt động tốt nhưng khi tôi gửi NewsLetter này đến email của mình và cố gắng nhấp vào thư của tôi
iphone - Giao tiếp HTML/CSS, truy vấn @media không thay đổi kích thước văn bản trên iPhone
Vì bất kỳ lý do gì, việc thay đổi kích thước văn bản của tôi không hoạt động bình thường trên iPhone nhưng hoạt động tốt trên Android và các định dạng email khác. Dường như không thể thấy bất kỳ sự khác biệt nào giữa hai tập tin. Hình ảnh cũng thay đổi kích thước, có vẻ như đó chỉ là vấn đề với văn bản.
asp.net - Bản tin HTML hàng loạt trong Asp.Net
Tôi đang phát triển một trang web và tôi cần gửi bản tin HTML tới danh sách gửi thư. Tôi đã tạo khung html chứa liên kết "xem trong trình duyệt" và "hủy đăng ký" (lý do sẽ khác nhau). Trong mô-đun quản trị tôi xuất bản html và ht
c - Lỗi giao tiếp I2C B-L072Z-LRWAN (master) và Arduino (slave)
Tôi đang cố gắng thực hiện giao tiếp I2C giữa B-L072Z-LRWAN(Master) và Arduino(Slave). Tôi gửi thành công dữ liệu từ chủ đến nô lệ bằng mã sau: Mã B-L072Z-LRWAN: #
Sitecore ECM Communication: ECM tạo ra các giá trị khác nhau cho các liên kết bên trong tin nhắn khi nhấp vào nút Gửi và Kiểm tra
Tôi có Bản tin ECM chứa một số liên kết đến một trang web (dự án khác). Khi tôi gửi bản tin này đến email của mình bằng cách nhấp vào nút gửi - các liên kết không hoạt động khi tôi nhấp vào chúng từ hộp thư đến email của mình. nó hiển thị 404
Học mẫu thiết kế (2) Mẫu nhà máy-Mẫu nhà máy trừu tượng-6ren
Học mẫu thiết kế (2) Mẫu nhà máy - Mẫu nhà máy vật tượng - Mục lục Bối cảnh Tóm tắt Mẫu nhà máy Ưu điểm và nhược điểm Bài viết tham khảo Bối cảnh Bây giờ tôi cần phát triển một mô-đun vận hành máy ảnh, có thể chạy trên Windows hoặc Linux. Nhà sản xuất
Thời gian cập nhật: 2024-07-05 19:05:35
lý lịch
model house object object
Ưu điểm của point point
Bài viết tham khảo
Bây giờ tôi cần phát triển một mô-đun vận hành máy ảnh, mô-đun này có thể chạy trên Windows hoặc Linux do nhà sản xuất cung cấp. Sự khác nhau giữa SDK trong Windows và SDK trong Linux, nên đối với một máy ảnh thương mại, chúng tôi cần tạo hai lớp để gói gọn API của hai Nền tảng khác nhau này.
Lớp sơ đồ như sau:
Đoạn mã tương ứng (không cần con trỏ thông minh, nếu không sẽ khó vẽ sơ đồ lớp):
class BaslerCamera { public: virtual ~BaslerCamera() = mặc định; bool Virtual OpenCamera() = 0; lớp LinuxBaslerCamera: public BaslerCamera { public: ~LinuxBaslerCamera() ghi đè = mặc định bool OpenCamera() ghi đè { return true; lớp WindowsBaslerCamera : public BaslerCamera { public: ~WindowsBaslerCamera() ghi đè = mặc định; OpenCamera() ghi đè { return true; } }; Lớp CreateBaslerCamera() = 0; LinuxCameraFactory : public CameraFactory { public: BaslerCamera* CreateBaslerCamera() ghi đè { trả về LinuxBaslerCamera new(); } }; lớp WindowsCameraFactory : public CameraFactory { public: BaslerCamera* CreateBaslerCamera() ghi đè { return new WindowsBaslerCamera() } }; //Client int main() { //Nếu bạn thay đổi nền tảng, khách hàng mã hóa chỉ cần sửa CameraFactory* cameraFactory = new LinuxCameraFactory( ); cameraFactory->CreateBaslerCamera(); camera->OpenCamera();
Bây giờ nếu một máy ảnh nhãn hiệu mới được thêm vào: Ốm, thì ý tưởng thiết kế mẫu phương thức nhà máy, lớp nhà vật tượng và lớp nhà máy công cụ tương thích sẽ được tạo cho nó (công cụ có thể bị bỏ qua).
Nhưng phân tích sâu hơn cho thấy rằng đối với mô-đun này, nó chạy trên Windows hoặc Linux. icon BaslerCamera và SickCamera, LinuxBaslerCamera và LinuxSickCamera đều được khởi tạo hoặc WindowsBaslerCamera và WindowsSickCamera được khởi tạo.
Có thể nói, các loại camera khác nhau được chia thành hai sản phẩm: camera Linux và camera Window. cho từng camera hiệu nhãn mà chỉ sử dụng hai Factory là WindowsCameraFactory và LinuxCameraFactory. chúng.
Sau đó, code của lớp máy chủ sẽ như thế này:
lớp CameraFactory { public: virtual ~CameraFactory() = mặc định; virtual BaslerCamera* CreateBaslerCamera() = 0; virtual SickCamera* CreateSickCamera() = 0; }; class LinuxCameraFactory : public CameraFactory { public: BaslerCamera* CreateBaslerCamera() ghi đè { trả lại mới LinuxBaslerCamera(); } Ghi đè SickCamera* CreateSickCamera() { return new LinuxSickCamera(); } }; class WindowsCameraFactory : public CameraFactory { public: BaslerCamera* CreateBaslerCamera() ghi đè { return new WindowsBaslerCamera() } SickCamera* CreateSickCamera(); ghi đè { trả về mới WindowsSickCamera() } };
Điều này dẫn đến mô hình nhà máy vật thể.
Sample Summary Factory cung cấp một giao diện để tạo ra một loạt đối tượng có liên quan hoặc phụ thuộc lẫn nhau mà không có chỉ định các lớp cụ thể của chúng.
sản phẩm sản phẩm ProductA1, ProductA2, ProductB1 và ​​​​ProductB2 là việc phát triển các loại công cụ của hai sản phẩm Vật tượng tương ứng với LinuxBaslerCamera, WindowsBaslerCamera, LinuxSickCamera và WindowsSickCamera trong ví dụ.
Tóm tắtFactory là một lớp cơ sở vật chất của nhà máy, tương thích với CameraFactory trong ví dụ. ConcreteFactory1 và ConcreteFactory2 là các máy cụ thể, tương ứng với LinuxCameraFactory và WindowsCameraFactory trong ví dụ.
Đối với máy khách, một công cụ xuất phiên bản thường có thể được tạo trong mã hóa (phiên bản này tương thích với một dòng sản phẩm) và phiên bản sản xuất này được sử dụng để tạo các sản phẩm cụ thể trong dòng sản phẩm.
Mã khách hàng như sau:
int main() { /* If trên nền windows, chỉ cần thay đổi câu này thành: CameraFactory* cameraFactory = new WindowsCameraFactory(); */ CameraFactory* camera_factory = new LinuxCameraFactory(); ảnh->OpenCamera(); = camera_factory->CreatSickCamera(); disease_Camera->OpenCamera();
Mã hoàn chỉnh như sau:
class BaslerCamera { public: virtual ~BaslerCamera() = mặc định; bool Virtual OpenCamera() = 0; lớp LinuxBaslerCamera: public BaslerCamera { public: ~LinuxBaslerCamera() ghi đè = mặc định bool OpenCamera() ghi đè { return true; lớp WindowsBaslerCamera : public BaslerCamera { public: ~WindowsBaslerCamera() ghi đè = mặc định; OpenCamera() ghi đè { return true; } }; OpenCamera() = lớp CameraFactory { công khai: ảo ~CameraFactory() = mặc định; BaslerCamera Virtual* CreateBaslerCamera() = 0; ; lớp LinuxCameraFactory : public CameraFactory { public: BaslerCamera* CreateBaslerCamera() ghi đè { return new LinuxBaslerCamera() } SickCamera* CreateSickCamera() ghi đè { return new LinuxSickCamera(); } }; class WindowsCameraFactory : public CameraFactory { public: BaslerCamera* CreateBaslerCamera() ghi đè { return new WindowsBaslerCamera() } SickCamera* CreateSickCamera () ghi đè { trả về WindowsSickCamera new(); () { //Nếu trên nền tảng windows, chỉ cần thay đổi câu này thành CameraFactory* cameraFactory = new WindowsCameraFactory(); CameraFactory* camera_factory = new LinuxCameraFactory(); ->OpenCamera(); disease_Camera->OpenCamera();
lợi thế:
Dễ dàng thay đổi dòng sản phẩm
: Quá trình khởi động máy chủ chỉ cần diễn ra một lần trên máy khách, giúp dễ dàng chỉnh sửa.
thiếu sót:
Nhà cung cấp vi phạm quy tắc đóng mở
)
Huaray Camera
WindowsHuarayCamera
LinuxHuarayMáy ảnh
Ngoài ba loại sản phẩm (điều này là cần thiết), bạn cũng phải sửa đổi
Máy ẢnhNhà Máy
Máy chủ Linux ẢnhNhà máy
Máy chủ Windows ẢnhNhà máy
Loại nhà máy này vi phạm nguyên tắc đóng mở.
Nguyên tắc đóng mở trái phép của khách hàng
: Khách hàng yêu cầu ngay từ đầu
CameraFactory* camera_factory = LinuxCameraFactory new();
, nếu muốn chuyển sang nền Windows, bạn cần sửa đổi kiểu khởi động theo cách thủ công, điều này vi phạm nguyên tắc mở và đóng. quả.
Những cải tiến đối với mẫu nhà máy vật thể sẽ được thảo luận trong bài viết tiếp theo.
1. "Mẫu thiết kế Dahua".
Design Pattern Learning (2) Factory Pattern - Mẫu nhà máy vật tượng kết thúc tại đây. Tôi hy vọng bạn sẽ ủng hộ blog của tôi trong tương lai .
Làm cách nào để người mới bắt đầu thử nghiệm hiệu quả càng sớm càng tốt?
Tiêm một dịch vụ (nhà) vào một dịch vụ (nhà) khác, cả hai đều không đồng bộ
Tôi nên làm như sau: Có thể thông báo một dịch vụ/nhà máy, sử dụng API truy vấn $q (async) để lấy một tập dữ liệu lớn về tên Có một dịch vụ khác (cũng không có đồng bộ) sẽ chỉ trả về các phần tử từ nhà máy nếu chúng khớp với một chuỗi mục tiêu phù hợp (tìm kiếm) phù hợp để giảm bớt
Nhà máy C# để phát triển công cụ khai thác cơ sở dữ liệu
Tôi có một lớp cơ sở chung. Tôi có một cơ sở phát triển lớp cơ sở. nhà máy để cung cấp các loại công cụ khác nhau? Ví dụ: lớp công khai ReceptBase trong đó T : IInte
Nhà Ninject cho các loại đường dẫn xuất ra
Tôi đang xem tiện ích mở rộng Ninject Factory tại liên kết sau: http://www.planetgeek.ch/2011/12/31/ninject-extensions-factory-intro
oop - Sự khác biệt giữa nhà cung cấp và dịch vụ?
Sự khác biệt giữa các điều khoản nhà máy, nhà cung cấp và dịch vụ là gì? Vừa phải tìm hiểu về NHibernate và kho lưu trữ mẫu của nó (các lớp POCO, vv). chọn loại dựa trên bất kỳ bối cảnh nào
Nhà Javassist - Cài đặt tải tùy chọn lớp
Sử dụng CGLIB tôi có thể thực hiện var Enhancer = new Enhancer();
Nhà Kotlin dành cho các lớp lồng nhau trong
Tôi đang cố gắng tạo một lớp bên trong lồng nhau trong Kotlin bằng cách sử dụng phương thức xuất xưởng đối tượng Đây là phiên bản mã hóa đơn giản của lớp tôi. OuterClass { var myData:L
Nhà Java với các loại chung
Về cơ bản, dự phòng dự án bao gồm một ứng dụng máy khách và tôi muốn tạo một gói để liên lạc với gói dữ liệu. nội dung. Bây giờ tôi có thể có một vấn đề khác
Nhà máy C++ có tính năng kế thừa
(6 câu trả lời lời) Object sl là gì?
Nhà máy C++.
Tôi muốn mọi ứng dụng bên ngoài sử dụng giao diện của lớp Socket, bao gồm một số lớp (ServerSocketTCP, ClientSocketTCP, ServerSocke
javascript - Nhà máy AngularJS
Tôi chưa quen với Angularjs và tôi đang cố gắng tạo ra một cơ sở dữ liệu nhỏ về phim. Đây là lần đầu tiên tôi sử dụng. nhà máy và tôi muốn chắc chắn rằng đây là cách tiếp cận đúng và cách nào tôi có thể sử dụng nhà máy này trong một chức năng khác như bên dưới?
Java - nhà máy, ví dụ
Câu hỏi này đã có câu trả lời ở đây: Lớp bên trong Java và lớp lồng tĩnh (28 câu trả lời) Đã đóng 5 năm trước lớp. DataFactory công khai
Nhà máy C++ (loại)
Tôi đã xem rất nhiều bài viết về các nhà máy C++, nhưng cho đến nay tôi vẫn chưa tìm ra giải pháp nào cho vấn đề của mình. (Mặc dù tôi có thể thiếu thứ gì đó.) Mẫu điều khiển bảng ứng dụng: #include #include #include
Mẫu đơn máy C++
Đây là một dự án đơn giản C++ đơn giản với 2 thiết kế mẫu: singleton và Factory sigleton cũng là một lớp được tạo mẫu mã, một giao dịch giao diện (IHash) và một lớp (Hash1). Một lớp nhà máy đơn giản (Hash
Nhà máy Java cho các lớp chung
Câu hỏi này tương tự như Factory và generics và có thể có cùng một câu trả lời, nhưng lại khác. được mở rộng bởi các lớp trong một JAR hoàn toàn riêng biệt. nào khác
Máy chủ JavaScript với các tùy chọn tham số
Vấn đề là tôi phải tạo một lớp mới có thể được truyền vào. chấp nhận bất kỳ số lượng đối số nào không? hàm createInstance(ofClass, arg1, arg2, arg3, ...
Nhà máy C++ createObject()
Tôi muốn tạo một phương thức xuất xưởng đơn giản bằng cú pháp C++ đơn giản: void *createObject(const char *str,...) { if(!strcmp("X",str)) retu
php - Di chuyển giữa máy chủ/Nhà vật thể
Sau khoảng 10 tháng học trình cài đặt PHP, giờ tôi đang cố gắng bắt đầu với các nguyên tắc cơ bản OOP và các thiết kế mẫu. Đây là một sở hữu và tôi không có nhiều thời gian để theo đuổi nó, vì vậy xin lỗi ở mức độ thấp của câu hỏi này. Trang web của tôi (hiện tại là chương trình 100%
cơ sở dữ liệu - Nhà Laravel - tạo hoặc động
Tôi có một câu hỏi đơn giản. tôi có một máy đơn giản /**
Angular: Mô-đun tải lười biếng không được gọi đến máy tiêmToken
Tôi đang cố gắng cung cấp mã thông báo APP_BASE_HREF trong mô-đun được tải từng phần, tuy nhiên, phương thức sản xuất vườn hoàn chỉnh không được gọi. Đây https://github.com/MaurizioCascia
Typescript AST Factory - Cách sử dụng chú thích?
Tôi có ast sau: import { Factory as f } from 'TypeScript' const typeDeclaration = f.createTypeAliasDeclara
ELK-6ren
Sử dụng docker để xây dựng giải pháp đồng bộ hóa bản phân phối ELK - ELK là giải pháp đồng bộ hóa bản nhật ký được Hình thức kéo dài ELK được sử dụng phổ biến nhất trong các ngành. nguồn tăng tốc độ trong nước tương đối cũ. nhật ký lưu trữ (-6ren
Thời gian cập nhật: 2024-07-05 19:07:35
Docker Hình do ELK kéo bằng nguồn tăng tốc trong nước tương đối cũ. Sự kiện có thể lấy nguồn từ trang web chính thức. lấy dữ liệu để phân tích trực tiếp API giao diện thông tin của eaticsearch. trình tạo ra với elaticsearch.
Xây dựng Elaticsearch.
docker run -d --name elasticsearch -p 9200:9200 -p 9300:9300 -e "discovery.type=single-node" -e "xpack.security.enabled=false" elasticsearch:8.14.1
Trong số đó, Discovery.type bị bắt buộc, nếu không quá trình khởi động sẽ không thành công. xpack.security.enabled bị sai, vì mặc định giá trị là đúng. Theo yêu cầu mặc định, elaticsearch quyền truy cập được quyền.
Xây dựng kibana.
docker run -d --name kibana --link elasticsearch -p 5601:5601 kibana:7.17.22
Thông số liên kết thông số của docker, no được liên kết với vùng chứa elaticsearch vừa được tạo và mặc định dữ liệu will be link Elaticsearch access data information qua API. điền sai, công việc cần được cấu hình vào lúc này.
Xây dựng một trang Web.
docker run -d --name web -p 5000:80 -v /Logs:/app/Logs -v /etc/localtime:/etc/localtime -e TimeZone=Asia/Shanghai webapplication1:latest
Kéo hình ảnh trang web và vùng khởi động. -v /etc/localtime:/etc/localtime được sử dụng để đồng bộ hóa thời gian của máy chủ và -e TimeZone=Asia/Shanghai được sử dụng để đồng bộ hóa giờ của máy chủ.
-v /Nhật ký:/ứng dụng/Nhật ký Bước này rất quan trọng.
Xây dựng Logstash.
Logstash cần cấu hình các tham số trước khi khởi động máy nhân.
đầu vào { file { path => "/Logs/*.txt" start_position => "bắt đầu" } } lọc { } đầu ra { elasticsearch { máy chủ => ["http://192.168.3.105:9200"] chỉ mục => " logstash-%{+YYYY.MM.dd}" } }
Đầu vào là nguồn đầu vào Chọn tệp. Đầu ra là nguồn đầu ra. điền sai khi xây dựng vùng chứa eaticsearch, bạn cần định cấu hình quyền tại thời điểm này.
docker run -d --name logstash -v /Logs:/Logs -v /root/logstash.conf:/usr/share/logstash/pipeline/logstash.conf logstash:7.17.22
Logstash.conf vào đó.
Nhật ký làm chương trình tạo ra sẽ được đồng bộ hóa với kết nối thông tin máy chủ thông qua kết nối, sau đó được đồng bộ hóa vào vùng chứa logstash sẽ đọc dữ liệu thường xuyên và ghi dữ liệu vào thư viện. for parsing.
Truy cập giao diện trực quan kibana cho phép phân tích đồng bộ hóa nhật ký theo thời gian thực Theo cổng vùng chứa và địa chỉ IP của tôi, địa chỉ trang web kibana của tôi là: http://192.168.3.105:5601.
Các bài viết khác trong loạt bài
Xây dựng hệ thống kiến trúc ứng dụng tích hợp, có thể mở rộng, có tính sẵn sàng cao, an toàn, tự động, có thể theo dõi và tích hợp
Cuối cùng, bài viết này về việc sử dụng docker để xây dựng giải pháp đồng bộ hóa nhật ký phân tán ELK kết thúc tại đây. Nếu bạn muốn biết thêm về cách sử dụng docker để xây dựng giải pháp đồng bộ hóa nhật ký phân tán ELK, vui lòng tìm kiếm các bài viết CFSDN hoặc tiếp tục duyệt các bài viết liên quan. tất cả sẽ ủng hộ blog của tôi trong tương lai! .
Các tình huống có thể áp dụng cho StringBuilder và StringBuffer trong JAVA là gì?
[Java/Log] Khung ghi nhật ký in trạng thái thực thi của mã ghi nhật ký ứng dụng
0 Giới thiệu Tôi thường nghĩ rằng khi định cấu hình cấp độ nhật ký INFO, mã ghi cấp độ gỡ lỗi logger (logger) trong mã ứng dụng sẽ không được thực thi (ví dụ: hàm printTestLog trong Thử nghiệm 1). Nhưng vấn đề trực tuyến ngày nay,
17. Nhật ký cấp độ
Nhật ký Nhật ký là giao diện chính của công cụ xây dựng. Nếu có quá nhiều nhật ký, các cảnh báo và vấn đề thực sự có thể dễ dàng bị ẩn đi. Mặt khác, nếu có sự cố xảy ra, bạn cần tìm hiểu những thông tin liên quan. Gradle xác định 6 cấp độ nhật ký, như được hiển thị trong Bảng 18.1, "Mức nhật ký". Ngoại trừ những người bạn biết
182. Khắc phục sự cố và gỡ lỗi HBase: Nhật ký
Nhật ký Nhật ký quá trình chính như sau... (thay thế bằng người dùng đã khởi động dịch vụ, thay thế bằng tên máy tính) NameNode: $HADOOP_HOME/logs/hadoop- -namenode-.log Da
Nhật ký Git của thay đổi tiếp theo đối với một dòng tệp cụ thể trong nhánh từ xa
Tôi đang khám phá lịch sử git của dự án FFMpeg. Tôi đã thực hiện các thay đổi đối với từng tệp giữa các lần xác nhận 517573a67088b5c7a25c18373434e3448892ee93 và 80bb65fafab1d2f5f.
biểu thức chính quy - nhật ký. Tìm kiếm bằng biểu thức chính quy
Tôi không biết cách tìm kiếm bằng biểu thức chính quy trong loggly. Ví dụ: sử dụng biểu thức /24nonstop.+7554/ để ghi lại nội dung tôi muốn tìm.
Nhật ký API Magento
Có cách nào để bật tính năng ghi nhật ký lệnh gọi API không? Chúng tôi có một ứng dụng của bên thứ ba đang gặp sự cố khi sử dụng cửa hàng của chúng tôi và muốn nhận một số thông tin gỡ lỗi. ~ Tôi đã tìm kiếm bt và không tìm thấy gì. Tôi đang sử dụng 1.7 Câu trả lời hay nhất trong một khoảng thời gian được kiểm soát
Nhật ký SVN cho các đường dẫn cố định trên các bản sao và di chuyển
Tôi đang cố gắng lấy lịch sử nhật ký của một đường dẫn cố định cho tất cả các bản sao/di chuyển/vv trong SVN (đệ quy nếu có thể). Thực ra, tôi đang cố tránh sửa đổi chốt và áp dụng nhật ký cho đường dẫn thay vì đối tượng. Hướng dẫn sử dụng svn hỏi câu hỏi này
nhật ký nant với dữ liệu và dấu thời gian
Làm cách nào tôi có thể chạy tập lệnh NAnt trong dòng lệnh và nhận thời gian của từng tác vụ trong tệp nhật ký? sử dụng nhiệm vụ nant hoặc NAnt -buildfile:testscript.build testnanttarg
Nhật ký tác nhân người dùng Coldfusion?
Có cách nào mặc định để ghi lại tác nhân người dùng nào đã truy cập vào máy chủ của bạn không? Tôi cần lập danh sách các trình duyệt truy cập trang web của chúng tôi để chúng tôi biết những gì chúng tôi có thể hỗ trợ tốt nhất. Cảm ơn! Nhật ký câu trả lời hay nhất CGI.HTTP_USER_AGENT, có thể ở A
mùa xuân - logJavaMailSenderImpl
Tôi đang sử dụng Spring trong ứng dụng của mình để gửi email. Tôi muốn ghi lại hoạt động của máy chủ imap khi gửi email. Tôi cố gắng triển khai đăng nhập vào applicationContext.xml của mình như sau:
Ghi nhật ký Kubernetes - bắt đầu từ đầu
Tôi đã chạy một nhóm được hơn một tuần và chưa khởi động lại nó kể từ đó. Tuy nhiên, tôi vẫn không thể xem nhật ký kể từ khi nó bắt đầu, nó chỉ cung cấp nhật ký của hai ngày qua. Có chính sách xoay vòng nhật ký nào cho vùng chứa không và làm cách nào tôi có thể kiểm soát việc xoay vòng dựa trên kích thước hoặc ngày? Tôi đã thử lệnh sau
elaticsearch - Tất cả dữ liệu nhật ký, số liệu và phân tích nên được nhóm vào một hồ dữ liệu hay được lưu trữ riêng biệt?
Bối cảnh: Tôi đang thiết lập ngăn xếp linh hoạt đầu tiên của mình và mặc dù tôi sẽ bắt đầu đơn giản nhưng tôi muốn đảm bảo rằng mình bắt đầu với một kiến trúc tốt. Cuối cùng tôi muốn có một giải pháp cho: Số liệu được lưu trữ, Nhật ký máy chủ (expressjs APM), Giám sát ứng dụng trang đơn (AP
Nhật ký thủy ngân với một dòng
Lệnh hg log thông thường cung cấp ít nhất 4 dòng đầu ra cho mỗi bộ thay đổi. Ví dụ: tập thay đổi: 238:03a214f2a1cf người dùng: Tên tôi ngày: Th
java - Ghi nhật ký - Cách xóa thông tin cơ sở dữ liệu trong tệp nhật ký
Tôi đang sử dụng khung Spring iBatis trong dự án của mình. Sau đó sử dụng logback để ghi lại. Sau đó khi kiểm tra file log mình thấy cơ sở dữ liệu hệ thống đang sử dụng... Mình muốn ẩn nó đi vì mục đích bảo mật ở đây là log mẫu.. 12:2
Nhật ký thủy ngân giữa hai thẻ
Tôi muốn sử dụng nhật ký hg để tạo nhật ký thay đổi ngắn bao gồm các thay đổi phiên bản mới nhất. Các bản phát hành được đánh dấu bằng tiền tố "v", chẳng hạn như "v0.9.1" hoặc "v1.0". Có thể sử dụng revsets để chọn phạm vi giữa hai thẻ cuối cùng bắt đầu bằng "v", không
PHP - In đối tượng ra bàn điều khiển/nhật ký của chức năng phụ trợ
Tôi mới làm quen với PHP vì vậy xin vui lòng tha thứ cho tôi nếu có câu trả lời đơn giản. Tôi đã tìm kiếm bất kỳ câu hỏi tương tự nào trên stackoverflow nhưng không thể tìm thấy bất kỳ trợ giúp nào. Tôi đang phát triển một ứng dụng dựa trên php hiện có và tôi chỉ cần có khả năng chuyển đổi các đối tượng
Nhật ký RADIUS của Linux
Tôi có một chương trình tên là Radius xác thực thông tin đăng nhập của người dùng. Nhật ký chạy trên máy chủ CentOS nằm trong /var/log/radius.log và chúng như sau: Thứ Hai ngày 24 tháng 7 22:17:08 2017: Tự động
Ghi nhật ký Python - Cách kiểm soát động mức ghi nhật ký
Gần đây tôi đã chuyển từ sử dụng "log" sang "log". Cho đến nay, rất tốt, nhưng tôi đang thiếu một tính năng chính - khả năng thay đổi mức thấp nhất trong thời gian chạy. Trong 'ghi nhật ký', tôi có thể gọi myLogger.setLevel(logging.I
Thiết kế theo dõi/ghi nhật ký cho các hệ thống quan trọng về tốc độ
Giả sử chúng tôi có các hệ thống quan trọng về tốc độ (ví dụ: thống kê/phân tích, lập trình socket, v.v.), làm cách nào để chúng tôi thiết kế theo dõi và ghi nhật ký. Cụ thể hơn, việc ghi nhật ký và theo dõi thường làm giảm hiệu suất (ngay cả khi chúng tôi có cơ chế tắt máy hoặc cơ chế mở rộng quy mô kéo dài). Trong trường hợp này, có lời khuyên nào về cách "đặt"
Học mẫu thiết kế (2) Mẫu nhà máy - Mẫu nhà máy trừu tượng + Sổ đăng ký-6ren
Học mẫu thiết kế (2) Mẫu nhà máy - Mẫu nhà máy trừu tượng + Sổ đăng ký - Mục lục Lời nói đầu Sử dụng Cải tiến nhà máy đơn giản Sử dụng Tài liệu tham khảo cải tiến sổ đăng ký Lời nói đầu Trong bài viết trước, chúng tôi đã đề cập đến một số thiếu sót của phiên bản đầu tiên của mã mẫu nhà máy trừu tượng: ① Khách hàng Kết thúc vi phạm nguyên tắc đóng mở ② Nhà cung cấp vi phạm nguyên tắc open-6ren
Học mẫu thiết kế (2) Mẫu nhà máy - Mẫu nhà máy trừu tượng + Sổ đăng ký
Thời gian cập nhật: 2024-07-09 21:03:39
Sử dụng các cải tiến nhà máy đơn giản
Sử dụng cải tiến đăng ký
Trong bài viết trước, chúng tôi đã đề cập đến một số thiếu sót của phiên bản đầu tiên của mã mẫu nhà máy trừu tượng: ① Máy khách vi phạm nguyên tắc mở và đóng ② Nhà cung cấp vi phạm nguyên tắc mở và đóng. Bài viết này sẽ thảo luận về hai điểm này.
Về thiếu sót ①, chúng ta có thể sử dụng ý tưởng về một nhà máy đơn giản để cải thiện phiên bản đầu tiên của mã nhà máy trừu tượng. Đối với ví dụ trong bài viết trước, chúng tôi đã loại bỏ CameraFactory, BaslerCameraFactory và SickCameraFactory và thay thế chúng bằng lớp SimpleFactory.
Sơ đồ lớp như sau:
Mã này như sau:
// Lớp nhà máy SimpleFactory { public: BaslerCamera* CreateBaslerCamera() { if ("Linux" == os_name_) { return New LinuxBaslerCamera(); } else if ("Windows" == os_name_) { return New WindowsBaslerCamera() } else if ("Windows" == os_name_) { return new WindowsBaslerCamera(); { return nullptr; } } SickCamera* CreateSickCamera() { if ("Linux" == os_name_) { return new LinuxSickCamera(); } else if ("Windows" == os_name_) { return new WindowsSickCamera(); } else { return nullptr; } } public: std::string os_name_ = "Linux" }; /Client int main() { SimpleFactory* camera_factory = new SimpleFactory(); camera_factory->CreateBaslerCamera(); basler_Camera->OpenCamera(); SickCamera* disease_Camera = camera_factory->CreateSickCamera(); disease_Camera->OpenCamera();
Lưu ý rằng mặc dù phương pháp trên đã cải thiện được nhược điểm ① nhưng nhược điểm ② vẫn tồn tại.
Về khuyết điểm ②, bản chất là: khi thêm sản phẩm mới, việc sửa đổi hạng nhà máy vi phạm nguyên tắc đóng mở. Đối với tình huống này, chúng ta có thể tham khảo sổ đăng ký được đề cập trong "Học mẫu thiết kế (2) Mẫu nhà máy - Mẫu phương thức nhà máy + Sổ đăng ký" để loại bỏ các phán đoán nhánh như chuyển đổi hoặc nếu và tách rời khớp nối do các phán đoán nhánh gây ra.
Đối với một sản phẩm cụ thể, chúng ta có thể đăng ký nó như thế này:
lớp LinuxBaslerCamera: public BaslerCamera { public: ~LinuxBaslerCamera() ghi đè = mặc định; bool OpenCamera() ghi đè { return true; } };
Sau đó, mã của lớp nhà máy có thể được đơn giản hóa thành:
class SimpleFactory { public: BaslerCamera* CreateBaslerCamera() { std::string name = os_name_ + "Basler"; return Object::CreateObject
(name); } SickCamera* CreateSickCamera() { std::string name = os_name_ + "Bệnh"; trả về Object::CreateObject
(name); std::string os_name_ = "Linux" };
Bằng cách này, khi thêm dòng sản phẩm (chẳng hạn như thêm HarmonyOS), chúng ta chỉ cần sử dụng ReflectRegister để đăng ký vào tệp tương ứng với lớp sản phẩm bên dưới nó, sau đó thay đổi os_name_ (tất nhiên, os_name_ cũng có thể được thay đổi từ tệp cấu hình khi đang tải, điều này tốt hơn).
Để thêm sản phẩm mới vào dòng sản phẩm hiện có (chẳng hạn như thêm máy ảnh Huaray), chức năng CreateHuarayCamera vẫn cần được thêm vào lớp xuất xưởng.
Cuối cùng, bài viết này về Học mẫu thiết kế (2) Mẫu nhà máy - Mẫu nhà máy trừu tượng + Mẫu đăng ký kết thúc tại đây Nếu bạn muốn biết thêm về Học mẫu thiết kế (2) Mẫu nhà máy - Mẫu nhà máy trừu tượng + Đăng ký cho nội dung của bảng. , vui lòng tìm kiếm các bài viết của CFSDN hoặc tiếp tục duyệt các bài viết liên quan. Tôi hy vọng bạn sẽ ủng hộ blog của tôi trong tương lai! .
Phiên bản MybatisPlus3.X chèn vào phân tích mã nguồn chiến lược IdType.ID_WORKER của id tự tăng
Thuật toán Dotnet và cấu trúc dữ liệu: Hashset, So sánh danh sách
Cách xử lý khi Red Hat không còn duy trì CentOS
Cạm bẫy và câu trả lời khi chuyển các lát Golang làm tham số hàm
Góc nhìn đầy đủ về giao tiếp Docker: nguyên tắc, thực tiễn và hiểu biết kỹ thuật-6ren
Góc nhìn đầy đủ về giao tiếp Docker: nguyên tắc, thực tiễn và hiểu biết kỹ thuật - Bài viết này thảo luận một cách toàn diện và chuyên sâu về công nghệ giao tiếp container Docker, từ các khái niệm cơ bản, mô hình mạng, thành phần cốt lõi đến các ứng dụng thực tế. Nó giới thiệu các chế độ mạng khác nhau và cách triển khai chúng một cách chi tiết, cung cấp chi tiết kỹ thuật và các trường hợp thực tế về giao tiếp container, đồng thời nhằm mục đích cung cấp cho những người hành nghề chuyên nghiệp những hiểu biết sâu sắc về kỹ thuật và thực hành-6ren
Góc nhìn đầy đủ về giao tiếp Docker: nguyên tắc, thực tiễn và hiểu biết kỹ thuật
Thời gian cập nhật: 2024-07-17 10:58:41
Bài viết này thảo luận một cách toàn diện và chuyên sâu về công nghệ truyền thông container Docker, từ các khái niệm cơ bản, mô hình mạng, các thành phần cốt lõi đến các ứng dụng thực tế. Nó giới thiệu các chế độ mạng khác nhau và cách triển khai chúng một cách chi tiết, cung cấp chi tiết kỹ thuật và các trường hợp thực tế về giao tiếp container, đồng thời nhằm mục đích cung cấp cho những người hành nghề chuyên nghiệp những hiểu biết sâu sắc về kỹ thuật và hướng dẫn vận hành thực tế.
Theo dõi [TechLeadCloud] để chia sẻ kiến thức toàn diện về kiến trúc Internet và công nghệ dịch vụ đám mây. Tác giả có hơn 10 năm kinh nghiệm về kiến trúc dịch vụ Internet, kinh nghiệm nghiên cứu và phát triển sản phẩm AI cũng như kinh nghiệm quản lý nhóm. Ông có bằng thạc sĩ tại Đại học Tongji thuộc Đại học Fudan, thành viên của Phòng thí nghiệm Trí tuệ Robot Fudan, kiến trúc sư cấp cao được chứng nhận bởi Alibaba Cloud. , chuyên gia quản lý dự án, nghiên cứu và phát triển các sản phẩm AI với doanh thu hàng trăm triệu người phụ trách.
1. Giới thiệu
Khi kiến trúc điện toán đám mây và vi dịch vụ ngày càng hoàn thiện, Docker, với tư cách là một công nghệ đóng gói nhẹ, đã trở thành thành phần chính trong quá trình phát triển và triển khai phần mềm hiện đại. Bằng cách cung cấp một môi trường chạy biệt lập cho các ứng dụng, các bộ chứa Docker không chỉ cải thiện đáng kể hiệu quả triển khai mà còn nâng cao tính di động và bảo mật của hệ thống. Tuy nhiên, khi các ứng dụng được đóng gói mở rộng về quy mô và độ phức tạp, giao tiếp giữa các container đã trở thành thách thức cốt lõi trong việc xây dựng các dịch vụ đám mây hiệu quả và đáng tin cậy.
Giao tiếp vùng chứa Docker đề cập đến việc trao đổi dữ liệu giữa các phiên bản vùng chứa và giữa các vùng chứa với thế giới bên ngoài (chẳng hạn như các vùng chứa khác, hệ thống máy chủ, tài nguyên Internet). Giao tiếp này là nền tảng của việc xây dựng kiến trúc microservice dựa trên container. Nó hỗ trợ cộng tác và chia sẻ dữ liệu giữa các dịch vụ, đồng thời là cơ sở để hiện thực hóa các tính năng chính như khám phá dịch vụ, cân bằng tải và bảo mật mạng.
Sự phát triển của công nghệ truyền thông
Từ liên kết đơn giản ban đầu đến mô hình mạng tiên tiến hiện tại, công nghệ truyền thông container Docker đã trải qua quá trình phát triển đáng kể. Ban đầu, giao tiếp vùng chứa Docker chủ yếu dựa vào các liên kết, đây là cơ chế giao tiếp cơ bản cho phép các vùng chứa nhận dạng và kết nối trực tiếp với nhau bằng tên. Tuy nhiên, với sự phức tạp ngày càng tăng của các ứng dụng được đóng gói, phương thức giao tiếp đơn giản này không còn có thể đáp ứng được nhu cầu.
Trong những năm gần đây, với sự phát triển và cải tiến liên tục của các chức năng mạng Docker, như Overlay Network và Macvlan, việc liên lạc giữa các container đã trở nên linh hoạt và đáng tin cậy hơn. Các mô hình mạng tiên tiến này cung cấp các khả năng mạng phức tạp hơn, chẳng hạn như giao tiếp giữa các máy chủ, cách ly mạng cũng như quản lý và kiểm soát lưu lượng chi tiết.
Ví dụ: trong ứng dụng thương mại điện tử có kiến trúc microservice, các dịch vụ khác nhau (chẳng hạn như xử lý đơn hàng, quản lý hàng tồn kho, xác thực người dùng) có thể được triển khai trong các vùng chứa khác nhau. Những vùng chứa này cần giao tiếp hiệu quả và an toàn để đảm bảo tính nhất quán của dữ liệu và tính liên tục của quy trình kinh doanh. Trong trường hợp này, mạng lớp phủ của Docker cung cấp khả năng liên lạc giữa các container trên nhiều máy chủ trong khi vẫn đảm bảo tính bảo mật và cách ly lưu lượng mạng.
Tác động của tiến bộ công nghệ
Với sự gia tăng của các công cụ điều phối container như Kubernetes, công nghệ truyền thông container phải đối mặt với những thách thức và cơ hội mới. Kubernetes không chỉ cung cấp khả năng quản lý container mạnh mẽ hơn mà còn giới thiệu các mô hình mạng phức tạp hơn, chẳng hạn như CNI (Giao diện mạng container), thúc đẩy hơn nữa sự phát triển của công nghệ truyền thông container.
2. Tổng quan về giao thông container
Trước khi đi sâu vào cách triển khai và công nghệ cụ thể của giao tiếp vùng chứa Docker, điều quan trọng là phải hiểu các khái niệm và nguyên tắc cơ bản của giao tiếp vùng chứa. Giao tiếp container không chỉ là nền tảng của công nghệ container mà còn là chìa khóa để xây dựng kiến trúc microservice hiệu quả và đáng tin cậy.
Nguyên tắc cơ bản của giao tiếp container
Giao tiếp vùng chứa Docker dựa trên công nghệ mạng, không gian tên và ảo hóa của Linux. Mỗi bộ chứa Docker chạy trong không gian tên mạng riêng, nghĩa là nó có một ngăn xếp mạng độc lập (bao gồm địa chỉ IP, bảng định tuyến, số cổng, v.v.). Giao tiếp giữa các container cần phải đạt được thông qua một loạt giao diện mạng và quy tắc định tuyến.
Phân loại các phương thức truyền thông
Giao tiếp container có thể được chia thành hai loại chính: giao tiếp trực tiếp và giao tiếp gián tiếp.
giao tiếp trực tiếp
Giao tiếp trực tiếp đề cập đến kết nối mạng trực tiếp giữa các container. Ví dụ điển hình nhất là chế độ mạng mặc định của Docker - chế độ cầu nối, trong đó container được kết nối với cầu ảo của máy chủ thông qua giao diện mạng ảo để đạt được giao tiếp giữa các container.
giao tiếp gián tiếp
Truyền thông gián tiếp liên quan đến các cấu trúc mạng phức tạp hơn như mạng lớp phủ. Trong mạng lớp phủ, giao tiếp giữa các vùng chứa đi qua lớp mạng ảo, cho phép các vùng chứa được phân phối trên các máy chủ khác nhau giao tiếp với nhau.
Các thành phần chính của giao tiếp container
Giao tiếp vùng chứa dựa trên một số thành phần chính, bao gồm daemon Docker, không gian tên mạng, cầu nối ảo, giao diện mạng ảo và trình điều khiển mạng.
Trình nền Docker
Trình nền Docker là cốt lõi của kiến trúc Docker và chịu trách nhiệm tạo, chạy và quản lý các vùng chứa. Nó cũng xử lý cấu hình mạng của vùng chứa, đảm bảo rằng vùng chứa có thể kết nối chính xác với mạng được chỉ định.
không gian tên mạng
Không gian tên mạng cung cấp một môi trường mạng biệt lập để mỗi vùng chứa có ngăn xếp mạng độc lập riêng. Tính năng này là chìa khóa để đạt được sự cách ly mạng giữa các vùng chứa.
Cầu ảo và giao diện mạng
Cầu ảo là cầu nối kết nối các giao diện mạng của các container khác nhau, cho phép các container chia sẻ cùng một mạng vật lý. Giao diện mạng ảo (chẳng hạn như cặp veth) là phương tiện để liên lạc giữa vùng chứa và máy chủ.
trình điều khiển mạng
Docker hỗ trợ nhiều trình điều khiển mạng khác nhau, chẳng hạn như cầu nối, lớp phủ, macvlan, v.v. Mỗi trình điều khiển cung cấp các tính năng và chức năng mạng khác nhau.
Những phát triển mới nhất trong công nghệ truyền thông container
Khi công nghệ container tiếp tục phát triển, công nghệ truyền thông container cũng đang phát triển. Ví dụ, một số nghiên cứu gần đây tập trung vào việc cải thiện hiệu suất của mạng container, giảm độ trễ mạng và nâng cao hiệu quả xử lý gói. Ngoài ra, an ninh mạng cũng trở thành chủ đề nghiên cứu nóng, đặc biệt là đảm bảo sự cách ly và bảo mật liên lạc giữa các container trong môi trường nhiều người thuê.
Nghiên cứu điển hình
Lấy một nhà cung cấp dịch vụ đám mây lớn làm ví dụ, họ có thể triển khai hàng nghìn container trong nhiều trung tâm dữ liệu để hỗ trợ các dịch vụ khác nhau. Trong môi trường này, việc giao tiếp hiệu quả giữa các container là rất quan trọng. Mạng lớp phủ đóng một vai trò quan trọng ở đây, không chỉ cung cấp khả năng liên lạc giữa các máy chủ mà còn hỗ trợ cân bằng tải và chuyển đổi dự phòng. Thiết kế mạng như vậy không chỉ đảm bảo tính sẵn sàng cao mà còn cải thiện hiệu suất mạng tổng thể.
3. Mô hình mạng Docker
Hiểu mô hình mạng của Docker là rất quan trọng để thành thạo giao tiếp vùng chứa. Docker cung cấp nhiều mô hình mạng để phù hợp với các nhu cầu triển khai và liên lạc khác nhau. Mỗi mô hình mạng có các đặc điểm và kịch bản sử dụng riêng, đồng thời hiểu rõ các mô hình này là nền tảng để thiết kế và triển khai các ứng dụng được đóng gói hiệu quả.
mạng lưới cầu
Mạng cầu nối là mô hình mạng mặc định của Docker và phù hợp với các container được triển khai trên một máy. Trong mô hình này, Docker tạo một cầu nối mạng ảo (docker0) và tất cả các container chạy trên cùng một máy chủ đều giao tiếp thông qua cầu nối ảo này.
Tính năng và công dụng
Sự cách ly
: Mạng cầu nối cung cấp một không gian tên mạng độc lập cho mỗi vùng chứa.
Dễ sử dụng
: Theo cấu hình mặc định, container có thể được sử dụng ngay mà không cần cấu hình phức tạp.
Các tình huống áp dụng
: Thích hợp cho các ứng dụng nhỏ hoặc môi trường phát triển được triển khai trên một máy.
mạng chủ
Ở chế độ mạng máy chủ, các thùng chứa chia sẻ không gian tên mạng của máy chủ. Điều này có nghĩa là các container giao tiếp không phải qua mạng ảo mà trực tiếp sử dụng giao diện mạng của máy chủ.
hiệu suất
: Cung cấp hiệu suất mạng cao hơn mạng ảo.
Không bị cô lập
: Không có sự cô lập trên mạng, hoạt động mạng của vùng chứa giống như máy chủ.
: Các vấn đề nhu cầu hiệu suất cao, xem xét các ứng dụng hoặc mạng dịch vụ có tải nặng.
No network
Trong mô hình không có mạng, vùng chứa cấu hình không có mạng giao diện. sử dụng yêu cầu bảo mật cao hoặc không yêu cầu mạng tương tác.
: Cung cấp cấp độ bảo mật cực cao vì không có quyền truy cập mạng bên ngoài.
: Các ứng dụng có yêu cầu bảo mật cực cao, có giới hạn như các hoạt động xử lý dữ liệu nhạy cảm.
lớp phủ mạng
Docker Swarm hỗ trợ kết nối container trên nhiều máy chủ Docker. một lớp mạng ảo để các container được phân phối trên các máy chủ khác có thể giao tiếp với nhau.
Giao tiếp giữa các máy chủ
: Hỗ trợ giao tiếp giữa các container chạy trên các máy chủ khác nhau.
: Các ứng dụng quy mô lớn được phát triển trên máy chủ nhiều máy chủ, được coi là kiến ​​trúc microservice.
mạng macvlan
Mạng Macvlan cho phép các container có địa chỉ MAC độc lập và được kết nối với vật lý mạng giống như vật lý thiết bị.
Truy cập trực tiếp vào vật lý mạng
: Các thùng chứa có thể hiển thị trực tiếp trên mạng giống như các vật lý.
: Các vấn đề cần xuất hiện trực tiếp trên vật lý mạng, suy nghĩ về các ứng dụng nhạy cảm các chức năng cần vượt qua mạng hóa ảo hóa.
Tiến bộ công nghệ và trường ứng dụng hợp lý
Với sự phát triển của công nghệ container, mô hình mạng Docker cũng không ngừng phát triển. tập trung cải thiện hoạt động và hiệu suất của mạng mô hình cũng như hỗ trợ các cấu trúc và chính sách network phức tạp hơn.
Trường hợp: Triển khai mô-đun microservice microservice
Trong quy mô microservice kiến ​​trúc lớn hơn, mỗi dịch vụ đều có thể được phát triển trên các máy chủ khác nhau. lớp phủ cung cấp một giải pháp lý tưởng, cho phép các giao tiếp tiếp nối vùng chứa giữa các máy chủ cung cấp cách thức và cần có mạng bảo mật. mà không phải lo lắng về sự phức tạp của cơ sở mạng.
4. Các thành phần cốt lõi của công cụ truyền thông công nghệ
Việc phát triển giao tiếp container phụ thuộc vào công việc cộng tác của nhiều thành phần cốt lõi. Sau đây là các thành phần cốt lõi của bộ chứa công nghệ truyền thông tin, mỗi thành phần đóng một vai trò không thể thiếu.
Trình nền Docker là trung tâm quản lý vòng đời của container. Docker nền chạy ở chế độ nền và tương tác với các dịch vụ và ứng dụng khác thông qua API Docker.
Chức năng cốt lõi
Quản lý vùng chứa
: Kiểm soát việc tạo, bắt đầu, dừng và các vòng đời sự kiện khác của vùng chứa.
: Cấu hình và quản lý cài đặt của vùng chứa mạng, bao gồm mạng chế độ, cổng xạ ảnh, vv
No network name
Không có mạng tên nào là một tính năng của nhân Linux cung cấp môi trường cài đặt đặc biệt cho mỗi vùng chứa. Điều này có nghĩa là mỗi vùng chứa. decan mạng môi trường.
cách thức
: Thực hiện cách ly mạng giữa các container.
Cấu hình độc lập
: Cung cấp cấu hình mạng độc lập cho từng container.
Cầu Đảo
Trọng Docker.
Thiết bị kết nối
: Cho phép nhiều giao tiếp mạng thiết bị trên cùng một mạng.
check Control line
: Quản lý và chuyển tiếp lượng lưu trữ qua bridge.
Virtual Network Interface
Trong giao tiếp tiếp theo vùng chứa, một điểm cuối được đặt bên trong vùng chứa và điểm cuối nhưng lại được kết nối với yêu cầu Ảo của máy chủ.
contact information
: Container kết nối mạng và máy chủ.
Truyền dữ liệu
: Cho phép truyền dữ liệu giữa các vùng chứa và máy chủ.
Network control
Docker cung cấp nhiều mạng điều khiển để hỗ trợ các mạng yêu cầu khác nhau. Hỗ trợ kết nối Chuẩn kết nối mạng được hỗ trợ, vùng liên kết hỗ trợ hỗ trợ lớp điều khiển chứa trên máy chủ và macvlan điều khiển có thể kết nối trực tiếp các vùng chứa với vật lý mạng.
Network model support
: Triển khai các mô hình truyền thông mạng khác nhau.
Cấu hình linh hoạt
: Cung cấp các tùy chọn và chiến lược cấu hình mạng khác nhau.
5. Hộp đựng giao tiếp Thực hành
Sau khi hiểu những điều cơ bản và các thành phần cốt lõi của giao tiếp tiếp theo, điều quan trọng phải áp dụng những lý do này đưa điều này vào các tình huống thực tế. vấn đề và công cụ hoạt động, bao gồm giao tiếp trực tiếp giữa các container, giao tiếp bên ngoài bằng cách sử dụng cổng xạ và kết quả tiếp theo giữa các container thông qua mạng Docker.
bản 1: Giao tiếp trực tiếp giữa các container
Trong kiến ​​trúc microservice đơn giản, dịch vụ A cần giao tiếp trực tiếp với dịch vụ B. Cả hai dịch vụ đều được phát triển khai trong các vùng chứa khác nhau trên cùng một máy chủ.
Thao tác các bước
Tạo mạng do người dùng xác định: Sử dụng docker mạng tạo lệnh để tạo mới kết nối mạng.
Khởi động các container: Sử dụng docker run để khởi động các container của dịch vụ A và dịch vụ B, đồng thời kết nối chúng with the network vừa được tạo.
Định cấu hình quy tắc mạng: Đảm bảo quy tắc mạng của các vùng được phép tiếp tục với nhau.
Kiểm tra giao tiếp: Sử dụng mạng công cụ (chẳng hạn như vòng tròn) trong vùng chứa dịch vụ A để kiểm tra giao tiếp tiếp theo dịch vụ B.
Tình huống 2: Sử dụng ánh xạ cổng để phát triển giao tiếp bên ngoài
Một ứng dụng web được triển khai trong vùng chứa Docker và cần được người dùng bên ngoài cho phép truy cập thông qua cổng của máy chủ.
Chuẩn bị ứng dụng: Chuẩn bị ứng dụng web và đảm bảo ứng dụng có thể chạy bình thường bên trong vùng chứa.
Ánh xạ cổng: Sử dụng lệnh docker run -p để khởi động vùng chứa và ánh xạ một cổng trên máy chủ tới cổng dịch vụ Web của vùng chứa.
Truy cập bên ngoài: Truy cập ứng dụng web từ bên ngoài thông qua địa chỉ IP của máy chủ và cổng được ánh xạ.
Kịch bản 3: Triển khai liên lạc giữa các container thông qua mạng Docker
Trong một ứng dụng phân tán, nhiều dịch vụ được triển khai trên các máy chủ khác nhau và cần phải đạt được sự liên lạc giữa các dịch vụ này.
Tạo mạng lớp phủ: Tạo mạng lớp phủ ở chế độ Docker Swarm.
Triển khai dịch vụ: Sử dụng docker service create để triển khai các dịch vụ khác nhau trên mạng lớp phủ.
Định cấu hình DNS: Sử dụng dịch vụ DNS tích hợp của Docker để đảm bảo rằng vùng chứa có thể phân giải địa chỉ của các dịch vụ khác thông qua tên dịch vụ.
Kiểm tra giao tiếp giữa các máy chủ: Kiểm tra giao tiếp trong vùng chứa của một dịch vụ với vùng chứa của dịch vụ khác.
Theo dõi [TechLeadCloud] để chia sẻ kiến thức toàn diện về kiến trúc Internet và công nghệ dịch vụ đám mây. Tác giả có hơn 10 năm kinh nghiệm về kiến trúc dịch vụ Internet, kinh nghiệm nghiên cứu và phát triển sản phẩm AI cũng như kinh nghiệm quản lý nhóm. Ông có bằng thạc sĩ tại Đại học Tongji thuộc Đại học Fudan, thành viên của Phòng thí nghiệm Trí tuệ Robot Fudan, kiến trúc sư cấp cao được chứng nhận bởi Alibaba Cloud. , chuyên gia quản lý dự án, nghiên cứu và phát triển các sản phẩm AI với doanh thu hàng trăm triệu người phụ trách. Nếu hữu ích, vui lòng chú ý nhiều hơn đến TeahLead KrisChang, hơn 10 năm kinh nghiệm trong ngành Internet và trí tuệ nhân tạo, hơn 10 năm kinh nghiệm quản lý nhóm kỹ thuật và kinh doanh, bằng cử nhân về công nghệ phần mềm tại Tongji, bằng thạc sĩ quản lý kỹ thuật đến từ Fudan, Kiến trúc sư cao cấp về dịch vụ đám mây được chứng nhận của Alibaba Cloud, Trưởng bộ phận kinh doanh sản phẩm AI với doanh thu trên 100 triệu.
Cuối cùng, bài viết này về quan điểm đầy đủ về giao tiếp Docker: nguyên tắc, thực tiễn và hiểu biết kỹ thuật sẽ kết thúc tại đây. Nếu bạn muốn biết thêm về quan điểm đầy đủ về giao tiếp Docker: nguyên tắc, thực tiễn và hiểu biết kỹ thuật, vui lòng tìm kiếm bài viết CFSDN hoặc tiếp tục Duyệt. các bài viết liên quan, hi vọng các bạn sẽ ủng hộ blog của mình trong tương lai! .
Từ DDPM đến DDIM
JavaJVM——12. Tổng quan về lý thuyết thu gom rác
Microsoft công bố tập trung vào .NET Aspire tại hội nghị nhà phát triển
Mẫu thiết kế-C# triển khai mẫu nhà máy đơn giản
docker - docker, docker không kiểm tra địa chỉ IP
Tôi đang sử dụng dockerfile sau: FROM ubuntu:14.04 MAINAINER xxx xxx # SSH RUN apt-get update && apt-get install
docker docker-compose không nhận được hình ảnh bộ đệm liên quan
Tôi đã chạy docker-compose build celery, (sau nhiều giờ thử và kết nối) nó đã hoạt động 80% lần đầu tiên của ứng dụng Dockerfile giống nhau. Nhưng bộ đệm không được sử dụng lại. Từ những gì tôi có thể duyệt,
docker - Tất cả các kho lưu trữ trong đăng ký Docker sẽ bị xóa sau khi docker khởi động lại nền tảng (docker-for-mac)
Tôi có thể tạo thành công dịch vụ đăng ký Docker v2 bằng lệnh sau: docker service create Sau đó, tôi sử dụng docker Push để đưa ra một số hình hình ảnh lên dịch vụ Khi tôi vượt qua Curl localh
docker - Không thể kết nối với docker daemon docker trong hình ảnh docker
gitlab, gitlab, gitlab, gitlab, gitlab, gitlab Đây là kết quả của việc xây dựng
docker - Giảm thiểu thời gian thực thi `docker build` bên trong vùng chứa Docker-in-Docker
Trường hợp sử dụng: Chúng tôi có một số "công việc phát hiện" trong ứng dụng xây dựng và cung cấp hình ảnh Docker của Jenkins sử dụng vào docker đăng ký, cập nhật phiên bản dự án trong nhiều tệp khác nhau và cuối cùng là đưa thẻ phát hành vào G tương thích ứng
docker - Docker của mình dùng
Khi tôi cố gắng xây dựng docker file của mình, docker trả lời lỗi sau: [+] Building 0.0s (1/2)
docker - Cách sử dụng docker trong đường ống jenkins mà không cần sử dụng docker-in-docker
Tác giả của docker-in-docker Khuyên bạn không nên sử dụng hình ảnh này cho CI mục tiêu trong blog này: jpetazzo/Using Docker-in-Docker for your CI or testing en
docker - Chạy Docker trong vùng chứa Docker: Không thể kết nối với daemon Docker
Tôi đã tạo một Dockerfile để chạy Docker trong Docker: FROM ubuntu:16.04 RUN apt-get update && \ apt-get in
docker - Làm cách nào để tìm hình ảnh Docker có thẻ cụ thể trong sổ đăng ký Docker từ Docker lệnh dòng?
Tôi đang cố gắng tìm một thẻ cụ thể để chọn Docker hình ảnh. tránh tải xuống tất cả các hình ảnh và sau đó xóa những hình ảnh tôi không cần thiết. https://registry.hub.do
docker - docker trong docker, đăng lỗi HTTP
Tôi đang chạy docker bên trong docker. muốn kiểm tra hiệu suất của docker khi chạy từ một docker khác. Tôi khởi động docker thông qua boot2docker trên Mac
docker - Docker: Tùy chọn trong docker-compose.yml để tự động phát triển lại hình ảnh mới
bản docker-compose.yml: "3" service: daggr: image: "docker.pvt phiên.com/test/daggr:stable"
docker - Truy cập Docker trong vùng chứa Docker
Trong một số mã, tôi đã khởi động vùng chứa để thu thập dữ liệu trang và truy xuất thông báo mã hóa cho dịch vụ (Gitlab) đang chạy trong vùng. Bây giờ, tôi muốn Dockerize chạy mã của nó. Cụ thể là đại loại như: o
docker - docker soạn thảo tập tin so với docker gói
Câu hỏi này đã được hỏi trước đây nhưng tôi không chắc liệu việc phát triển khai phá docker có thể được thực hiện bằng cách sử dụng các tệp docker-compose tại thời điểm đó hay không. Do sắp xếp bằng cách sử dụng tính năng chỉnh sửa nên tôi không thể hiểu được giá trị của tệp dữ liệu mà tôi kiểm tra.
docker - Sự khác biệt giữa docker pool và docker đăng ký là gì?
Tôi đã hỏi câu hỏi này trong một cuộc phỏng vấn và không thể trả lời được thông tin liên quan. đã thấy.
docker - docker: Làm cách nào để sao chép tất cả các tệp png trong docker vào máy chủ?
Docker cp docker cp docker cp container_name:path/to/file/in/docker/*.png path/o
docker
Nhật ký điều khiển của tôi đã được đặt thành tạp chí. Nhật ký cấp độ trong tệp daemon.json có ảnh hưởng đến nhật ký không? Khi sử dụng nhật ký docker sẽ chỉ cập nhật vùng chứa ký tự ảnh có bị ảnh hưởng không? Ví dụ: docker và jour
docker
Gần đây tôi đã bắt đầu sử dụng Docker + Celery. là một số đoạn mã từ đó giúp giải quyết quan điểm của tôi trong bối cảnh.
docker - docker: Không thể gửi hình ảnh docker được xây dựng
CMD ---> Use buffer ---> efc82ff1ca
docker - Docker + docker-composition + không thể khởi động dịch vụ
Docker-compose.yml chỉnh sửa, chúng tôi đang gặp lỗi sau docker-comp
docker - kho lưu trữ hình ảnh cơ sở docker bên ngoài docker hub?
Tôi mới làm quen với Docker. trên đám mây của bạn thay vì có tài khoản DH Cảm ơn? mình nếu muốn. Có thể tìm thấy ở Depl
Khái niệm cơ bản về phát triển iOS 109-Bảo mật mạng-6ren
iOS Development Basics 109 - Network Security - Trong quá trình phát triển iOS, việc đảm bảo an ninh mạng cho các ứng dụng là một mắt xích rất quan trọng. Sau đây là một số biện pháp bảo mật mạng phổ biến và mã mẫu tương ứng: Phiên bản Swift 1. Sử dụng HTTPS Đảm bảo rằng tất cả các yêu cầu mạng đều sử dụng giao thức HTTPS để mã hóa việc truyền dữ liệu, -6ren
Khái niệm cơ bản về phát triển iOS 109-Bảo mật mạng
Thời gian cập nhật: 2024-07-17 12:58:39
Trong quá trình phát triển iOS, việc đảm bảo an ninh mạng cho ứng dụng là một mắt xích rất quan trọng. Sau đây là một số biện pháp an ninh mạng phổ biến và mã mẫu tương ứng:
Phiên bản Swift
Đảm bảo rằng tất cả các yêu cầu mạng đều sử dụng giao thức HTTPS để mã hóa việc truyền dữ liệu và ngăn chặn các cuộc tấn công trung gian.
Mã mẫu:
Định cấu hình Bảo mật vận chuyển ứng dụng (ATS) trong Info.plist:
NSAppTransportSecurity
NSAllowsArbitraryLoads
2. Ghim SSL
Ghim SSL có thể đảm bảo rằng ứng dụng chỉ tin cậy chứng chỉ máy chủ được chỉ định và ngăn không cho nó bị tấn công vào máy chủ giả mạo.
nhập Lớp nền tảng URLSessionPinningDelegate: NSObject, URLSessionDelegate { func urlSession(_ session: URLSession, didReceive challenge: URLAuthenticationChallenge, CompleteHandler: @escaping (URLSession.AuthChallengeDisposition, URLCredential?) -> Void) { if let serverTrust = challenge.protectionSpace.serverTrust, SecTrustEvaluate(serverTrust, nil) == errSecSuccess, let serverCertificate = SecTrustGetCertificateAtIndex(serverTrust, 0) { let localCertificateData = try? Data(contentsOf: Bundle.main.url(forResource: "your_cert", withExtension: "cer")!) hãy để máy chủCertificateData = SecCertificateCopyData(serverCertificate) as Data if localCertificateData == serverCertificateData { let credential = URLCredential(trust: serverTrust) CompleteHandler(.useCredential, credential) return } } CompleteHandler(.cancelAuthenticationChallenge, nil) } } // Cách sử dụng let url = URL(string: "https://yoursecurewebsite.com")! let session = URLSession(configuration: .default, delegate: URLSessionPinningDelegate(), delegateQueue: nil) let task = session.dataTask(with: url) { data, reply, error in // Xử lý phản hồi } task.resume()
3. Ngăn chặn việc tiêm SQL
Sử dụng các truy vấn được tham số hóa để ngăn chặn các cuộc tấn công tiêm nhiễm SQL khi xử lý thông tin đầu vào của người dùng.
import SQLite3 func queryDatabase(userInput: String) { var db: OpaquePointer? // Mở cơ sở dữ liệu (giả sử dbPath là đường dẫn đến cơ sở dữ liệu của bạn) sqlite3_open(dbPath, &db) var queryStatement: OpaquePointer let query = "SELECT * FROM user WHERE username? = ?" if sqlite3_prepare_v2(db, query, -1, &queryStatement, nil) == SQLITE_OK { sqlite3_bind_text(queryStatement, 1, userInput, -1, nil) while sqlite3_step(queryStatement) == SQLITE_ROW { // Kết quả xử lý } } sqlite3_finalize(queryStatement) sqlite3_close(db) }
4. Mã hóa dữ liệu
Khi lưu trữ dữ liệu nhạy cảm, hãy sử dụng thư viện mã hóa của iOS để mã hóa dữ liệu, chẳng hạn như sử dụng Chuỗi khóa.
import Security func saveToKeychain(key: String, data: Data) -> OSStatus { let query: [String: Any] = [ kSecClass as String: kSecClassGenericPassword, kSecAttrAccount as String: key, kSecValueData as String: data ] SecItemDelete(truy vấn dưới dạng CFDictionary ) // Xóa mọi mục hiện có return SecItemAdd(truy vấn dưới dạng CFDictionary, nil) // Thêm mới item } func LoadFromKeychain(key: String) -> Data? { let query: [String: Any] = [ kSecClass as String: kSecClassGenericPassword, kSecAttrAccount as String: key, kSecReturnData as String: kCFBooleanTrue!, kSecMatchLimit as String: kSecMatchLimitOne ] var dataTypeRef: AnyObject? hãy để trạng thái: OSStatus = SecItemCopyMatching(truy vấn dưới dạng CFDictionary, &dataTypeRef) if status == noErr { return dataTypeRef as?
5. Xác thực và làm sạch đầu vào
Xác thực và vệ sinh đầu vào của người dùng để ngăn chặn XSS (tập lệnh chéo trang) và các cuộc tấn công tiêm nhiễm khác.
func clean(userInput: String) -> String { // Xóa mọi thẻ script hoặc nội dung nguy hiểm tiềm tàng khác return userInput.replacingOccurrences(of: "
", with: "", options: .caseInsensitive) } // Cách sử dụng let userInput = "
" let được vệ sinhInput = vệ sinh(userInput: userInput) print(sanitizedInput) // Kết quả đầu ra: cảnh báo ('xss')
phiên bản OC
#import
@interface URLSessionPinningDelegate : NSObject
@end @implementation URLSessionPinningDelegate - (void)URLSession:(NSURLSession *)session didReceiveChallenge:(NSURLAuthenticationChallenge *)challenge CompleteHandler:(void (^)(NSURLSessionAuthChallengeDisposition, NSURLCredential * _Nullable credential))completionHandler { if ([challenge.protectionSpace.authenticationMethod isEqualToString:NSURLAuthenticationMethodServerTrust]) { SecTrustRef serverTrust = challenge.protectionSpace.serverTrust; = SecTrustGetCertificateAtIndex(serverTrust, 0); NSString *certPath = [[NSBundle mainBundle] pathForResource:@"your_cert" ofType:@"cer"]; *)(SecCertificateCopyData(serverCertificate)); if ([localCertData isEqualToData:serverCertData]) { NSURLCredential *credential = [NSURLCredential credentialForTrust:serverTrust]; CompleteHandler(NSURLSessionAuthChallengeCancelAuthenticationChallenge, nil); } @end // Cách sử dụng NSURL *url = [NSURL URLWithString:@"https://yoursecurewebsite.com"]; NSURLSessionConfiguration *sessionConfig = [NSURLSessionConfiguration defaultSessionConfiguration]; *pinningDelegate = [[URLSessionPinningDelegate alloc] init]; NSURLSession *session = [NSURLSession sessionWithConfiguration:sessionConfig delegate:pinningDelegate delegateQueue:nil]; NSURLSessionDataTask *task = [session dataTaskWithURL:url CompleteHandler:^(NSData *data, NSURLResponse *response, NSError *error) { if (error == nil) { // Xử lý phản hồi } }] [tiếp tục nhiệm vụ];
- (void)queryDatabase:(NSString *)userInput { sqlite3 *db; // Mở cơ sở dữ liệu (giả sử dbPath là đường dẫn đến cơ sở dữ liệu của bạn) if (sqlite3_open([dbPath UTF8String], &db) == SQLITE_OK) { câu lệnh sqlite3_stmt *; const char *query = "CHỌN * TỪ người dùng Ở ĐÂU tên người dùng = ?"; if (sqlite3_prepare_v2(db, query, -1, &statement, NULL) == SQLITE_OK) { sqlite3_bind_text(statement, 1, [userInput UTF8String], -1, SQLITE_TRANSIENT); while (sqlite3_step( câu lệnh) == SQLITE_ROW) { // Kết quả xử lý } } sqlite3_finalize(câu lệnh); sqlite3_close(db);
- (OSStatus)saveToKeychainWithKey:(NSString *)key data:(NSData *)data { NSDictionary *query = @{(__bridge id)kSecClass: (__bridge id)kSecClassGenericPassword, (__bridge id) kSecAttrAccount: khóa, (__bridge id)kSecValueData: data}; SecItemDelete((__bridge CFDictionaryRef)query); // Xóa mọi mục hiện có return SecItemAdd((__bridge CFDictionaryRef)query, NULL); // Thêm mục mới } - (NSData *)loadFromKeychainWithKey:(NSString *)key { NSDictionary *query = @{(__bridge id)kSecClass: (__bridge id)kSecClassGenericPassword, (__bridge id)kSecAttrAccount: key, (__bridge id)kSecReturnData: (__bridge id)kCFBooleanTrue, (__bridge id)kSecMatchLimit: (__bridge id)kSecMatchLimitOne}; trạng thái OSStatus = SecItemCopyMatching((__bridge CFDictionaryRef)query, &dataTypeRef ); if (status == noErr) { return (__bridge_transfer NSData *)dataTypeRef; } else { return nil; }
- (NSString *)sanitize:(NSString *)userInput { // Xóa mọi thẻ tập lệnh hoặc nội dung nguy hiểm tiềm tàng khác NSString *sanitizedInput = [userInput stringByReplacingOccurrencesOfString:@"
" withString:@"" options:NSCaseInsensitiveSearch range:NSMakeRange(0,sanitizedInput.length)]; return cleanedInput; } // Cách sử dụng NSString *userInput = @"
"; NSString *sanitizedInput = [tự vệ sinh:userInput]; NSLog(@"%@", được vệ sinhInput); // Kết quả đầu ra: cảnh báo ('xss')
Thông qua các biện pháp này, bạn có thể cải thiện đáng kể tính bảo mật mạng của ứng dụng iOS của mình. Dựa trên nhu cầu của dự án, các công nghệ này được sử dụng linh hoạt để đảm bảo an toàn cho dữ liệu người dùng.
Cuối cùng, bài viết về iOS Development Fundamentals 109 - Network Security kết thúc tại đây. Nếu bạn muốn biết thêm về iOS Development Fundamentals 109 - Network Security, vui lòng tìm kiếm các bài viết về CFSDN hoặc tiếp tục duyệt các bài viết liên quan. tương lai blog của tôi! .
Trực quan hóa—gojs có nhiều chia sẻ kinh nghiệm thực tế (3)
Trình trang trí DjangoDRF@action
Giải mã bản đồ triển khai xsync
Nguyên tắc tổng hợp bảng tính có hiệu suất cao: Tiết lộ sự kỳ diệu của phản hồi cấp hai thuần túy của giao diện người dùng đối với hàng triệu hàng dữ liệu
io - IO được ánh xạ bộ nhớ - Làm thế nào để thiết bị IO biết giá trị đã thay đổi?
Làm thế nào để một thiết bị IO biết rằng giá trị trong bộ nhớ thuộc về nó đã thay đổi trong IO được ánh xạ vào bộ nhớ? ? Ví dụ: giả sử rằng địa chỉ bộ nhớ 0 được dành riêng để giữ màu nền của thiết bị VGA. Khi chúng ta thay đổi giá trị trong bộ nhớ[0], VGA
Lỗi đăng nhập Facebook iOS iOS SDK
Tôi hiện đang phát triển một ứng dụng iOS sử dụng sdk Facebook để đăng nhập (thông qua FBLoginView). Mọi thứ đều hoạt động tốt ngoại trừ những người có phiên bản facebook cũ hơn. Khi họ nhấn nút "Đăng nhập bằng Facebook", anh ấy
ios ios nsrange char từ cuối
Giả sử tôi có: đây - là một - ví dụ - với một số - dấu gạch ngangNSRange sẽ chọn phiên bản đầu tiên của "-" bằng cách sử dụng `rangeOfString:@"-", nhưng nếu tôi chỉ muốn phiên bản cuối cùng
Làm cách nào để lấy tên quốc gia từ SDK card.io? -iOS
Card.io SDK cung cấp các thông tin chi tiết sau: số thẻ, ngày hết hạn, tháng, năm, CVV và mã bưu chính. Làm cách nào tôi có thể lấy tên quốc gia từ SDK này. - (void)userDidProvideCreditCardInfo:(Ô tô
Làm cách nào để ứng dụng iOS tải xuống hình ảnh từ dịch vụ web và cài đặt chúng trên thiết bị iOS của người dùng trong khi cài đặt?
Làm cách nào để ứng dụng iOS tải xuống hình ảnh từ dịch vụ web và cài đặt chúng trên thiết bị iOS của người dùng trong quá trình cài đặt? Có thể được không? Câu trả lời hay nhất Bạn không có quyền kiểm soát việc cài đặt ứng dụng trên thiết bị của người dùng, do đó không thể tải xuống dữ liệu bổ sung trong quá trình cài đặt. Chỉ cần khởi chạy ứng dụng lần đầu tiên sau khi cài đặt
Sự khác biệt giữa Ứng dụng iOS Enterprise và Ứng dụng bán lẻ iOS
Tôi đã từng phát triển một sản phẩm iOS dành cho doanh nghiệp mà công ty chúng tôi đã bán cho các doanh nghiệp lớn để nhân viên của họ sử dụng. Ứng dụng này có sẵn thông qua AppStore và người dùng doanh nghiệp được cung cấp hồ sơ dành riêng cho công ty (chứa hồ sơ ứng dụng) để cho phép
Tích hợp Card.io ios với bản địa hóa
Tôi đang cố gắng tích hợp SDK Card.io vào ứng dụng iOS của mình. Tôi muốn thực hiện một bản địa hóa đơn giản cho giao diện người dùng CardIO, chẳng hạn như thay đổi tiêu đề nút hủy hoặc văn bản nhắc "Giữ thẻ tín dụng của bạn ở đây". Tôi tìm thấy cái này trên github
ios - Tên quét Card.Io iOS
Tôi đang sử dụng các lớp CardIOView và CardIOViewDelegate và không có BOOL nào có thể được đặt thành CÓ để quét collCardholderName. Tôi có thể thấy nó trong CardIOP
Làm cách nào để đặt trường tên cho ứng dụng ios gốc gần đây? -iOS
Tôi có một ứng dụng voip được tích hợp với bộ công cụ gọi điện. Mỗi lần tôi gọi từ ứng dụng voip của mình, một bản ghi cuộc gọi mới gần đây sẽ được tạo trong ứng dụng điện thoại gốc. Tôi cũng có danh bạ tùy chỉnh trong ứng dụng voip (điện thoại nên
Làm cách nào để ứng dụng iOS biết bàn phím đã ở trên màn hình hay chưa khi ứng dụng đang mở (đa nhiệm iOS)
Làm cách nào để ứng dụng iOS biết đã có bàn phím trên màn hình khi ứng dụng được mở? Sau khi ứng dụng đang chạy, nó có thể nhận được thông báo hiển thị/ẩn bàn phím. Tuy nhiên, nếu ứng dụng được mở dưới dạng ứng dụng phụ ở chế độ chia đôi màn hình và ứng dụng chính đã hiển thị bàn phím thì ứng dụng phụ sẽ không hiển thị
Lỗi IO hình ảnh trên iOS
Tôi gặp lỗi sau trong trình mô phỏng: ImageIO: CGImageReadSessionGetCachedImageBlockData *** CGImageReadSessionGetCachedIm
ios - Thiết bị iOS giao tiếp với các thiết bị không phải iOS
Như được trình bày trong tài liệu của Apple, việc giao tiếp với các phụ kiện được chứng nhận (được Apple chứng nhận) có thể được thực hiện thông qua EAAccessory Framework. Nhưng tôi hơi bối rối vì một số bài đăng cho tôi biết nó cũng hoạt động qua CoreBluetoo
ios - (iOS) Cách xem thông điệp tường trình trực tiếp trên thiết bị iOS?
Mặc dù các trình gỡ lỗi ngày nay rất tốt nhưng đôi khi cách tốt nhất để tìm hiểu những gì đang diễn ra trong ứng dụng của bạn vẫn là NSLog cũ. Việc này thật dễ dàng khi bạn kết nối với máy tính; Xcode sẽ giúp bật lên bảng Log Viewer và bạn đã sẵn sàng. khi bạn không ở nơi làm việc
ios - Kontakt.io iOS - Xác định các cảnh báo theo tên
Trong ứng dụng iOS của tôi, tôi xác định một số điểm ưa thích. Một số trong số chúng có tên là đèn hiệu Kontakt.io, được liên kết với một PoI cụ thể (ý tôi là tên thường được gắn vào nhãn đèn hiệu). Bây giờ tôi muốn khám phá các đèn hiệu gần đó,
Plugin Trigger.io iOS trả về dữ liệu từ cuộc gọi lại
Tôi đang tạo plugin trigger.io để nhận lời nhắc cảnh báo. Cố gắng trả lại dữ liệu từ lời nhắc cảnh báo. Đây là mã của tôi: // Nhắc + (void)show_Prompt:(ForgeTask*)task{
ios - Thông báo đẩy khác nhau như thế nào trong iOS 4, iOS 5 và iOS 6?
Xin chào, tôi mới làm quen với Apple iOS. Mình đã đọc và tìm kiếm rất nhiều bài viết về thông báo đẩy nhưng không tìm thấy thông tin nào về các bản cập nhật mới của APNS từ io4 lên ios 6. Ai có thể cung cấp cho tôi APNS cách thực hiện trong ios không
Chiều cao của UITabBar trên iOS 8, iOS 9, iOS 10 và iOS 11 là bao nhiêu?
Chiều cao của UITabBar dường như đã thay đổi giữa iOS 7 và 8/9/10/11. Tôi đăng câu hỏi này để giúp người khác dễ dàng tìm thấy câu trả lời. Sau đó: iOS 8/9/10/11 trên iPhone và iPad
ios - các phương pháp hay nhất. Làm cho ứng dụng iOS trở nên phổ biến bằng cách hỗ trợ giao diện người dùng iOS 5, iOS 6 và iOS 7
Tôi nghĩ tôi có thể sử dụng các Bảng phân cảnh khác nhau cho các phiên bản iOS khác nhau. Do có sự khác biệt về UI nên mình sẽ tạo Storyboard tiếp theo: Main_iPhone.storyboard Main_iPad.st
Làm cách nào để chọn một phần của bản âm thanh trong ios bằng điều khiển trực quan trong iOS?
Tôi đang viết nội dung nào đó trong đó tôi sẽ sử dụng một phần bản âm thanh từ thư viện iTunes của thiết bị để phủ lên sự kết hợp của 2 video, ví dụ: AVMutableComposition* mixComposition = [[AVMutableC
Tệp tiêu đề tồn tại trong trình mô phỏng iOS nhưng không tồn tại trên thiết bị iOS...?
Tôi đã tạo một chương trình iOS đơn giản có khả năng biên dịch mượt mà và chạy tốt trên trình mô phỏng iPad. Chương trình tương tự không biên dịch được khi tôi yêu cầu XCode 4 sử dụng thiết bị iPad được kết nối của mình. Có vẻ như vấn đề xảy ra khi tôi cố gắng sử dụng iPad kèm theo
Hình dung—gojs có nhiều kinh nghiệm thực tế chia sẻ (3)-6ren
Trực quan hóa - gojs có nhiều chia sẻ kinh nghiệm rất thực tế và rất thực tế (3) - Thư mục 32.go.Palette Hai liên tiếp 33.go.Palette Cách sử dụng cơ bản 34. Tạo kết nối của riêng bạn trỏ đến chính bạn 35. Đặt nhómTemplate và -6ren khác nhau
Thời gian cập nhật: 2024-07-17 13:02:39
32.go.Palette hai liên tiếp
33.go.Palette cách sử dụng cơ bản
34. Tạo kết nối của riêng bạn trỏ đến chính bạn
35. Đặt nhómTemplate và linkTemplate khác nhau
36. Nghe click chuột phải vào GraphObject
37. Xác định menu chuột phải trên nền nút/kết nối/canvas
38. Khi kéo động một kết nối từ một nút, hãy xác định xem hướng của nó là trái hay phải?
Giá trị định tuyến 39.linkTemplate
40. Thay đổi vị trí của tất cả các điểm khi di chuyển kết nối
go.Palette là một thành phần trong thư viện GoJS hiển thị một tập hợp các thành phần đồ họa được xác định trước mà người dùng có thể chọn và kéo và thả vào khung vẽ. Nếu bạn muốn hiển thị hai go.Palette liên tiếp, .
1. Bạn có thể sử dụng HTML và CSS để kiểm soát bố cục của chúng. Sử dụng display: inline-block để sắp xếp các phần tử div theo chiều ngang trong cùng một dòng.
Hình dung—gojs có nhiều kinh nghiệm thực tế chia sẻ (4)-6ren
Trực quan hóa - gojs có nhiều chia sẻ kinh nghiệm thực tế (4) - Mục lục 41. Nghe sự kiện sau khi kéo và thả kết nối hoàn tất 42. Nghe sự kiện sửa đổi canvas 43. Nghe sự kiện gọi lại sau khi nút bị xóa bởi del (dùng để thực hiện giao diện gọi thực hiện một số thao tác xóa Real) 44. Màn hình nút mouse-6ren
Trực quan hóa—gojs có nhiều chia sẻ kinh nghiệm thực tế (4)
Thời gian cập nhật: 2024-07-18 13:10:42
41. Theo dõi các sự kiện sau khi quá trình kéo và thả kết thúc
42. Nghe sự kiện sửa đổi của canvas
43. Nghe sự kiện gọi lại sau khi nút bị xóa bởi del (dùng để thực hiện giao diện gọi để thực hiện một số thao tác xóa thực tế)
44. Nghe các sự kiện di chuyển chuột vào và ra của nút và hiển thị các phần tử cụ thể sau khi di chuột
45. Bản đồ cây nghe thực hiện chức năng mở rộng hoặc thu gọn các nút con bằng cách nhấp vào chính nút đó thay vì nhấp vào nút khác.
46. Nghe sự kiện gọi lại sau khi chỉnh sửa khối văn bản hoàn tất (dùng để triển khai giao diện gọi để thực hiện một số thao tác chỉnh sửa và sửa đổi thực tế)
47. Sau khi soạn thảo văn bản xong, trạng thái chỉnh sửa có thể bị hủy sau khi nhấn Enter
Mô tả các thuộc tính/phương thức được sử dụng:
1. go.LinkingTool.prototype.doActivate
2. thuộc tính có thể định hình lại và phân đoạn lại
3. Vai trò của makeTwoWay trong go.Binding("text", "name").makeTwoWay() mới
4. Cách sử dụng Point cơ bản
5. Hàm dragTool.gridSnapCellSize
6.initialPosition tọa độ ban đầu
7. Sửa đổi kiểu mặc định của nút
8. Phóng to hoặc thu nhỏ, khôi phục và làm lại
9. Tìm các phần tử nút dựa trên các giá trị khóa và tìm các phần bên trong các phần tử
10.toolManager.hoverDelay
Bạn có thể sử dụng công cụ LinkingTool để theo dõi các sự kiện sau khi quá trình kéo kết nối kết thúc. Các bước cụ thể như sau:
Tạo một
Công cụ liên kết
dụ và đặt nó làm công cụ mặc định của biểu đồ:
myDiagram.toolManager.linkingTool = go.LinkingTool mới();
màn hình
doCancel()
doActivate()
Cách thực hiện các thao tác tương ứng sau khi kéo kết nối xong:
myDiagram.toolManager.linkingTool.doCancel = function () { // Sẽ được gọi khi người dùng hủy thao tác kéo và thả liên kết console.log("Đã hủy liên kết"); ; myDiagram.toolManager.linkingTool.doActivate = function () { // Sẽ được gọi là console.log("Liên kết đã hoàn thành"); go.LinkingTool.prototype.doActivate.call(this); };
Trong mọi trường hợp gojs, sẽ có một đoạn mã như vậy. Phương thức myDiagram.addDiagramListener('Modified', function() {...}) được sử dụng để lắng nghe sự kiện sửa đổi của canvas. được sửa đổi, hàm gọi lại tương ứng sẽ được thực thi. Tuy nhiên, phương pháp này không phù hợp để theo dõi liên tục, có nghĩa là nó chỉ có thể được kích hoạt sau khi mỗi sửa đổi được lưu.
// khi tài liệu được sửa đổi, thêm "*" vào tiêu đề và bật nút "Save" myDiagram.addDiagramListener("Modified", function (e) { var Button = document.getElementById("SaveButton"); if ( nút) nút.disabled = !myDiagram.isModified; var idx = document.title.indexOf("*"); console.log(111); if (myDiagram.isModified) { if (idx < 0) document.title += "*"; } else { if (idx >= 0) document.title = document.title.substr(0, idx } }); ;
Nếu bạn muốn theo dõi mọi thay đổi của khung vẽ và thực hiện thay đổi JSON tương ứng, sự kiện này sẽ được kích hoạt mỗi khi mô hình được sửa đổi và bạn có thể lấy dữ liệu JSON mới nhất trong hàm gọi lại. Nếu việc sửa đổi diễn ra thường xuyên và các thao tác tiếp theo phức tạp thì nên thêm một lớp chống rung vào chức năng sửa đổi.
myDiagram.addChangedListener((e) => { //Thực hiện thao tác thay đổi JSON tương ứng var jsonData = myDiagram.model.toJson(); });
Tên sự kiện để xóa các nút là SelectionDeleting. Bạn có thể sử dụng đoạn mã sau để nghe sự kiện xóa một nút và gọi giao diện:
myDiagram.addDiagramListener("SelectionDeleting", (e) => { const đã xóaObj = e.subject.first(); const deleteKey = đã xóaObj.part.data.key; });
Cơ chế xử lý sự kiện của GoJS được sử dụng để thực hiện chức năng hiển thị nút thêm nút khi chuột di chuột vào nút cây. Các bước triển khai cụ thể như sau:
Thêm thành phần nút vào mẫu nút để hiển thị nút thêm nút.
Thêm chức năng xử lý sự kiện di chuột vào mẫu nút. Khi chuột di chuột qua nút, nút thêm nút sẽ được hiển thị.
Thêm chức năng xử lý sự kiện di chuột ra trong mẫu nút. Khi chuột di chuyển ra khỏi nút, nút thêm nút sẽ bị ẩn.
Thêm chức năng xử lý sự kiện nhấp chuột vào mẫu nút thêm nút để thêm nút mới.
myDiagram.nodeTemplate = $( go.Node, "Auto", { mouseEnter: function (e, node) { // Khi chuột di chuột qua nút, nút thêm nút được hiển thị var addButton = node.findObject("addButton ") ; if (addButton) addButton.visible = true; }, mouseLeave: function (e, node) { // Khi chuột di chuyển ra khỏi nút, ẩn nút thêm nút var addButton = node.findObject("addButton"); , $(go.Shape, "RoundedRectangle", { fill: "white" }), $(go.TextBlock, { lề : 8 }, new go.Binding("text", "name")), $( go.Panel, "Horizontal", { căn chỉnh: go.Spot.BottomRight, dòng: 4 }, $( "Button", { name: "addButton",visible: false, click: (e, obj) => {} }, $(go.TextBlock, "+" ) ) ) );
// MyDiagram.addDiagramListener('ObjectSingleClicked', (e, obj) { var part = e.subject.part if (part instanceof go.Node) { if (part .isTreeExpanded ) { part.collapseTree() } else { part.expandTree() } } })
Bạn có thể sử dụng sự kiện TextEdited của lớp DiagramEvent để gọi lại hàm ở cuối quá trình chỉnh sửa văn bản. Sự kiện này được kích hoạt khi trình soạn thảo chỉnh sửa văn bản đã hoàn tất và bị đóng.
myDiagram.addDiagramListener("TextEdited", (e) => { const editText = e.subject.text; const key = e.subject.part.data.key; console.log("Nội dung đã chỉnh sửa: " + editText ) ; console .log("Khóa nút:", khóa });
Theo mặc định, sau khi người dùng chỉnh sửa xong khối văn bản. trình chỉnh sửa trạng thái của khối văn bản đang được chỉnh sửa và phím mặc định được nhấn Enter được coi là ngắt dòng.
Enter, tức là thao tác chỉnh sửa đã hoàn tất chứ không phải thay đổi dòng nên cần thay đổi một thuộc tính. để hoàn tất thao tác chỉnh sửa.
$( go.TextBlock, { editable: true, // Liệu nó có thể được chỉnh sửa hay không isMultiline: false, // Liệu nó có thể là nhiều dòng hay không, false }, new go.Binding("text", "tên") );
Phương thức này sẽ được gọi khi người dùng nhấp vào nút liên kết công cụ hoặc nhấn phím tắt công cụ liên kết.
Thuộc tính có thể định cấu hình lại: Cho biết nút dữ liệu có thể được định cấu hình lại hoặc không thể đặt thành true để có thể cấu hình lại nút. thay đổi hình dạng bằng cách kéo các cạnh hoặc góc.
được đặt thành đúng, kết nối của nút có thể được thêm hoặc xóa bằng cách kéo dài giữa các nút. kết nối của nút sẽ không thay đổi.
Phương thức makeTwoWay được sử dụng để đặt hai chiều liên kết thành liên kết trong GoJS, liên kết đến các liên kết. thuộc tính có mối liên hệ lại trong mô hình dữ liệu với các thuộc tính thuộc tính của đồ họa phần tử, hãy thực hiện khi một thuộc tính được thay đổi trong dữ liệu mô hình thì các thuộc tính của đồ họa phần tử cũng thay đổi tương thích ứng.
Khi bạn sử dụng phương thức makeTwoWay, link sẽ trở thành hai chiều, có nghĩa là khi thuộc tính của phần đồ họa tử tử đã thay đổi, các thuộc tính trong dữ liệu mô hình cũng thay đổi tương ứng. màn hình dữ liệu và đồ họa các phần tử sẽ trở nên thuận tiện và hiệu quả hơn.
Điểm là một lớp trong GoJS được sử dụng để thể hiện một điểm có thể được định nghĩa trên Sản phẩm hai chiều. được tìm thấy trong API GoJS tài liệu.
Trong GoJS, bạn có thể sử dụng go.Point(x, y) mới để tạo một Point đối tượng, trong đó x và y lần biểu tượng bùng nổ độ và độ của điểm. Ví dụ:
var point = go.Point mới(100, 200);
Bạn cũng có thể sử dụng phương thức Point.parse(str) để phân tích một chuỗi thành đối tượng Point.str là một chuỗi biểu tượng mode của một điểm.
var str = "100 200"; var point = go.Point.parse(str);
dragTool.gridSnapCellSize là một trong những thuộc tính thuộc tính của công cụ kéo trong gojs. while hold. bố cục gọn gàng và đẹp mắt hơn. Ví dụ: nếu bạn đặt dragTool.gridSnapCellSize thành 20, phần tử sẽ được kéo dài gắn vào đường viền 20 pixel. lưới.
myDiagram = $(go.Diagram, "myDiagramDiv", { "draggingTool.gridSnapCellSize": new go.Size(1, 5), });
Khi gojs tạo bản vẽ, đồ họa được đặt ở giữa khung vẽ theo mặc định. gojs được bố trí ở giữa. bạn muốn bản vẽ bắt đầu từ góc trên bên trái, bạn có thể:
var myDiagram = $(go.Diagram, "myDiagramDiv", { initPosition: new go.Point(0, 0), // Vị trí thư giãn ban đầu});
$( "Button", { width: 15, Height: 15, "ButtonBorder.fill": "green", // Thay đổi màu thành mặc định _buttonFillOver: "red", // Màu tô khi di chuột // _buttonStrokeOver: " #000", //Màu đường viền di chuột}, $(go.TextBlock, "Nút văn bản") );
// Phóng to myDiagram.scale += 0,1; // Giảm myDiagram.scale -= 0,1; // Khôi phục myDiagram.commandHandler.undo(); // Làm lại myDiagram.commandHandler.redo();
// Tìm các phần tử dựa trên khóa giá trị const node = diagram.findNodeForKey("key value"); // Tìm các phần tử trong phần tử: Tìm các phần có phần tên tử: TEXT và thay đổi màu phông chữ chữ thành màu đỏ node.findObject("TEXT") .đột ngột = "đỏ";
tính toolManager.hoverDelay chuột qua một biểu tượng thành phần.
Nếu it was set to 200, điều đó có nghĩa là sự kiện di chuột sẽ không được kích hoạt khi chuột di chuột qua Đồ họa phần tử trong 200 mili giây.
myDiagram = $(go.Diagram, "myDiagramDiv", { "toolManager.hoverDelay": 200, // delay});
Thời gian địu ToolTip mặc định được hiển thị bằng cách di chuột. Định nghĩa hơi dài.
$( go.TextBlock, { width: 100, maxLines: 1, tràn: go.TextBlock.OverflowEllipsis, }, new go.Binding("text", "name").makeTwoWay(), { toolTip: $("ToolTip ", $(go.TextBlock, new go.Binding("text", "name"))), } );
Nếu bạn muốn biết các bài viết liên quan tôi hy vọng bạn sẽ ủng hộ blog của tôi trong tương lai .
Nâng cao ComfyUI: Plug-in Comfyroll (3)
Cách viết vòng lặp trên Google Earth Engine bằng cách nôn ra máu.
Về cách sử dụng trực tiếp EFCore để thực hiện tạo bản cập nhật khổng lồ, kiểm tra người dùng, đồng thời liên lạc auto, delete phần mềm và truy vấn cây (Phần 1)
CSS: Bố cục linh hoạt (display:flex)
phương pháp công khai thinkphp5 để tải lên hình ảnh và tạo hình thu nhỏ (chia sẻ)
Tiếp theo tải lên mã, liệu có thể viết dưới dạng tệp công khai phổ biến và kế thừa lớp cơ bản để dễ dàng gọi không?
Hướng dẫn đồ họa về thiết lập môi trường máy chủ PHP (chia sẻ)
1. Xây dựng môi trường máy chủ PHP Cài đặt môi trường máy chủ 1.php trọng)\dl_learning\tải xuống các tài nguyên quan trọng\apache
Phím tắt PHPstorm (chia sẻ)
Như được hiển thị bên dưới: Phím tắt Eclipse Ctrl+1 Chỉnh sửa nhanh Ctrl+D: Xóa dòng hiện tại Ctrl+Alt+↓ Sao chép dòng hiện tại tại sang dòng tiếp theo (sao chép và tăng) Ctrl+Alt+↑ Sao chép dòng hiện tại sang dòng trước đó (sao chép và tăng)
Ví dụ về viết ứng dụng giao diện bằng php và trả về dữ liệu json (chia sẻ)
Bước đầu tiên: file conn.PHP, dùng để kết nối với cơ sở dữ liệu và xác định giao diện có định dạng, mã như sau: php" id="highlighter_808731">
Tổng hợp một số câu hỏi phỏng vấn kinh nghiệm bằng ngôn ngữ C trên Linux (chia sẻ)
Bài viết này đã tổng hợp một số câu hỏi phỏng vấn cổ điển về ngôn ngữ C trong Linux. nhiều người hiểu rõ hơn về ngôn ngữ C trong Linux. trình biên dịch GCC để thực hiện chương trình này trên Linux thì kết quả là gì?
Giải quyết nhanh chóng lỗi boost link thư viện (share)
Sau khi cài đặt thư viện Boost mới nhất, có một câu trong hướng dẫn chính thức: Cuối cùng, cài đặt $ ./b2 sẽ để lại các tệp nhị phân Boost trong thư mục con lib/
Ví dụ hoàn chỉnh MyBatis tích hợp mùa xuân (chia sẻ)
Để sắp xếp nội dung của "mybatis tích hợp mùa xuân (maven+mysql) 1" và "mybatis tích hợp mùa xuân (maven+mysql) 2" đã được nghiên cứu trước đó, tôi sẽ làm một ví dụ hoàn chỉnh để hoàn thành một chức năng quản lý thư viện đơn giản .
Mẹo kiểm soát giá trị trang website (chia sẻ)
Chất lượng nội dung website chỉ là một trong số điểm toàn diện của trang, dù thuật toán có thay đổi, điều chỉnh như thế nào thì công cụ tìm kiếm cũng sẽ không loại bỏ điểm toàn diện của trang web. Trong trường hợp thông thường, chúng tôi chia điểm toàn diện của trang thành 8 điểm: 1. Cài đặt tiêu đề (cài đặt tiêu đề phải là duy nhất)
Thông tin cơ bản về Android: Sử dụng các mảnh để thích ứng với các màn hình và độ phân giải khác nhau (Chia sẻ)
Gần đây mọi thứ rất bận rộn, tôi đang gấp rút khởi động một dự án mới, nhưng nhiều chức năng cần phải làm lại. Tôi đang viết mã và gỡ lỗi. Hôm nay, một chương trình mới cần được thực hiện bằng cách sử dụng các mảnh vỡ trước đây, nhưng hôm nay tôi chưa nghiên cứu kỹ về chúng.
Quy ước đặt tên tài nguyên Android (chia sẻ)
Thông số kỹ thuật đặt tên tài nguyên Android Trong những tháng gần đây, có rất nhiều công việc liên quan đến tài nguyên Android. Đối với các ứng dụng phức tạp, quy ước đặt tên tài nguyên là cần thiết. Ngoài các nhà phát triển, các nhà thiết kế giao diện người dùng (hoặc những người liên quan đến việc cắt sơ đồ) cũng cần phải nhận thức rất rõ về nơi sử dụng tài nguyên.
Một số thông tin chi tiết dựa trên bản đồ Mybaits (chia sẻ)
Tôi đã sử dụng Hibernate trước đây và về cơ bản chưa bao giờ sử dụng Mybatis. Tôi cần tạo các mối quan hệ ánh xạ tại nơi làm việc. Cả hai đều hỗ trợ một-một, một-nhiều và nhiều-nhiều. Chương này giới thiệu ngắn gọn cách sử dụng một-một và những điểm cần lưu ý.
Thảo luận ngắn gọn về phạm vi của các kiểu dữ liệu cơ bản trong java (chia sẻ)
Như được hiển thị bên dưới: ? 1
Chia sẻ phương pháp thiết lập bố cục View to FrameLayout tùy chỉnh của Android để hiện thực hóa hiển thị đa thành phần
Nếu bạn muốn hiển thị Button và các thành phần View khác trên View tùy chỉnh, bạn cần hoàn thành các tác vụ sau 1. Ghi đè xây dựng lớp cha trong lớp View tùy chỉnh (lưu ý là 2 tham số Sao chép mã như sau). : quán rượu
Ví dụ về triển khai kéo bảng tr trong java (share)
Chức năng thực hiện: thực hiện kéo bảng tr và lưu mức độ thay đổi do kéo mã jsp?
Bản demo đơn giản về Hẹn giờ và Hẹn giờ của Java (chia sẻ)
Mã: lớp kiểm tra java" id="highlighter_819000">?
Dựa trên nguyên tắc hoạt động chèn cây đỏ đen và phương pháp triển khai java (chia sẻ)
Cây đỏ là cây tìm kiếm cân bằng nhị phân. or black.
Demo dom4j vận hành xml (chia sẻ)
Không còn dòng dài nữa, hãy đi thẳng vào mã 1?
Mẹo cho phép chỉ định mức tối đa và tối thiểu trong Python (chia sẻ)
Khi mã hóa, nhân đôi khi bạn cần chỉ định các giá trị riêng theo phép so sánh kích thước: ?
Hướng dẫn cài đặt và sử dụng Git (chia sẻ)
Trong quá trình phát triển dự án thực tế, chúng tôi thường sử dụng một số phiên bản điều khiển để lưu trữ Hôm nay, chúng tôi sẽ tắt cách sử dụng Git có liên quan. trên github thông qua Git 1. Tải xuống và cài đặt Git 1. Tải xuống
Một lớp mã xác minh php đẹp (chia sẻ)
Tải trực tiếp mã hóa lên: Sao chép mã như sau: //Mã xác minh lớp lớp ValidateCode { Private $charset = 'abcdefghkmnprstuvwxyzABC
Cách lấy apple uid an toàn, imei-6ren
Cách lấy udid của Apple một cách an toàn, imei-[Nhấp để kiểm tra https://authapi.applekuid.com](https://authapi.applekuid.com/) Có nhiều cách để lấy udid ở Trung Quốc, ví dụ như Dandelion và các nơi khác trên web -6ren
Cách lấy apple uid, imei an toàn
Thời gian cập nhật: 2024-07-20 11:00:42
[Nhấp để kiểm tra https://authapi.applekuid.com](https://authapi.applekuid.com/) .
Hiện tại, có nhiều cách để lấy udid ở Trung Quốc. Về cơ bản bản văn, họ có thể vượt qua quá trình xác thực thông tin để ngụy trang để chắc chắn rằng thiết bị đó có thật.
## Làm thế nào để Apple có được sự thực sự đúng đắn?
Không có dưới một bài viết được tìm kiếm trên Baidu, nhưng không có bài nào an toàn hoặc có thể nói là an toàn để ngăn chặn udid giả.
1. Hướng dẫn người dùng cài đặt udid mô tả tệp 2. Sau khi cài đặt Đặt mô tả tệp, điện thoại di động sẽ gửi mẫu imei udid và các thông tin khác đến máy chủ.
Nhưng làm sao bạn biết nó đúng hay sai?
##Làm sao để biết nó đúng hay sai?
Rất tiếc, hiện tại không có phần mềm nào trên thị trường. Có nhiều phần mềm ngụy trang udid. sửa đổi thông tin qua phần mềm fiddler và nhiều phần mềm khác được duy trì bởi một số nhóm mà không có tác dụng gì.
Thực sự không thể ngăn chặn việc ngụy trang sao?
##Thật sự không thể ngăn chặn việc ngụy trang sao?
Tiếp theo, chúng ta hãy thử xem xét các phương pháp phổ biến để lấy uid.
1. Chuẩn bị Apple .mobileconfig mô tả tệp.
```.

Nội dung tải trọng
URL
http://xxx/app/uuid
Thiết bị thuộc tính
UDID
IMEI
ICCID
PHIÊN BẢN
SẢN PHẨM
Tổ chức tải trọng
www.yun-bangshou.com
Tên hiển thị tải trọng
xxx
Phiên bản tải trọng
Tải trọngUUID
8C7AD0B8-3900-44DF-A52F-3C4F92921807
Mã định danh tải trọng
com.yun-bangshou.profile-service
Mô tả tải trọng
Lấy số UDID của thiết bị iOS hiện tại
Loại tải trọng
Profile service
``` .
2. Đặt tệp trên web máy chủ.
3. Hướng dẫn tải liên kết người dùng.
4. Sau khi người dùng cài đặt thiết bị, thiết bị sẽ gửi thiết bị thông tin http://xxx/app/uu toid.
```
12 123456 123456 7
iPhone4,1
b59769e6c28b73b1195009d4b21cXXXXXXXXXXXX
9B206
Nhưng chỉ thế thôi là chưa đủ.
## Lấy nó có thực sự an toàn không?
Bằng cách chụp gói tin ([https://authapi.applekuid.com](https://authapi.applekuid.com/)) được yêu cầu 4 lần và cơ sở dữ liệu đã được mã hóa.
Cuối cùng, bài viết về cách lấy Apple uid và imei một cách hoàn toàn cuối cùng tại đây. cách an toàn, vui lòng tìm kiếm bài viết CFSDN hoặc tiếp tục duyệt các bài viết liên quan blog tương lai!
Kiến trúc máy ảo tuyệt vời-AQ
Wails phát triển khai bot Tencent Yuanqi
12 công cụ không mã nguồn mở hàng đầu theo số Sao GitHub
Xây dựng một Applet tâm lý dựa trên JavaSpringBoot và Uniapp: Hướng dẫn đầy đủ từ 0 đến 1
c# - task no clock
Đã nhận VS HttpResponseMessage Đã nhận
Tôi cần sự giúp đỡ của bạn với những điều sau đây. một tháng. và tất cả chúng đều hoạt động như mong đợi: public Htt
Không thể lấy URI từ URL, nhận giá trị rỗng?
Tôi có mẫu tệp (.xls) trong tệp thực thi của mình. (Sẽ được thêm vào sau).
javascript - Mô hình thu thập nguyên mẫu (nguyên mẫu) của Backbone so với thu thập xương sống
Tôi đang xem mô hình mã hóa của trang web và có câu hỏi về nguyên mẫu. đây...define([], function () { "sử dụng
javascript - Bắt ScrollTop, got offsetHeight và getStyle mất nhiều thời gian
Ba thao tác hàng đầu ảnh hưởng đến hiệu suất của tôi là: Nhận thanh cuộn Nhận chiều cao bù trừ Ext.getStyle Để giải thích tôi đang làm việc Hết mọi thứ nội dung của mạng, nó sẽ hoạt động
Nhận URL tham số chức năng, nhận giá trị của url phần hoặc trả về true nếu có nhưng không có giá trị?
URL. hàm gup(tên, url) { name = name.replace(/[\[]/, '\\\[').replace(/[\]]/ ,
c - MacOS sử dụng sysctl() để lấy HW_MACHINE_ARCH để nhận "không có tệp hoặc thư mục như vậy"
HW_MACHINE_ARCH. Tôi đang sử dụng HW_MACHINE, tôi cũng nghĩ vậy
Cung cấp (đưa) kênh YouTube của tôi vào ứng dụng iOS của tôi
đóng cửa. Câu hỏi này không tuân thủ các nguyên tắc của Stack Overflow. Hiện tại nó không chấp nhận câu trả lời. Đóng cửa 9 năm trước Các câu hỏi yêu cầu mã phải thể hiện sự hiểu biết tối thiểu về vấn đề đang được giải quyết. Bao gồm các giải pháp đã thử và tại sao
webpack: Cách lấy JavaScript từ "bower_comComponents" thay vì "node_modules"
Vì sử dụng main-bower-files như một phần của tác vụ biên dịch bằng Gulp, nên tôi không thể sử dụng webpack trong node_modules để yêu cầu module code> dir vì tôi sẽ làm rối mã
Javascript - Nhận "mon" từ "Thứ Hai" hoặc "thứ ba" từ "Thứ Ba", v.v.
đóng cửa. Câu hỏi này cần tập trung hơn. Hiện tại nó không chấp nhận câu trả lời. Bạn muốn cải thiện câu hỏi này? Đã cập nhật câu hỏi để tập trung vào một vấn đề chỉnh sửa bài đăng này Đã đóng 5 năm trước. Cải thiện câu hỏi này
Java: Không thể áp dụng Gridlayout cho Jscrollpane. Nhận java.lang.ClassCastException
Tôi đang sử dụng Gridlayout để đặt 4 phần tử liên tiếp. Đầu tiên, tôi có JPanel và mọi thứ đều hoạt động tốt. Đối với những trường hợp số lượng hàng ngày càng lớn và tôi phải cuộn xuống, tôi đã thực hiện một số thay đổi đối với nó. Bây giờ tôi đã thêm J vào JPanel của mình
python — Cách lấy VolumeId từ khóa BlockDeviceMappings (boto3 lấy thông tin về âm lượng ec2)
Tôi muốn lưu giá trị của VolumeId vào một biến vì những lý do sau: #!/usr/bin/env python import boto3 import json import argparse import
Angularjs - Không sử dụng AcacquiTokensilent để nhận mã thông báo mà sử dụng trình duyệt Msal AcacquiTokenpopup để nhận mã thông báo
Tôi đang cập nhật MSAL phiên bản 1.x lên trình duyệt MSAL cho Angular. Vì vậy, tôi đang cố gắng di chuyển từ phiên bản 1.x sang 2.XI và đã có thể thay thế mã thành công và nó hoạt động tốt. Nhưng tôi đã gặp có đượcT
python - Lấy mức trung bình của Pandas bằng GroupBy - Lấy DataError: Không có loại số nào để tổng hợp -
Tôi biết có rất nhiều câu hỏi về vấn đề này như Lấy số trung bình hàng ngày với gấu trúc và Làm thế nào để lấy giá trị trung bình hàng tháng của gấu trúc bằng cách sử dụng nhóm nhưng tôi đã gặp phải
Không thể lấy DATETIME từ QueryString trong phương thức mvc getController (từ Uri())
Đây là chuỗi truy vấn mà tôi nhận được trong URL đầu ra: /demo/analysis/test?startDate=Sat+
ubuntu - Tải Geoserver từ OpenLayer 3 nhận '500 (Lỗi máy chủ nội bộ)'
Tôi đang cố gắng truy cập lớp Geoserver var gkvrtWmsSource =new ol.source.ImageWMS({ u
javascript - Nhận thông tin API Ecobee bằng XMLHttpRequest. Nhận 500 (Lỗi 1: "Xác thực không thành công. Cần có mã thông báo.")
API yêu cầu tiêu đề chứa mã ủy quyền. Đây là những gì tôi có cho đến nay: var fullUrl = 'https://api.ecobee.com/1/thermostat?json=\{"s
c# - Nhận/xóa ký tự cuối cùng của tệp mà không tải vào bộ nhớ
Làm cách nào tôi có thể lấy ký tự cuối cùng trong một tệp và nếu đó là một ký tự nhất định, hãy xóa nó mà không tải toàn bộ tệp vào bộ nhớ? Đây là những gì tôi có hiện tại. sử dụng (var fileStream = new FileStream("file.t
JSP lấy/đặt tham số của toàn bộ đối tượng
Tôi mới tham gia cộng đồng này và nghĩ ra câu hỏi đầu tiên của mình. Tôi đang làm việc với JSP và tôi đã tạo thành công các Trang web JSP đang sử dụng jsp:setParameter và jsp:getParameter bằng một chuỗi duy nhất.
đa luồng - thu thập/giải phóng ngữ nghĩa
Để trả lời cho việc sắp xếp lại StoreStore xảy ra khi biên dịch C++ cho x86 @Peter Cordes đã viết For Acquire/Release se
javascript - Nhận kết quả của các hàm được sử dụng trong .on
Tôi có một hàm, hãy gọi nó là X1, hàm này trả về biến Y. Hàm này được sử dụng trong hành động .on("focusout", X1). Làm thế nào để có được biến Y? Kết quả của X1 sau khi thực thi .on là gì? Câu trả lời hay nhất Bạn có thể thay đổi phạm vi của Y để nó nằm trong hàm
rên rỉ thực hiện Tencent Yuanqi bot-6ren
Wails triển khai bot Tencent Yuanqi - một mô-đun của công cụ ghi âm đơn giản. Lệnh gọi API phụ trợ được đăng nhập vào Tencent Yuanqi để tạo đại lý. Bạn có thể tạo nó theo nhu cầu của riêng mình và chờ xem xét sau khi xuất bản. Sau khi phát hành xong, hãy nhấp để gọi api. Tại đây bạn có thể thấy user_id,-6ren.
Thời gian cập nhật: 2024-07-20 11:02:42
Một mô-đun cho các công cụ ghi nhật ký đơn giản.
phía sau
Lệnh gọi API
Sau khi đăng nhập vào Tencent Yuanqi, hãy tạo một đại lý và tạo nó theo nhu cầu của riêng bạn. Sau khi xuất bản, bạn phải chờ xem xét.
Sau khi phát hành xong, hãy nhấp để gọi api. Tại đây, bạn có thể xem các thông số user_id, Assistant_id và mã thông báo.
Sử dụng thư viện được đóng gói github.com/chenmingyong0423/go-yuanqi để gọi API. Theo cách sử dụng bản demo (ở đây, tương tác API không phát trực tuyến được sử dụng làm ví dụ), bạn nên chú ý đến một thay đổi ban đầu. chat.Chat() Đối với chat.Session() (bản demo của tác giả chưa kịp cập nhật), cụ thể như sau:
gói nhập chính ( "context" "fmt" "github.com/chenmingyong0423/go-yuanqi" "log" "time" ) /** * @Author Lockly * @Description * @Date 2024/7/1 **/ func main() { trò chuyện := yuanqi.NewChat("assistant_id", "user_id", "token", yuanqi.WithAssistantVersion(""), yuanqi.WithTimeOut(10*time.Second)) // Điền các thông số trên theo thứ tự := chat.Session().WithStream(false).WithChatType("published") textContent := yuanqi.NewContentBuilder().Text("hi").Build() // Tin nhắn hình ảnh yêu cầu phải bật plug-in nên tin nhắn không được sử dụng := yuanqi.NewMessageBuilder(). Vai trò("người dùng"). Nội dung(textContent).Build() resp, err := session.AddMessages(message).Request(context.Background()) if err != nil { log.Fatal (err) } // Nếu bạn chỉ muốn nhận câu trả lời của ai fmt.Println(resp.Choices[0].Message.Content) }
Chỉ cần gói gọn nó, chuyển câu hỏi để nhận câu trả lời và ba tham số trên được lấy từ cấu hình. Nói một cách đơn giản, hãy xác định phương thức trong wails' app.go (giống như các phương thức đã đăng ký khác). Sau khi bắt đầu dòng lệnh wails dev, wailsjs sẽ tự động được thêm vào để gọi giao diện người dùng.
Chỉ cần xác định ngắn gọn:
func (a *App) ChatWithAI(chuỗi nội dung, config *share.Config) chuỗi { resp, err := service.Chat(content, a.config) if err != nil { log.Logger.Error("ERR Nhận AI Trả lời không thành công") return err.Error() } return resp }
giao diện người dùng
giao diện
Để gọi giao diện người dùng, hãy nhập {ChatWithAI} từ "../../../wailsjs/go/cli/App"; sau đó hiển thị thành phần giao diện người dùng đơn giản. Để định cấu hình, bạn có thể thêm một trang (Khung phương thức). và ngăn kéo có thể được sửa đổi) và những thứ cần thiết khác có thể được thêm vào nếu cần.
Cấu hình
Lưu
Xóa
❗Hiện chỉ hỗ trợ Tencent Yuanqi
Màn hình trò chuyện sử dụng thành phần n-log, được sử dụng để hiển thị nhật ký và đẩy các câu hỏi cũng như câu trả lời. Điều quan trọng là hỗ trợ đánh dấu.
Xác định const msg ở đây: string[] = []; const chatData = ref(showMsg('', false)). Hàm showMsg chỉ cần đẩy nội dung vào msg rồi thêm \n dòng mới để hiển thị thông báo. Xử lý các điểm nổi bật.
Điểm nổi bật
Không có highlight.js tích hợp trong ui ngây thơ, vì vậy trước khi sử dụng nó, bạn cần giới thiệu import hljs from 'highlight.js/lib/core' và đặt trước:
Có một số ngôn ngữ được tích hợp trong hljs, nhưng nó không hoạt động khi tôi thử. Ví dụ: đăng ký markdown và sau đó sử dụng markdown trong n-log. Khi mã được ai trả lời sử dụng cú pháp markdown ```` để tải. mã, nó sẽ không được đánh dấu, điều tương tự không hoạt động với ngôn ngữ tương ứng.
nhập markdown từ 'highlight.js/lib/linguage/markdown' hljs.registerLanguage('markdown ', markdown )
Tuy nhiên, các ví dụ được cung cấp trên trang web chính thức là các ngôn ngữ được tùy chỉnh để thực hiện các chức năng tương ứng, chẳng hạn như làm nổi bật tất cả các số:
nhập hljs từ 'highlight.js/lib/core' hljs.registerLanguage('naive-log', () => ({ contains: [ { className: 'number',begin: /\d+/ } ] }))
Tương tự, bạn có thể sử dụng tính năng khớp thông thường để khớp các ký tự để đặt các danh mục nhằm điều chỉnh kiểu, chẳng hạn như tiếng Trung và tiếng Anh cũng như các ký hiệu tôi muốn đánh dấu các đoạn hội thoại ở đây»:
hljs.registerLanguage('naive-log', () => ({ contains: [ { className: 'number',begin: /\d+/ }, { className: 'chinese',begin: /[一-饥]/ , // Phạm vi ký tự tiếng Trung (Phạm vi mã hóa Unicode) mức độ liên quan: 10 }, { className: 'english', Begin: /[A-Za-z]/, mức độ liên quan: 0 }, { className: 'bot',begin: /[\w\s]+»\s*/, // Khớp bất kỳ từ nào, dấu cách cho đến » theo sau là mức độ liên quan của dấu cách: 1, }, ] }))
ClassName ở đây có thể được xác định một cách ngẫu nhiên, miễn là nó dễ phân biệt và sau đó xác định nó trong style.css trong wails: (Những cái mới khác có thể được thêm vào bên dưới).
.n-code, .n-layout-content, .n-layout-header, .n-layout, .terminal .t-window { font-family: "Giao diện người dùng Microsoft YaHei", system-ui } .n-code; .hljs-attr, .n-code .hljs-biến, .n-code .hljs-template-biến, .n-code .hljs-type, .n-code .hljs-selector-class, .n-code .hljs-selector-attr, .n-code .hljs-selector-pseudo, .n-code .hljs-number { color: # 078585; họ phông chữ: "Giao diện người dùng Microsoft YaHei", system-ui } .n-code; .hljs-log-info {color: #25c9ab;} .n-code .hljs-log-debug {color: #13778a;} .n-code .hljs-log-error {color: #931023;} .n- mã .hljs-log-warn {color: #0d705e;} .n-code .hljs-chinese {color: rgba(19, 19, 19, 0.89);} .n-code .hljs-english {color: rgba(31, 32, 33, 0.89);} .n-code .hljs-bot {color: #11c5a4;}
Cuối cùng, thêm một hộp đầu vào và hai nút. Hộp đầu vào đặt thuộc tính @keydown.enter="send" và nhấn Enter để kích hoạt phương thức gửi. Phương thức này được sử dụng để gọi ChatWithAI trước đó. có thể được hiển thị trong hộp nhập và nhật ký. Cả hai đều đặt thuộc tính :loading để chờ tải và hộp nhập phải bị tắt trong thời gian chờ.
Hiệu ứng cuối cùng như sau (mã hoàn chỉnh sẽ được mở nguồn sau):
Cuối cùng, bài viết về việc triển khai bot Tencent Yuanqi của Wails kết thúc tại đây. Nếu bạn muốn biết thêm về việc triển khai bot Tencent Yuanqi của Wails, vui lòng tìm kiếm bài viết CFSDN hoặc tiếp tục duyệt các bài viết liên quan. blog tương lai! .
[rCore Study Notes 016] Triển khai ứng dụng
vue.js - go get wails không được cài đặt đúng cách
Đã thử sử dụng...golang và wails...nhưng sau này...hãy truy cập github.com/wailsapp/wails/cmd/wails Tôi hiểu rồi. ../../github.com/w
go - Nguyên nhân gây ra lỗi "no such file: mshtmhst.h" khi sử dụng Wails trên Windows?
Tôi đang cố gắng sử dụng Wails trên máy Windows nhưng tôi nhận được: Trong tệp được bao gồm từ C:\Go\external\pkg\mod\github.com\wailsapp\wa
Kiến trúc bộ nhớ máy ảo tuyệt vời-AQ-6ren
Kiến trúc bộ nhớ máy ảo tuyệt vời-AQ-Liên kết nguồn: https://www.axa6.com/zh/an-excellent-virtual-machine-memory-architecture Giới thiệu Kiến trúc bộ nhớ máy ảo ảnh hưởng trực tiếp đến hiệu suất của máy ảo và- 6 nhân
Thời gian cập nhật: 2024-07-20 12:58:41
Liên kết nguồn: https://www.axa6.com/zh/an-excellent-virtual-machine-memory-architecture.
Kiến trúc bộ nhớ máy ảo ảnh hưởng trực tiếp đến hiệu suất và khả năng chiếm dụng của máy ảo. Thiết kế một kiến trúc xuất sắc có thể cải thiện hiệu suất và hiệu quả một cách hiệu quả. Bài viết này sẽ giới thiệu kiến trúc bộ nhớ được sử dụng bởi máy ảo AQ và các tiêu chuẩn chi tiết về bộ nhớ máy ảo AQ. Bằng cách tối ưu hóa kiến trúc bộ nhớ máy ảo, nó giúp máy ảo chạy hiệu quả hơn và giảm chiếm dụng. Nếu có thể, bạn nên cân bằng cả hai càng nhiều càng tốt để máy ảo của bạn đạt được hiệu suất tốt nhất.
Trong một số trường hợp, việc phát triển phải được thực hiện khác nhau tùy theo nhu cầu đặc biệt của máy ảo. Ví dụ: Trong trường hợp bộ nhớ hạn chế như vi điều khiển, cần giảm chiếm dụng càng nhiều càng tốt. Trong các tình huống nhạy cảm về hiệu suất như tính toán song song, bạn cần tập trung vào việc tối ưu hóa hiệu suất.
ý tưởng thiết kế
kiến trúc bộ nhớ
Kiến trúc bộ nhớ cơ bản
AQ áp dụng kiến trúc bộ nhớ cơ bản của các thanh ghi, nhưng nó khác với kiến trúc thanh ghi tiêu chuẩn và đã thực hiện một số cải tiến và tối ưu hóa đối với kiến trúc thanh ghi.
Các thanh ghi ở đây không phải là các thanh ghi trong CPU mà là các thanh ghi ảo được mô phỏng trong bộ nhớ.
Lý do chọn đăng ký
So với các máy ảo ngôn ngữ chính thống như JAVA và Python, sử dụng kiến trúc ngăn xếp, lý do AQ quyết định áp dụng kiến trúc đăng ký là để tối ưu hóa hiệu suất và làm cho mã byte dễ hiểu hơn. Mặc dù kiến trúc ngăn xếp thường được coi là dễ chuyển và ghi hơn, nhưng sẽ có một số tổn thất về hiệu suất thực tế và việc truy cập nhiều lần vào bộ nhớ sẽ làm chậm nó, điều này là không thể tránh khỏi và khó tối ưu hóa hoàn toàn. Do đó, để giải quyết tình trạng giảm hiệu suất ở đây, AQ áp dụng kiến trúc đăng ký. Đồng thời, từ góc độ mã byte, mã byte của kiến trúc thanh ghi dễ hiểu hơn và các hướng dẫn của nó tương tự như phương thức tham số của hàm, thay vì trực tiếp đối mặt với nhiều thao tác của ngăn xếp.
đăng ký
Sự khác biệt về kiến trúc
Kiến trúc thanh ghi tiêu chuẩn
Trong kiến trúc thanh ghi tiêu chuẩn, các thanh ghi bao gồm:
kiểu dữ liệu
- Kiểu dữ liệu mà thanh ghi sẽ lưu trữ (chẳng hạn như int, float, double, v.v.)
dữ liệu
- Giá trị của dữ liệu mà thanh ghi sẽ lưu trữ
(tùy chọn) thẻ - Thẻ cho dữ liệu mà thanh ghi sẽ lưu trữ (ví dụ: biến, hàm, lớp, v.v.)
(tùy chọn) tham chiếu - tham chiếu đến dữ liệu mà thanh ghi sẽ lưu trữ (chẳng hạn như địa chỉ của một đối tượng, v.v.)
Mặc dù kiến trúc bộ nhớ của máy ảo ở các ngôn ngữ khác nhau có thể khác nhau nhưng thông tin này thường được lưu trữ.
Kiến trúc này đã được sử dụng trong quá trình phát triển AQ, nhưng sau khi thử nghiệm, nó chiếm một lượng lớn bộ nhớ.
Sau đây là mã register.h được AQ sử dụng:
// Bản quyền của tác giả AQ 2024, Mọi quyền được bảo lưu. // Chương trình này được cấp phép theo Giấy phép AQ. Bạn có thể tìm thấy giấy phép AQ trong // thư mục gốc. { // VIỆC CẦN LÀM(Đăng ký): Đang chờ sự cải thiện của sổ đăng ký. sự đoàn kết AqvmMemoryRegister_Value { // TODO(Register): Đang chờ cải thiện thanh ghi. const int int_value; const int const_int_value; const float const_float_value; const double long_value; const_character_value; boolean_value; const bool const_boolean_value }; struct AqvmMemoryRegister_Register { enum AqvmMemoryRegister_ValueType; liên kết giá trị AqvmMemoryRegister_Value };
Như có thể thấy từ đoạn mã trên, ngay cả khi chỉ giữ lại nội dung cần thiết, vì kiểu enum AqvmMemoryRegister_ValueType chiếm 4 byte và kiểu kết hợp AqvmMemoryRegister_Value chiếm 8 byte, nên bản thân kiểu cấu trúc sẽ chiếm 12 byte bộ nhớ.
Đồng thời, do tối ưu hóa trình biên dịch C, kiểu enum trong kiểu cấu trúc AqvmMemoryRegister_Register là bộ nhớ được căn chỉnh theo giá trị kiểu kết hợp, do đó 4 byte bộ nhớ đệm được thêm vào. Đặt AqvmMemoryRegister_Register thuộc loại cấu trúc chiếm 16 byte.
Nếu bạn sử dụng loại không phải 8 byte như int, 4 byte bộ nhớ đệm sẽ bị lãng phí, dẫn đến mất bộ nhớ. Vì vậy sẽ có 4-8 byte bộ nhớ bị lãng phí trong tất cả các thanh ghi.
AQ
Cấu trúc thanh ghi của
Để giải quyết vấn đề chiếm chỗ của kiến trúc thanh ghi truyền thống, AQ kết hợp các đặc điểm bảng biến cục bộ của khung ngăn xếp JVM và tối ưu hóa kiến trúc bộ nhớ, giảm đáng kể vấn đề chiếm chỗ.
Sau đây là ba lựa chọn thay thế:
// kế hoạch 1: struct AqvmMemoryRegister_Register{ uint8_t type; void* value_ptr; }; void* value; AqvmMemoryRegister_Register array[]; // kế hoạch 2: giá trị void*; 0 cho chỉ số 1 là // float, v.v. size_t type[] // plan 3: struct AqvmMemoryRegister_Register { giá trị uint32_t*; kích thước size_t };
Do con trỏ chiếm 4-8 byte nên bản thân dữ liệu cũng chiếm 1-8 byte, cộng với byte loại 1 nên phương án 1 chiếm 6-17 byte và có thể có sự căn chỉnh bộ nhớ nên phương án 1 cũng sẽ gây ra sự mất bộ nhớ rất lớn. . Trên thực tế, khi cần lưu giữ thông tin loại bộ nhớ, gói 2 có mức sử dụng bộ nhớ cao nhất, nhưng gói 2 không thể duy trì sự gắn kết của các loại dữ liệu khác nhau trong cùng một cấu trúc dữ liệu (chẳng hạn như cấu trúc), điều này có thể làm mất hiệu lực một số con trỏ. hoạt động. Do đó, kế hoạch 2 không được sử dụng để đảm bảo an toàn cho bộ nhớ. Trong một số trường hợp (tập lệnh máy ảo bao gồm các loại), phương án 3 cũng có thể đáp ứng nhu cầu lưu trữ bộ nhớ, nhưng do nhu cầu tập lệnh rút gọn nên thông tin loại không có trong hướng dẫn nên không thể đáp ứng được nhu cầu. hoạt động của máy ảo.
Do đó, chúng tôi áp dụng thiết kế sau để đảm bảo sử dụng bộ nhớ và cải thiện đáng kể vấn đề sử dụng bộ nhớ.
Bộ nhớ của AQ trực tiếp sử dụng con trỏ void* để lưu trữ dữ liệu, bộ lưu trữ size_t chiếm kích thước bộ nhớ và sử dụng kiểu lưu trữ mảng uint8_t. Vì uint8_t chiếm 8 bit nên để giảm dung lượng chiếm chỗ, 4 bit được sử dụng cho mỗi byte để lưu trữ loại. Do đó, một biến uint8_t có thể lưu trữ 2 loại. 4 bit đầu tiên của mỗi biến uint8_t được sử dụng cho loại byte chẵn và 4 bit cuối cùng được sử dụng cho loại byte lẻ.
// Cấu trúc lưu trữ thông tin về bộ nhớ. // |type| là một con trỏ tới một mảng lưu trữ kiểu của mỗi byte trong bộ nhớ //. Mỗi byte sử dụng 4 bit để lưu trữ kiểu này. / lưu trữ 2 loại. 4 bit đầu tiên của biến uint8_t được sử dụng cho loại byte chẵn và 4 bit tiếp theo được sử dụng cho loại byte lẻ. |data| là một con trỏ kiểu void* tới bộ nhớ lưu trữ dữ liệu // |size| là kích thước của bộ nhớ. // LƯU Ý: Cấu trúc AqvmMemory_Memory chỉ lưu trữ thông tin của bộ nhớ. bởi hàm bytecode khi lưu trữ bytecode. // Bộ nhớ của |memory| và |type| là một phần của dữ liệu bytecode struct AqvmMemory_Memory { uint8_t* void*; kích thước size_t;
Vì lý do bộ nhớ, việc truy cập kiểu yêu cầu sử dụng chính xác. Loại uint8_t yêu cầu 8 bit, nhưng nó vượt quá nhu cầu lưu trữ của loại, vì vậy 4 bit không chỉ có thể đáp ứng nhu cầu lưu trữ của loại mà còn giảm mức sử dụng bộ nhớ. Nhưng cần có các chức năng đặc biệt để duy trì quyền truy cập kiểu.
// Đặt loại dữ liệu tại |index| byte trong |memory| thành |type|. // phải nhỏ hơn 4 bit. Trả về 0 nếu thành công. . Trả về -2 // nếu con trỏ kiểu là NULL. Trả về -3 nếu chỉ mục nằm ngoài phạm vi. Trả về // -4 nếu kiểu nằm ngoài phạm vi. Bộ nhớ AqvmMemory_Memory*, chỉ mục size_t, loại uint8_t) { if (bộ nhớ == NULL) { AqvmRuntimewindow_OutputReport("\"ERROR\"", "\"AqvmMemory_SetType_NullMemoryPointer\"", "\"Con trỏ bộ nhớ là NULL.\"", NULL); trả về -1; } nếu (bộ nhớ->loại == NULL) { AqvmRuntimewindow_OutputReport("\"ERROR\"", "\"AqvmMemory_SetType_NullTypePointer\"", "\"Con trỏ loại là NULL.\"", NULL return -2 }; (chỉ mục > bộ nhớ-> kích thước) { AqvmRuntimewindow_OutputReport( "\"ERROR\"", "\"AqvmMemory_SetType_OutOfMemoryRange\"", "\"Chỉ mục nằm ngoài phạm vi bộ nhớ.\"", NULL); return -3; } if (type > 0x0F) { AqvmRuntimewindow_OutputReport("\ "LỖI\"", "\"AqvmMemory_SetType_OutOfTypeRange\"", "\"Loại nằm ngoài phạm vi.\"", NULL); return -4; } // Đặt loại dữ liệu tại |index| byte trong bộ nhớ. // Vì Aqvm lưu trữ dữ liệu loại chiếm 4 bit và uint8_t. chiếm 8 bit, // mỗi vị trí loại uint8_t lưu trữ hai loại dữ liệu. // (4 bit cao, 4 bit thấp) được đặt theo tính chẵn lẻ của |index|. các bit cao của (|index| / 2) và số lẻ được // lưu trữ trong các bit thấp của (|index| / 2). = (bộ nhớ->loại [chỉ mục / 2] & 0xF0) | loại; } else { bộ nhớ->loại [chỉ mục / 2] = (bộ nhớ->loại [chỉ mục / 2] & 0x0F) | (type << 4); } return 0; } // Lấy loại dữ liệu tại |index| byte trong |memory|. // Trả về loại nhỏ hơn 4 bit (0X0F) nếu thành công. / nếu con trỏ bộ nhớ là NULL. Trả về 0x12 nếu con trỏ loại là NULL // Trả về 0x13 nếu chỉ mục nằm ngoài phạm vi bộ nhớ uint8_t. AqvmMemory_GetType(struct AqvmMemory_Memory* bộ nhớ, chỉ mục size_t) { if (bộ nhớ == NULL) { AqvmRuntimewindow_OutputReport("\"ERROR\"", "\"AqvmMemory_GetType_NullMemoryPointer\"", "\"Con trỏ bộ nhớ là NULL.\"", NULL); trả về 0x11 } nếu (bộ nhớ->loại == NULL) { AqvmRuntimewindow_OutputReport("\"ERROR\"", "\"AqvmMemory_GetType_NullTypePointer\"", "\"Con trỏ loại là NULL.\"", NULL trả về 0x12; chỉ mục > bộ nhớ-> kích thước) { AqvmRuntimewindow_OutputReport( "\"ERROR\"", "\"AqvmMemory_GetType_OutOfMemoryRange\"", "\"Chỉ mục nằm ngoài phạm vi bộ nhớ.\"",NULL); return 0x13; } // Lấy loại dữ liệu tại |index| byte trong bộ nhớ // Vì Aqvm lưu trữ loại dữ liệu chiếm 4 bit và uint8_t chiếm 8 bit, // mỗi vị trí loại uint8_t lưu trữ hai loại dữ liệu. Các vị trí lưu trữ // (4 bit cao, 4 bit thấp) được đặt theo tính chẵn lẻ của |index|. 2) và các số lẻ được // lưu trữ ở các bit thấp của (|index| / 2). if (index % 2 != 0) { return Memory->type[index / 2] & 0x0F; bộ nhớ->loại [chỉ mục / 2] & 0xF0) >> 4;
Tuy nhiên, sử dụng thiết kế này có yêu cầu cao hơn về việc lưu trữ dữ liệu, do độ dài của dữ liệu không cố định nên cần có các chức năng đặc biệt để hoạt động với bộ nhớ.
// Ghi dữ liệu |data_ptr| trỏ đến có kích thước |size| vào dữ liệu tại // |index| byte trong |memory|. // Trả về 0 nếu thành công. -2 // nếu con trỏ kiểu là NULL. Trả về -3 nếu chỉ mục nằm ngoài phạm vi. Trả về // -4 nếu con trỏ dữ liệu là NULL. Bộ nhớ AqvmMemory_Memory*, chỉ mục size_t, void* data_ptr, size_t size) { if (memory == NULL) { AqvmRuntimewindow_OutputReport( "\"ERROR\"", "\"AqvmMemory_WriteData_NullMemoryPointer\"", "\"Con trỏ bộ nhớ là NULL. \"", NULL); trả về -1 } nếu (bộ nhớ->loại == NULL) { AqvmRuntimewindow_OutputReport("\"ERROR\"", "\"AqvmMemory_WriteData_NullTypePointer\"", "\"Con trỏ loại là NULL.\"", NULL trả về -2 }; (chỉ mục > bộ nhớ-> kích thước) { AqvmRuntimewindow_OutputReport( "\"ERROR\"", "\"AqvmMemory_WriteData_OutOfMemoryRange\"", "\"Chỉ mục nằm ngoài phạm vi bộ nhớ.\"", NULL); return -3; } if (data_ptr == NULL) { AqvmRuntimewindow_OutputReport(" \"LỖI\"", "\"AqvmMemory_WriteData_NullDataPointer\"", "\"Con trỏ dữ liệu là NULL.\"", NULL); return -4; } // Vì void* không có kích thước cụ thể nên việc di chuyển con trỏ cần phải được // chuyển đổi trước đó di chuyển. memcpy((void*)((uintptr_t)memory->data + index), data_ptr, size return 0;
Ngoài việc giảm mức sử dụng bộ nhớ, điều quan trọng không kém là tránh chiếm dụng bộ nhớ thứ cấp. Do đó, chúng tôi sử dụng lại bộ nhớ của bytecode, lưu trữ dữ liệu bộ nhớ và các loại trong phần bộ nhớ của bytecode và sử dụng bộ nhớ được cấp phát trước trong tệp bytecode (tệp bytecode chứa dữ liệu và loại của bộ nhớ) để triển khai Để sử dụng bộ nhớ hiệu quả. Bởi vì nếu bạn lưu trữ hai phần riêng biệt, bạn cần có hai phần dữ liệu và loại bộ nhớ lặp lại. Một phần nằm trong phần bộ nhớ và phần còn lại, phần mã byte, sẽ không được sử dụng. để giảm thiểu Loại bỏ lãng phí bộ nhớ do dữ liệu và loại bộ nhớ gây ra. Tuy nhiên, việc triển khai chức năng đặc biệt là cần thiết và cần lưu ý rằng việc phân bổ và giải phóng dữ liệu bộ nhớ cũng như các loại bộ nhớ được quản lý bởi các chức năng liên quan đến mã byte.
// Hàm sẽ phân tích cấu trúc AqvmMemory_Memory và sao chép |data|, // |type| và |size| tới cấu trúc nếu // thành công. Trả về NULL nếu việc tạo struct AqvmMemory_Memory* AqvmMemory_CreateMemory(void* data, type void*, size size_t) { struct AqvmMemory_Memory* Memory_ptr = (struct AqvmMemory_Memory*)malloc(sizeof(struct AqvmMemory_Memory)); if (memory_ptr == NULL) { AqvmRuntimewindow_OutputReport( "\"ERROR\"", "\"AqvmMemory_CreateMemory_MemoryAllocationFailure\"", "\"Không thể cung cấp bộ nhớ.\"", NULL); trả về NULL } bộ nhớ_ptr->data = bộ nhớ_ptr->type = bộ nhớ_ptr->size = kích size; } // Giải thích bộ nhớ của |memory_ptr|. // Ý: Hàm giải phóng cấu trúc bộ nhớ chỉ. được con trỏ tới // bởi các con trỏ tới dữ liệu và nhập vào cấu hình không được giải phóng. các hàm liên kết đến byte mã hóa.
Ngoài ra, hãy xác định loại trong một số hệ thống khác với AQ tiêu chuẩn để thiết kế các chức năng liên kết Nếu hệ thống khác với tiêu chuẩn thì phải thiết kế đặc biệt cho hệ thống this system.
// Trả về số lượng cảnh báo. int AqvmMemory_CheckMemoryConditions() { int Warning_count = 0; != 4) { AqvmRuntimewindow_OutputReport( "\"WARNING\"", " \"AqvmMemory_CheckMemoryConditions_IntLengthWarning\"", "\"Yêu cầu về độ dài cho kiểu int không thêm theo định nghĩa " "type " ", NULL); ++warning_count; } if (sizeof(aqlong) != 8) { AqvmRuntimewindow_OutputReport( "\" WARNING\"", "\"AqvmMemory_CheckMemoryConditions_LongLengthWarning\"", "\"Yêu cầu về độ dài cho loại dài không theo định nghĩa " ", NULL); ++warning_count; } if (sizeof(aqfloat) != 4) { AqvmRuntimewindow_OutputReport( "\"WARNING\"", "\" AqvmMemory_CheckMemoryConditions_FloatLengthWarning\"", "\"Yêu cầu về độ dài cho loại float không kèm theo " " định nghĩa loại.\"", NULL); ++warning_count } if (sizeof(aqdouble) != 4) { AqvmRuntimewindow_OutputReport( "\"CẢNH BÁO\"", "\"AqvmMemory_CheckMemoryConditions_DoubleLengthWarning\"", "\"Yêu cầu về độ dài cho loại kép không kèm theo định nghĩa loại " ".\"", NULL); ++warning_count; } if (sizeof(aqchar) != 1) { AqvmRuntimewindow_OutputReport( "\"WARNING\"", "\"AqvmMemory_CheckMemoryConditions_CharLengthWarning\"", "\"Yêu cầu về độ dài cho loại char không. thủ theo định nghĩa " "type " ".\", NULL); ++warning_count; } if (sizeof(aqbool) != 1) { AqvmRuntimewindow_OutputReport( "\"WARNING\"", "\"AqvmMemory_CheckMemoryConditions_BoolLengthWarning\"" , "Yêu cầu về độ dài cho loại bool không phù hợp với loại " " định nghĩa.", NULL); ++warning_count; } if (warning_count == 0) { AqvmRuntimewindow_OutputReport("\"INFO\"", "\"AqvmMemory_CheckMemoryConditions_CheckNormal\"", "\"Không có cảnh báo điều kiện bộ nhớ.\"", NULL } return Warning_count }
Chi tiết tiêu chuẩn:
Mã cho bộ nhớ nằm trong /aqvm/memory. Chứa nhiều mã hóa tập tin.
CMakeLists.txt
- File build CMake in this folder
bộ nhớ.h
- Bộ nhớ cấu trúc và các liên kết chức năng
bộ nhớ.c
- Thực hiện các chức năng liên quan đến bộ nhớ
loại.h
- Định nghĩa các loại bộ nhớ
AqvmMemory_Memory
|type| là một con trỏ tới một kiểu lưu trữ từng byte trong bộ nhớ. byte sử dụng 4 bit để lưu trữ loại. Do đó, một biến uint8_t có thể lưu trữ 2 loại. Danh sách các loại có trong type.h. |data| là một kẻ lừa đảo con trỏ void* tới bộ nhớ nơi lưu trữ dữ liệu |size| là kích thước của bộ nhớ. |bộ nhớ| và | bộ nhớ là một phần của bộ nhớ nhớ byte mã hóa.
struct AqvmMemory_Memory { uint8_t* data size void*;
AqvmMemory_CheckMemoryĐiều kiện
Kiểm tra bộ nhớ điều kiện trong hệ thống. Trả về cảnh báo số lượng.
int AqvmMemory_CheckMemoryConditions() { int Warning_count = 0; if (sizeof(aqint) != 4) { AqvmRuntimewindow_OutputReport( "\"WARNING\"", "\"AqvmMemory_CheckMemoryConditions_IntLengthWarning\"", "\"Yêu cầu độ dài cho kiểu int không phù hợp với " "loại" "định nghĩa.\"", NULL); ++warning_count; } if (sizeof(aqlong) != 8) { AqvmRuntimewindow_OutputReport( "\"WARNING\"" , "\"AqvmMemory_CheckMemoryConditions_LongLengthWarning\"", "\"Yêu cầu về độ dài đối với loại dài không cộng theo định nghĩa " " loại " ".\"", NULL); ++warning_count; } if (sizeof(aqfloat) != 4) { AqvmRuntimewindow_OutputReport( "\"WARNING\"", "\"AqvmMemory_CheckMemoryConditions_FloatLengthWarning\"", "\" thủ thuật tới " " định nghĩa kiểu.\"", NULL); } if (sizeof(aqdouble) != 4) { AqvmRuntimewindow_OutputReport( "\"WARNING\"", "\"AqvmMemory_CheckMemoryConditions_DoubleLengthWarning\"", "\"Yêu } if (sizeof(aqchar) != 1) { AqvmRuntimewindow_OutputReport( "\"CẢNH BÁO\"", "\"AqvmMemory_CheckMemoryConditions_CharLengthWarning\"", "\"Yêu cầu về độ dài cho loại char không cộng theo định nghĩa " "type " ".\"", NULL ); ++warning_count } if (sizeof(aqbool) != 1) { AqvmRuntimewindow_OutputReport( "\"WARNING\"", "\"AqvmMemory_CheckMemoryConditions_BoolLengthWarning\"", "Yêu cầu về độ dài cho loại bool không bổ sung theo loại " " định nghĩa.", NULL); = 0) { AqvmRuntimewindow_OutputReport("\"INFO\"", "\"AqvmMemory_CheckMemoryConditions_CheckNormal\"", "\"Không có cảnh báo điều kiện nhớ.\"", NULL } return Cảnh báo_count }
AqvmMemory_TạoBộ nhớ
Tạo cấu trúc AqvmMemory_Memory chứa |data|, |type| và |size|. Hàm này phân bổ cấu trúc AqvmMemory_Memory và sao chép |data|, |type| và |size| vào cấu trúc đó. Trả về một con trỏ tới cấu trúc này. Trả về NULL nếu việc tạo không thành công.
struct AqvmMemory_Memory* AqvmMemory_CreateMemory(void* data, void* type, size_t size) { struct AqvmMemory_Memory* Memory_ptr = (struct AqvmMemory_Memory*)malloc(sizeof(struct AqvmMemory_Memory)); if (memory_ptr == NULL) { AqvmRuntimewindow_OutputReport( "\"ERROR\"", "\"AqvmMemory_CreateMemory_MemoryAllocationFailure\"", "\"Không thể cấp phát bộ nhớ.\"", NULL trả về NULL } Memory_ptr->data = data; ; bộ nhớ_ptr->size = kích thước trả về bộ nhớ_ptr }
AqvmMemory_FreeMemory
Giải phóng bộ nhớ của |memory_ptr|. Không có giá trị trả lại. Lưu ý: Chức năng này chỉ giải phóng bộ nhớ của cấu trúc. Bộ nhớ được trỏ tới bởi con trỏ tới dữ liệu và kiểu trong cấu trúc sẽ không được giải phóng. Những bộ nhớ này được quản lý bởi các hàm liên quan đến mã byte.
void AqvmMemory_FreeMemory(struct AqvmMemory_Memory* Memory_ptr) { free(memory_ptr }
AqvmMemory_SetType
Đặt kiểu dữ liệu ở byte |index| trong |memory| thành |type|. |loại| phải ít hơn 4 chữ số. Trả về 0 khi thành công. Nếu con trỏ bộ nhớ là NULL, -1 được trả về. Nếu con trỏ chỉ mục là NULL, -2 được trả về. Nếu chỉ số nằm ngoài phạm vi, -3 sẽ được trả về. Nếu loại nằm ngoài phạm vi, -4 sẽ được trả về.
int AqvmMemory_SetType(const struct Bộ nhớ AqvmMemory_Memory*, size_t index, uint8_t type) { if (memory == NULL) { AqvmRuntimewindow_OutputReport("\"ERROR\"", "\"AqvmMemory_SetType_NullMemoryPointer\"", "\"Con trỏ bộ nhớ là NULL.\"", NULL); trả về -1; } if (bộ nhớ->loại == NULL) { AqvmRuntimewindow_OutputReport("\"ERROR\"", "\"AqvmMemory_SetType_NullTypePointer\"", "\"Con trỏ kiểu là NULL.\"", NULL); trả về -2 } if (chỉ mục> bộ nhớ-> kích thước) { AqvmRuntimewindow_OutputReport( "\"ERROR\"", "\"AqvmMemory_SetType_OutOfMemoryRange\"", "\"Chỉ mục nằm ngoài phạm vi bộ nhớ.\"", NULL return -3; "\"LỖI\"", "\"AqvmMemory_SetType_OutOfTypeRange\"", "\"Loại nằm ngoài phạm vi.\"", NULL); return -4; } // Đặt loại dữ liệu tại |index| lưu trữ dữ liệu loại chiếm 4 bit và uint8_t chiếm 8 bit, // mỗi vị trí loại uint8_t lưu trữ hai loại dữ liệu Vị trí lưu trữ // (4 bit cao, thấp. 4 bit) được thiết lập theo tính chẵn lẻ của |index|. // Số chẵn được lưu ở bit cao của (|index| / 2) và số lẻ được // được lưu ở bit thấp của (|index| / 2) ). if (index % 2 != 0) { bộ nhớ->type[index / 2] = (bộ nhớ->type[index / 2] & 0xF0) | loại; 2] = (bộ nhớ->loại [chỉ mục / 2] & 0x0F) | (loại << 4);
AqvmMemory_GetType
Lấy kiểu dữ liệu tại |index| byte trong |memory|. Loại nhỏ hơn 4 bit (0X0F) được trả về thành công. Nếu con trỏ bộ nhớ là NULL thì trả về 0x11. Nếu con trỏ chỉ mục là NULL thì trả về 0x12. Nếu chỉ số vượt quá phạm vi bộ nhớ, 0x13 sẽ được trả về.
uint8_t AqvmMemory_GetType(struct AqvmMemory_Memory* bộ nhớ, size_t chỉ mục) { if (bộ nhớ == NULL) { AqvmRuntimewindow_OutputReport("\"ERROR\"", "\"AqvmMemory_GetType_NullMemoryPointer\"", "\"Con trỏ bộ nhớ là NULL.\"" , KHÔNG); trả về 0x11; } if (bộ nhớ->loại == NULL) { AqvmRuntimewindow_OutputReport("\"ERROR\"", "\"AqvmMemory_GetType_NullTypePointer\"", "\"Con trỏ loại là NULL.\"", NULL trả về 0x12); ; } if (chỉ mục > bộ nhớ-> kích thước) { AqvmRuntimewindow_OutputReport( "\"ERROR\"", "\"AqvmMemory_GetType_OutOfMemoryRange\"", "\"Chỉ mục nằm ngoài phạm vi bộ nhớ.\"", NULL return 0x13; chỉ mục| byte trong bộ nhớ. // Vì Aqvm lưu trữ loại dữ liệu chiếm 4 bit và uint8_t chiếm 8 bit bit, // mỗi vị trí loại uint8_t lưu trữ hai loại dữ liệu. Các vị trí lưu trữ // (4 bit cao, 4 bit thấp) được đặt theo tính chẵn lẻ của |index|. |index| / 2) và các số lẻ được // lưu trữ ở các bit thấp của (|index| / 2). if (index % 2 != 0) { return Memory->type[index / 2] & 0x0F; } else { return (memory->type[index / 2] & 0xF0) >> 4;
AqvmMemory_WriteData
Ghi dữ liệu có kích thước |size| được trỏ bởi |data_ptr| vào dữ liệu tại |index|. Trả về 0 khi thành công. Nếu con trỏ bộ nhớ là NULL, -1 được trả về. Nếu con trỏ chỉ mục là NULL, -2 được trả về. Nếu chỉ số vượt quá phạm vi bộ nhớ, -3 sẽ được trả về. Nếu con trỏ dữ liệu là NULL, -4 được trả về.
int AqvmMemory_WriteData(struct AqvmMemory_Memory* bộ nhớ, size_t index, void* data_ptr, size_t size) { if (memory == NULL) { AqvmRuntimewindow_OutputReport( "\"ERROR\"", "\"AqvmMemory_WriteData_NullMemoryPointer\"", "\"Bộ nhớ con trỏ là NULL.\"", NULL); trả về -1; } if (bộ nhớ->loại == NULL) { AqvmRuntimewindow_OutputReport("\"ERROR\"", "\"AqvmMemory_WriteData_NullTypePointer\"", "\"Con trỏ kiểu là NULL.\"", NULL); trả về -2 } if (chỉ mục> bộ nhớ-> kích thước) { AqvmRuntimewindow_OutputReport( "\"ERROR\"", "\"AqvmMemory_WriteData_OutOfMemoryRange\"", "\"Chỉ mục nằm ngoài phạm vi bộ nhớ.\"", NULL return -3 } if (data_ptr == NULL) { AqvmRuntimewindow_OutputReport ("\"LỖI\"", "\"AqvmMemory_WriteData_NullDataPointer\"", "\"Con trỏ dữ liệu là NULL.\"", NULL); return -4; } // Vì void* không có kích thước cụ thể nên việc di chuyển con trỏ cần phải được // chuyển đổi trước đó di chuyển. memcpy((void*)((uintptr_t)memory->data + index), data_ptr, size return 0;
Mã hoàn chỉnh:
// Bản quyền của tác giả AQ 2024, Mọi quyền được bảo lưu. // Chương trình này được cấp phép theo Giấy phép AQ. Bạn có thể tìm thấy giấy phép AQ trong // thư mục gốc.
#include "aqvm/memory/types.h" // Cấu trúc lưu trữ thông tin về bộ nhớ // |type| bộ nhớ //. Vì vậy, một biến uint8_t có thể // lưu trữ 2 loại, 4 bit đầu tiên của biến uint8_t được sử dụng cho byte loại chẵn và 4 bit tiếp theo được sử dụng cho loại danh sách byte // có dạng.h. // |data| là một kiểu con trỏ void* tới bộ nhớ. lưu trữ dữ liệu. struct AqvmMemory_Memory chỉ lưu trữ thông tin của bộ nhớ // Bộ nhớ được bổ sung bởi hàm bytecode khi lưu trữ bytecode // Bộ nhớ của |memory| và |type| là một phần của dữ liệu bytecode bộ nhớ; void* size; system. // Trả về số lượng cảnh báo. , và |size|. // Hàm sẽ phân tích AqvmMemory_Memory Structure và sao chép |data|, // |type|, và |size| architecture. Trả về một con trỏ tới cấu trúc nếu // thành công. AqvmMemory_CreateMemory(void* data, void* type, size_t size); // Lưu Ý: Hàm giải phóng bộ nhớ chỉ của struct. do con trỏ tới dữ liệu và nhập vào struct không được giải phóng. // được quản lý bởi các hàm liên kết. đến byte mã hóa void AqvmMemory_FreeMemory(struct AqvmMemory_Memory* Memory_ptr); // Đặt loại dữ liệu tại |index| phải nhỏ hơn 4 bit. thành công. Trả về -1 nếu bộ nhớ con trỏ là NULL. phạm vi. int AqvmMemory_SetType(const struct AqvmMemory_Memory* bộ nhớ, size_t index, uint8_t type); // Lấy dữ liệu tại byte chỉ mục| // Trả về 0x12 nếu loại con trỏ là NULL. 0x13 if mục nằm ngoài phạm vi bộ nhớ // Ghi dữ liệu |data_ptr| tới kích thước |size| if thành công Trả về -1 nếu bộ nhớ con trỏ là NULL. phạm vi. Trả về // -4 if con trỏ dữ liệu là NULL.int AqvmMemory_WriteData(struct AqvmMemory_Memory* bộ nhớ, size_t chỉ mục, void* data_ptr, size size_t);
// Chương trình này được cấp phép theo AQ Giấy phép. Bạn có thể tìm thấy AQ giấy phép trong // thư mục gốc #include "aqvm/memory/memory.h" #include
#include "aqvm/memory/types.h" #include "aqvm/runtime/window/window.h" int AqvmMemory_CheckMemoryConditions() { int Warning_count = 0; if (sizeof(aqint) != 4) { AqvmRuntimewindow_OutputReport( "\" CẢNH BÁO\"", "\"AqvmMemory_CheckMemoryConditions_IntLengthWarning\"", "\"Yêu cầu về độ dài đối với kiểu int không kèm theo định nghĩa " "type ", NULL); (sizeof(aqlong) != 8) { AqvmRuntimewindow_OutputReport( "\"WARNING\"", " \"AqvmMemory_CheckMemoryConditions_LongLengthWarning\"", "\"Yêu cầu về độ dài cho loại dài không thêm vào " "type " " định nghĩa.\", NULL); ++warning_count; } if (sizeof(aqfloat) != 4) { AqvmRuntimewindow_OutputReport( "\"WARNING\"", "\"AqvmMemory_CheckMemoryConditions_FloatLengthWarning\"", " \"Yêu cầu độ dài cho kiểu float không phù hợp với kiểu " " định nghĩa.\", NULL); } if (sizeof(aqdouble) != 4) { AqvmRuntimewindow_OutputReport( "\"WARNING\"", "\"AqvmMemory_CheckMemoryConditions_DoubleLengthWarning\"", "\"Yêu cầu về độ dài cho loại kép không cộng theo định nghĩa loại " ".\"", NULL); (sizeof(aqchar) != 1) { AqvmRuntimewindow_OutputReport( "\"WARNING\"", "\"AqvmMemory_CheckMemoryConditions_CharLengthWarning\"", "\"Yêu cầu về độ dài cho loại char không có nhiều theo " "gõ " " định nghĩa.\"", NULL); ++warning_count; } if (sizeof(aqbool) != 1) { AqvmRuntimewindow_OutputReport( "\"WARNING\"", "\"AqvmMemory_CheckMemoryConditions_BoolLengthWarning\"", "Yêu cầu về độ dài cho loại bool không đóng theo định nghĩa loại " ".", NULL ); ++warning_count; } if (warning_count == 0) { AqvmRuntimewindow_OutputReport("\"INFO\"", "\"AqvmMemory_CheckMemoryConditions_CheckNormal\"", "\"Không có cảnh báo điều kiện bộ nhớ.\"", NULL); } return Warning_count } struct AqvmMemory_Memory* AqvmMemory_CreateMemory(void* data, void* type; , kích thước size_t) { struct AqvmMemory_Memory* Memory_ptr = (struct AqvmMemory_Memory*)malloc(sizeof(struct AqvmMemory_Memory)); if (memory_ptr == NULL) { AqvmRuntimewindow_OutputReport( "\"ERROR\"","\"AqvmMemory_CreateMemory_MemoryAllocationFailure\"", "\"Không thể cung cấp bộ nhớ phát hiện.\"", NULL); trả về NULL } bộ nhớ_ptr->data = dữ liệu bộ nhớ_ptr->type = bộ nhớ_ptr->size = kích thước; } void AqvmMemory_FreeMemory(struct AqvmMemory_Memory* Memory_ptr) { free(memory_ptr); } int AqvmMemory_SetType(const struct AqvmMemory_Memory* bộ bộ nhớ, size_t chỉ mục,loại uint8_t) { if (bộ nhớ == NULL) { AqvmRuntimewindow_OutputReport("\"ERROR\"", "\"AqvmMemory_SetType_NullMemoryPointer\"", "\"Con trỏ bộ nhớ là NULL.\"", NULL return - 1; } nếu (bộ nhớ->loại == NULL) { AqvmRuntimewindow_OutputReport("\"ERROR\"", "\"AqvmMemory_SetType_NullTypePointer\"", "\" Loại bỏ con trỏ là NULL.\"", NULL trả về -2; } nếu như (chỉ mục > bộ nhớ-> kích thước) { AqvmRuntimewindow_OutputReport( "\"ERROR\"", "\"AqvmMemory_SetType_OutOfMemoryRange\"", "\"Chỉ mục ngoài phạm vi bộ nhớ.\"", NULL); return -3; } if (type > 0x0F) { AqvmRuntimewindow_OutputReport("\"ERROR\"", "\"AqvmMemory_SetType_OutOfTypeRange\"", "\" Out of range.\" ", trả về NULL -4 } // index| byte trong bộ nhớ // Vì loại dữ liệu lưu trữ Aqvm sử dụng 4 bit và uint8_t sử dụng 8 bit, // mỗi vị trí loại uint8_t lưu trữ hai loại dữ liệu. Các vị trí lưu trữ // (cao 4 bit, thấp 4 bit) được đặt theo tính chất chẵn của |index|. và các số lẻ được // lưu trữ ở các bit thấp của (|index| / 2). if (index % 2 != 0) { Memory->type[index / 2] = (memory->type[index / 2] & 0xF0) | loại } else { bộ nhớ->type[index / 2] = (bộ nhớ->type[index / 2] & 0x0F) | (loại << 4); } trả về 0; bộ nhớ AqvmMemory_Memory*, size mục_t) { (bộ nhớ == NULL) { AqvmRuntimewindow_OutputReport("\"ERROR\"", "\"AqvmMemory_GetType_NullMemoryPointer\"", "\"Con trỏ bộ nhớ là NULL.\"", NULL trả về 0x11 } if (bộ nhớ->loại == NULL) { AqvmRuntimewindow_OutputReport ("\"LỖI\"", "\"AqvmMemory_GetType_NullTypePointer\"", "\"Con trỏ kiểu là NULL.\"", NULL); return 0x12; (chỉ mục > bộ nhớ->kích thước) { AqvmRuntimewindow_OutputReport( "\"ERROR\"", "\ "AqvmMemory_GetType_OutOfMemoryRange\"", "\"Chỉ mục đã hết phạm vi bộ nhớ.\"", NULL); return 0x13; } // Lấy loại dữ liệu tại |index| byte trong bộ nhớ // Vì Aqvm archive loại dữ liệu sử dụng 4 bit và uint8_t sử dụng 8 bit, // mỗi loại uint8_t. vị trí lưu trữ hai loại dữ liệu // (cao 4 bit, thấp 4 bit) được thiết lập theo tính năng lẻ của |index|. // lưu trữ ở bit thấp của (|index| /. 2) và số lẻ được // lưu trữ ở bit thấp của (|index| /. 2). (chỉ mục % 2 != 0) { return bộ nhớ->type[index / 2] & 0x0F; else { return (memory->type[index / 2] & 0xF0) >> 4; } } int AqvmMemory_WriteData(struct AqvmMemory_Memory * bộ nhớ, size_t chỉ mục, void* data_ptr, size_t size) { if (bộ nhớ == NULL) { AqvmRuntimewindow_OutputReport( "\"ERROR\"", "\"AqvmMemory_WriteData_NullMemoryPointer\""," \"Ký ức con trỏ là NULL.\"", NULL); trả về -1; } if (bộ nhớ->loại == NULL) { AqvmRuntimewindow_OutputReport("\"ERROR\"", "\"AqvmMemory_WriteData_NullTypePointer\ "", "\"Cuộn con trỏ là NULL.\", NULL); trả về -2 } if (chỉ mục > bộ nhớ-> kích thước) { AqvmRuntimewindow_OutputReport( "\"ERROR\"", "\"AqvmMemory_WriteData_OutOfMemoryRange\"", "\"Chỉ mục nằm ngoài phạm vi bộ nhớ.\"", NULL return -3 } if (data_ptr == NULL) { AqvmRuntimewindow_OutputReport ("\"LỖI\"", "\"AqvmMemory_WriteData_NullDataPointer\"", "\"Con trỏ dữ liệu là NULL.\"", NULL); return -4; } // Vì void* không có công cụ kích thước nên việc chuyển con trỏ memcpy((void*)((uintptr_t)memory->data + index), data_ptr, trả về kích thước 0;memcpy((void*)((uintptr_t)memory->data + index), data_ptr, size return 0 }memcpy((void*)((uintptr_t)memory->data + index), data_ptr, size return 0 }
Thông qua tác phẩm này, một Aqvm kiến ​​trúc đã được hoàn thành, giúp giảm bớt sức mạnh của bộ nhớ Aqvm.
Chúng tôi đang làm việc chăm chỉ hơn trên máy ảo AQ. trang web chính thức của chúng tôi: https://www.axa6.com và Github: https://github.com/aq-org/AQ.
Bài viết này được xuất bản dựa trên Giấy phép AQ: https://github.com/aq-org/AQ/blob/main/LICENSE. lại theo AQ Giấy phép.
Cuối cùng, bài viết về kiến ​​trúc máy xuất sắc máy ảo - AQ end tại đây. trúc bộ nhớ máy ảo xuất sắc - AQ, vui lòng tìm kiếm các bài viết CFSDN hoặc tiếp tục duyệt các bài viết liên quan, tôi hy mong bạn sẽ ủng hộ blog của tôi trong tương lai .
Hiệu ứng gradient viền văn bản CSS rất dễ dàng!
vmware - máy ảo
Tôi đang cố gắng tìm hiểu cách thức hoạt động của VMware (đặc biệt là khi cài đặt Linux) và tôi có hai câu hỏi: Điều gì xảy ra khi VMware gặp một lệnh như push cs?
máy ảo Gửi lệnh đến đầu thiết bị?
Tôi đang cố gắng định cấu hình vim làm chương trình mã hóa chính của mình. Nhưng khi tôi thực hiện chương trình này từ vim, tôi liên tục nhận được mã lỗi 127. Tôi có bí danh trên hộp của mình là ./a.out, Nhưng khi tôi bắt đầu từ vim
Javascript máy ảo
Tôi muốn biết liệu bạn có sử dụng máy ảo javascript hay có ý tưởng gì không! sử dụng trong trình duyệt như V8 của chrome, tôi muốn thực thi java trên máy chủ linux.
Cổng kết nối tiếp Ubuntu trên VirtualBOX (máy ảo)
đóng cửa câu hỏi này. cập nhật câu hỏi để nó phù hợp với chủ đề về Stack Overflow. Đóng cửa 10 năm trước.
Máy ảo Azure - đích đến của tài khoản lưu trữ
Tôi đang tìm cách sử dụng tài khoản lưu trữ trong Azure. tài khoản lưu trữ, hình như tôi cũng đã dùng rồi nhưng không biết tại sao, tôi nghĩ mình không cần thiết. tài khoản lưu trữ và dịch vụ đám mây. Tôi muốn tạo một cái khác
java - máy ảo: không thể mở
Error - JVM - Trình mô phỏng BlackBerry 9800 ----------------------------------------- - -- JVM: không thể mở được
Máy ảo/giả lập Javascript?
Thật khó để nói những gì để hỏi ở đây. không thể trả lời hợp lý ở dạng hiện tại. truy cập vào trung tâm trợ giúp.
linux - máy ảo - thiết lập centos làm bộ định tuyến
Đây là vấn đề của tôi. ảo...
Máy ảo Java không cần hệ điều hành?
Tôi biết BEA đang phát triển LiquidVM không yêu cầu hệ điều hành cơ bản nhưng tôi tự hỏi liệu có ai trong cộng đồng nguồn mở đang phát triển thứ gì đó tương tự hay không. Lý tưởng nhất là tôi muốn tìm một triển khai trong đó VM được tải trực tiếp bởi bộ tải khởi động hệ điều hành. Câu trả lời hay nhất là với
Hướng dẫn đồ họa chi tiết từng bước về cài đặt Vmware (máy ảo) trong hệ thống Linux
Hướng dẫn cài đặt Vmware trên hệ thống Linux. Do nhu cầu của dự án, việc ảo hóa Windows trên Linux là cần thiết. Sau khi tìm kiếm một số thông tin, tôi thấy rằng có thể đạt được điều đó với VMware. có thể được sử dụng, chẳng hạn như Win4lin và bochs.
sharepoint - Cách đổi tên máy ảo SharePoint
Tôi đang sử dụng máy ảo để phát triển nhưng mỗi khi cần một máy ảo mới, tôi lại sao chép các tệp và tạo một máy chủ mới nhưng tôi cần một tên máy chủ mới để thêm nó vào mạng của chúng tôi. Sau khi đổi tên server, trang Sharepoint có nhiều
Cách kết nối với máy ảo Cassandra
Nếu Cassandra và mã nằm trên cùng một máy, đoạn mã sau sẽ hoạt động: sử dụng System; sử dụng không gian tên CassandraInsertTest {
vmware - Làm cách nào để tắt máy ảo VMware mà không chết?
đóng cửa. Câu hỏi này không đáp ứng các nguyên tắc của Stack Overflow. Hiện tại nó không chấp nhận câu trả lời. Bạn muốn cải thiện vấn đề này? Câu hỏi được cập nhật để làm cho câu hỏi trở thành chủ đề cho Stack Overflow. Đóng cửa 7 năm trước Cải thiện điều này
CUDA/OpenCL trong máy ảo/trình ảo hóa
đóng cửa. Câu hỏi này không tuân thủ các nguyên tắc của Stack Overflow. Hiện tại nó không chấp nhận câu trả lời. Bạn muốn cải thiện câu hỏi này? Đã cập nhật câu hỏi theo chủ đề cho Stack Overflow. Đóng cửa 3 năm trước. Cải thiện câu hỏi này
azure - Lỗi ghi nhật ký vào máy ảo Azure?
Tôi đang chuyển ứng dụng web của mình, hãy thử bắt các thông báo theo dõi lỗi ngoại lệ vào thư mục C:\Temp trên máy chủ web. Nhưng khi ứng dụng web của tôi chạy trên Azure, tôi muốn chạy nó trên Azure VM c.
azure - Cách định cấu hình máy ảo Azure cho môi trường nhiều người dùng
Chúng tôi cung cấp phần mềm ERP dành cho máy tính để bàn cho khách hàng của mình. Phần mềm được cài đặt trong máy ảo Azure. Mỗi công ty có tập tin cơ sở dữ liệu riêng của mình. Tôi cần tối ưu hóa hiệu suất nhưng tôi có một số nghi ngờ và không thể tìm thấy câu trả lời. Ví dụ: đối với 2 công ty: 1-Mua 2 VM nhỏ (2
Azure - Không thể truy cập máy ảo Azure
Tôi đang cố gắng thay đổi địa chỉ số mạng của máy ảo trên Azure thành cùng mạng với một máy ảo khác trên nhóm Azure, khi tôi nhấp vào "lưu" trên card mạng thì nó bị kẹt và không hoạt động thông qua máy tính để bàn từ xa hoặc bất cứ cách nào khác. Xin hãy giúp đỡ. Câu trả lời hay nhất: Đừng thử
azure - Chia sẻ máy ảo Azure
Có thể thiết lập một máy ảo trên Azure và có cùng một phiên bản của máy ảo hiển thị cho nhiều người dùng không? Chúng tôi là một ISV. Người dùng của chúng tôi nằm rải rác trên toàn cầu. Chúng tôi muốn sử dụng máy ảo Azure để hướng dẫn người dùng thiết lập phần mềm của chúng tôi. Lý tưởng nhất là bàn trợ giúp của chúng tôi sẽ có mặt tại
azure - Không thể kết nối với máy ảo Azure
Tôi đã tạo một máy ảo bằng hình ảnh Ubuntu và tải sẵn Discourse từ kho lưu trữ Azure. Sau khi thiết lập tự động hoàn tất, tôi thấy máy ảo đang chạy nhưng không thể kết nối để xem máy từ xa. Tôi không thấy bất kỳ cài đặt nào giải quyết được vấn đề này cho tôi
[rCore Study Notes 016] Triển khai ứng dụng-6ren
[rCore Study Notes 016] Ứng dụng triển khai - Viết ở phía trước Bài luận này được viết bởi một người mới học rất giỏi. Nếu bạn có bất kỳ câu hỏi nào, xin vui lòng hỏi họ kịp thời. Bạn có thể liên hệ: 1160712160@qq.com GitHhub: https://github.com/WindDevil (Hiện tại không có gì -6ren
Thời gian cập nhật: 2024-07-20 13:00:42
viết ở phía trước
Bài luận này được viết bởi một người rất mới. Nếu bạn có bất kỳ câu hỏi nào, xin vui lòng hỏi họ kịp thời.
Bạn có thể liên hệ: 1160712160@qq.com.
GitHhub: https://github.com/WindDevil (Hiện tại không có gì.
phương pháp thiết kế
Trên thực tế, sau khi hiểu cơ chế cấp đặc quyền, nếu muốn thiết kế một ứng dụng, bạn cần đảm bảo rằng nó đáp ứng các yêu cầu của chế độ U và không truy cập các chức năng ở chế độ S. Sau đó, những điểm chính khi triển khai nó là.
Bố cục bộ nhớ ứng dụng
Cuộc gọi hệ thống do ứng dụng đưa ra
thiết kế cụ thể
Những tính năng cần bổ sung
Trong quá trình thực hiện cụ thể, việc thiết kế cũng phải được thực hiện theo các điểm chính được đưa ra trong phương pháp thiết kế.
Đặt vị trí nhập của thư viện người dùng
linker.ld
File, thiết lập người dùng khó khăn
rom
địa chỉ ở
Việc thực hiện có thể gọi
gọi lại
Các ứng dụng cần triển khai
Ứng dụng được biên dịch riêng để tạo tệp ELF và cắt nó thành tệp .bin. Để gọi nó, bạn chỉ cần liên kết nó với kernel trước rồi kernel sẽ tải nó vào bộ nhớ vào thời điểm thích hợp. để thực hiện nó trong phần giới thiệu của phần này
xin chào thế giới
 : In một dòng lên màn hình 
Xin chào thế giới từ chương trình chế độ người dùng!
cửa hàng_lỗi
 : Truy cập vào một địa chỉ vật lý bất hợp pháp để kiểm tra xem hệ thống xử lý hàng loạt có bị ảnh hưởng bởi lỗi này hay không.
quyền lực
 : Liên tục chuyển đổi cấp độ đặc quyền giữa các thao tác tính toán và thao tác in chuỗi
Tạo dự án
Đảm bảo rằng vị trí hiện tại là không gian làm việc.
cd -/không gian làm việc
Sử dụng hàng hóa để tạo dự án và tạo thư mục người dùng trong thư mục dự án để lưu trữ mã và giao diện chế độ người dùng.
hàng hóa mới ./user
Đã có user/src trong tệp dự án để lưu thư viện người dùng. Tiếp theo, tạo user/src/bin để lưu ứng dụng.
người dùng mkdir/src/bin
Thực hiện cấu hình bố trí bộ nhớ
Tạo tệp liên kết linker.ld trong user/src.
liên kết liên kết.ld
Vì địa chỉ mục nhập của lớp người dùng ứng dụng là 0x80400000 nên linker.ld được cung cấp trong Chương 1 cần được sửa đổi và BASE_ADDRESS được đặt thành 0x80400000.
OUTPUT_ARCH(riscv) ENTRY(_start) BASE_ADDRESS = 0x80400000; SECTIONS { . = BASE_ADDRESS; skernel = .; stext = .; (4K); etext = .; .rodata : { *(.rodata .rodata.*) *(.srodata .srodata.*) } = ALIGN(4K); erodata = .; sdata = .; ) *(.sdata .sdata.*) } = ALIGN(4K); edata = .bss : { *(.bss.stack) sbss = .; *(.bss .bss.*) *(.sbss .sbss.*) } . = ALIGN(4K); ebss = .; *(.eh_frame) } }
Bố cục bộ nhớ được thể hiện bằng tệp liên kết này như trong hình. Hãy chú ý đến vị trí của địa chỉ thấp và địa chỉ cao trong hình.
Phân đoạn dữ liệu được khởi tạo lưu trữ dữ liệu toàn cục được khởi tạo trong chương trình và được chia thành 
.rodata
 Và 
.data
 Hai phần. Cái trước lưu trữ dữ liệu toàn cầu chỉ đọc, thường là một số hằng số hoặc chuỗi không đổi, v.v. trong khi cái sau lưu trữ dữ liệu toàn cầu có thể sửa đổi.
Phân đoạn dữ liệu chưa được khởi tạo 
.bss
 Lưu dữ liệu chung chưa được khởi tạo trong chương trình, dữ liệu này thường được khởi tạo bằng 0 bởi trình tải của chương trình, nghĩa là xóa vùng này theo từng byte;
 Vùng (heap) được sử dụng để lưu trữ dữ liệu được phân bổ động khi chương trình đang chạy. Ví dụ: dữ liệu được phân bổ bởi malloc/new trong C/C++ được đặt trong vùng heap và nó sẽ tăng dần lên các địa chỉ cao hơn;
chồng
 Vùng (ngăn xếp) không chỉ được sử dụng để lưu và khôi phục ngữ cảnh lệnh gọi hàm mà các biến cục bộ trong phạm vi của từng hàm cũng được trình biên dịch đặt trong khung ngăn xếp của nó và nó phát triển về các địa chỉ thấp hơn.
Nhớ lại hướng dẫn mà chúng tôi đã sử dụng để flash tệp nhị phân vào QEMU, chúng tôi thực sự đã đặt kernel đã biên dịch ở 0x80200000, đây là phần .text.
qemu-system-riscv64 \ -machine virt \ -nographic \ -bios ../bootloader/rustsbi-qemu.bin \ -device Loader,file=target/riscv64gc-unknown-none-elf/release/os.bin,addr= 0x80200000
Đặt .text.entry trong đó _start nằm ở đầu toàn bộ chương trình. Nghĩa là, hệ thống hàng loạt đã nhập điểm vào của thư viện người dùng miễn là nó nhảy tới 0x80400000 sau khi tải và sẽ chuyển đến ứng dụng sau khi khởi tạo Logic chính...
Ở đây lưu ý rằng ENTRY(_start) là lối vào chương trình cài đặt. Nhìn lại nội dung của entry.asm trong Chương 1, .section .text.entry được đặt ở đây và Global_asm!(include_str!("entry. asm" )), trích dẫn mã này
# os/src/entry.asm .section .text.entry .globl _start _start: la sp, boot_stack_top gọi Rust_main .section .bss.stack .globl boot_stack_low_bound boot_stack_low_bound: .space 4096 * 16 .globl boot_stack_top boot_stack_top:
Cung cấp địa chỉ bắt đầu và kết thúc của phần .bss của tệp thực thi được tạo cuối cùng để hỗ trợ việc sử dụng hàm clear_bss.
Quan sát ~/App/rCore-Tutorial-v3/user/src/linker.ld
OUTPUT_ARCH(riscv) ENTRY(_start) BASE_ADDRESS = 0x80400000; SECTIONS { . = BASE_ADDRESS; .text : { *(.text.entry) *(.text .text.*) } .rodata : { *(.rodata .rodata. *) *(.srodata .srodata.*) } .data : { *(.data .data.*) *(.sdata .sdata.*) } .bss : { start_bss = .; *(.bss .bss.*) *(.sbss .sbss.*) end_bss = .; /DISCARD/ : { *(.eh_frame) *(.debug*) } }
Bạn có thể thấy rằng so với file link.ld mà chúng ta xây dựng theo file thì có ít mô tả về xxx(label) = .; và offset của = ALIGN(4K); hơn.
xxx(label) = .; được sử dụng để xác định ký hiệu xxx và đặt vị trí con trỏ hiện tại cho anh ta.
. = ALIGN(4K) được sử dụng để kiểm tra xem vị trí liên kết hiện tại có được căn chỉnh theo ranh giới 4K hay không. Nếu vị trí liên kết hiện tại không phải là bội số của ranh giới 4K, trình liên kết sẽ lấp đầy đủ byte cho đến ranh giới 4K tiếp theo.
Do đó, chúng ta có thể biết rằng trong linker.ld gốc, một số nhãn cần được đặt để chúng ta có thể lấy các con trỏ này thông qua extern C để biết kích thước của từng phần sau khi biên dịch. Và mỗi khi một phần được đặt, nó cần. được kiểm tra để phù hợp với ranh giới 4K ..
chi tiết (vui lòng đọc kỹ phần này, đặc biệt là BỎ QUA)
OUTPUT_ARCH(riscv)
: Xác định rằng kiến trúc đầu ra mục tiêu là RISC-V.
NHẬP(_bắt đầu)
: Chỉ định điểm vào của chương trình là
_bắt đầu
chức năng. Đây là nơi thực hiện chương trình bắt đầu.
BASE_ADDRESS = 0x80200000;
: Đặt địa chỉ cơ sở của chương trình thành 0x80200000, đây là địa chỉ bắt đầu của chương trình được tải vào bộ nhớ.
PHẦN
: Bắt đầu xác định bố cục của phân đoạn bộ nhớ.
. = CƠ SỞ_ĐỊA CHỈ;
: Đặt địa chỉ hiện tại làm địa chỉ cơ sở.
da = .;
: Ghi lại địa chỉ bắt đầu của phân đoạn kernel.
văn bản = .;
: Ghi địa chỉ bắt đầu của đoạn văn bản (đoạn mã).
.chữ
: Xác định một đoạn văn bản, chứa mã thực thi.
*(.text.entry)
*(.text .text.*)
có nghĩa là tất cả
.chữ.*
Nội dung phần được liên kết ở đây.
. = CĂN HỘ(4K);
: Căn chỉnh địa chỉ hiện tại theo ranh giới 4K (4096 byte).
etext = .;
: Ghi địa chỉ cuối của đoạn văn bản.
srodata = .;
: Ghi lại địa chỉ bắt đầu của phân đoạn dữ liệu chỉ đọc.
: Xác định phân đoạn dữ liệu chỉ đọc, bao gồm các hằng số và dữ liệu chỉ đọc.
*(.rodata .rodata.*)
*(.srodata .srodata.*)
.srodata
erodata = .;
: Ghi lại địa chỉ cuối của phân đoạn dữ liệu chỉ đọc.
sdata = .;
: Ghi lại địa chỉ bắt đầu của đoạn dữ liệu khởi tạo.
: Xác định phân đoạn dữ liệu khởi tạo, bao gồm các biến toàn cục được khởi tạo.
*(.data .data.*)
*(.sdata .sdata.*)
.sdata
edata = .;
: Ghi lại địa chỉ cuối của đoạn dữ liệu khởi tạo.
: Xác định phân đoạn dữ liệu chưa được khởi tạo (phân đoạn BSS), bao gồm các biến toàn cục chưa được khởi tạo.
*(.bss.stack)
*(.bss .bss.*)
cũng như
*(.sbss .sbss.*)
.sbss
.bss.stack
sss = .;
Ghi lại địa chỉ bắt đầu của phân đoạn BSS.
ebss = .;
: Ghi lại địa chỉ cuối của đoạn dữ liệu chưa được khởi tạo.
hạt nhân = .;
: Ghi lại địa chỉ cuối của toàn bộ phân đoạn kernel.
/BỎ BỎ/
: Xác định phần loại bỏ để loại trừ các phần không cần thiết, ở đây quy định là không bao gồm
.eh_frame
phần này, thông thường phần này chứa thông tin khung xử lý ngoại lệ.
Tương ứng với việc tạo các chức năng nhập và khởi tạo hệ thống
Tạo mô-đun lib.rs
chạm vào lib.rs
Giống như main.rs của os, khi tạo mục nhập hàm, hãy sử dụng #[no_mangle] để đảm bảo tên hàm không được tối ưu hóa và sử dụng macro mới #[link_section = ".text.entry"] để tạo _start mã này. mã hợp ngữ đã biên dịch được đặt trong một tệp có tên .text.entry Trong đoạn mã, thuận tiện cho chúng ta điều chỉnh vị trí của nó trong quá trình liên kết tiếp theo để nó có thể đóng vai trò là lối vào thư viện người dùng. Ở đây cần lưu ý rằng chúng ta vẫn chỉ có thể sử dụng thư viện lõi nên chúng ta phải sử dụng. #![no_std] macro
#![no_std] #[no_mangle] #[link_section = ".text.entry"] pub extern "C" fn _start() -> ! { clear_bss(); sys_exit!"); }
Tương ứng với Chương 1, bạn cũng cần xóa phần .bss và sử dụng macro hoảng loạn!
#![feature(panic_info_message)] fn clear_bss() { extern "C" { fn start_bss(); fn end_bss(); } (start_bss as usize..end_bss as usize).for_each(|addr| không an toàn { (addr as *mut u8).write_volatile(0); } }
Và dùng giao diện exit để gọi hàm main. Giao diện exit ở đây chỉ có thể thực hiện được thông qua ecall sau này đối với hàm main nếu có ký hiệu main trong thư mục bin thì chương trình có thể liên kết bình thường, nhưng khi đó chúng ta không thể liên kết được. tìm chính, chúng tôi cũng cần phải có một Đảm bảo, điều này liên quan đến các liên kết yếu. Nếu không tìm thấy chính, hãy liên kết đến chính.
#![feature(linkage)] #[linkage = "weak"] #[no_mangle] fn main() -> i32 { hoảng loạn!("Không thể tìm thấy main!" }
Tạo mô-đun cuộc gọi hệ thống
Tạo mô-đun syscall. Tệp này được tạo trong tệp người dùng/src.
touchsyscall.rs
Chúng tôi sử dụng mã hợp ngữ nhúng của Rust để gọi ecall nhằm bắt đầu các cuộc gọi hệ thống ở chế độ người dùng.
Khi một tiến trình thực thi lệnh ecall, bộ xử lý sẽ kích hoạt một ngoại lệ, khiến điều khiển chuyển sang trình xử lý ngoại lệ kernel đặt trước. Tại thời điểm này, kernel có thể kiểm tra ngữ cảnh đã kích hoạt ecall và cung cấp các dịch vụ phù hợp dựa trên các tham số được truyền vào, chẳng hạn như mở tệp, tạo tiến trình, phân bổ bộ nhớ, v.v.
Bản thân lệnh ecall không mang bất kỳ tham số nào, nhưng nó có thể truy cập các giá trị trong các thanh ghi chung và chuyển chúng vào kernel dưới dạng tham số. Thông thường, các thanh ghi sau được sử dụng để truyền tham số:
x10
(a0): tham số đầu tiên
x11
(a1): tham số thứ hai
x12
(a2): Tham số thứ ba
x13
(a3): Tham số thứ tư
x14
(a4): Tham số thứ năm
x15
(a5): Tham số thứ sáu
x16
(a6): Tham số thứ bảy
x17
(a7): Tham số thứ tám, cũng đóng vai trò là số cuộc gọi hệ thống
Sau đó, bạn có thể tạo giao diện trong tệp syscall.rs
// user/src/syscall.rs use core::arch::asm; fn syscall(id: usize, args: [usize; 3]) -> isize { let mut ret: isize không an toàn { asm!( " ecall ", inlateout("x10") args[0] => ret, in("x11") args[1], in("x12") args[2], in("x17") id } ret }
Format macro asm!
Đầu tiên, dòng 6 chính là đoạn mã hợp nhất mà chúng tôi muốn chèn ở đây, chúng tôi chỉ chèn một dòng. 
 hướng dẫn, nhưng nó có thể hỗ trợ chèn nhiều hướng dẫn cùng một lúc.
Bắt đầu từ dòng 7, chúng tôi liên kết các biến đầu vào/đầu ra với các thanh ghi với sự trợ giúp của trình biên dịch dịch.
Ví dụ: dòng 8 
trong ("x11") tranh luận [1]
 Có nghĩa là các thông số sẽ được nhập 
lập luận[1]
 kill with 
 ghi đầu vào 
 Instant setting 
a1
 , trình biên dịch sẽ tự động chèn các lệnh liên quan và chắc chắn rằng 
 đăng ký trước khi thực hiện lệnh này 
 Giá trị của 
 như nhau.
Theo cách tương tự, chúng tôi có thể đặt các tham số đầu vào 
lập luận[2]
 Liên kết với các thanh ghi tương ứng 
a2
a7
 ở giữa.
Điều đặc biệt ở đây là 
a0
 Thanh ghi, đóng vai trò vừa đầu vào vừa là đầu ra, vì vậy chúng ta sẽ 
 Change thành công 
vào sau
 và trong phần biến ở dòng cuối cùng, hãy sử dụng 
{in_var} => {out_var}
 format, ở đâu 
{in_var}
{out_var}
 Giao diện cho các biến đầu vào và đầu ra biến trong bối cảnh tương ứng.
Trong chương trình này, hai lệnh gọi hệ thống sau đây được thống nhất giữa chương trình ứng dụng và hệ thống xử lý hàng loạt theo API cấu hình:
/// Chức năng: Ghi dữ liệu vào bộ nhớ đệm vào tệp /// Tham số: `fd` đại diện cho tệp mô tả của file. được ghi; /// `buf` đại diện cho địa chỉ bắt đầu của bộ đệm trong bộ nhớ /// `len` đại diện cho chiều dài; /// ID tòa nhà: 64 fn sys_write(fd: usize, buf: *const u8, len: usize) -> isize; /// Chức năng: Thoát khỏi ứng dụng và thông báo cho hệ thống xử lý hàng hóa về giá trị trả về /// Tham số: `exit_code` biểu tượng /// ID tòa nhà: 93 fn sys_exit(exit_code: useize) -> !;
Tương tự như vậy, chúng tôi có thể sử dụng syscall để phát triển API này
// user/src/syscall.rs const SYSCALL_WRITE: usize = 64; const SYSCALL_EXIT: usize = 93; pub fn sys_write(fd: usize, buffer: &[u8]) -> isize { syscall(SYSCALL_WRITE, [fd, buffer .as_ptr() as usize, buffer.len()]) } pub fn sys_exit(xstate: i32) -> isize { syscall(SYSCALL_EXIT, [xstate as usize, 0, 0]) }
Lưu ý rằng sys_write sử dụng lát lát &[u8] để mô tả bộ đệm, đó là một con trỏ béo (Con trỏ béo), chứa cả địa chỉ chỉ bắt đầu bộ đệm và độ dài của bộ đệm. ứng dụng và sử dụng chúng để tạo ra một tham số gọi hệ thống thực tế một cách độc lập.
Đóng gói bổ sung giao diện

Lưu ý sau khi mở port nhớ nhả port nhé! ! ! Ngoài việc phát hành chùa, máy chủ của bạn (Alibaba Cloud/Tencent Cloud, v.v.) cũng nhớ phát hành nó! ! ! .

Bắt đầu công nhân

Mở terminal trong thư mục gốc của dự án và nhập php start_all_workman.php start -d để bắt đầu quá trình daemon. Nếu trang sau xuất hiện, nó sẽ được khởi động thành công.

hình ảnh

Nếu bạn muốn tắt tiến trình Workman, hãy nhập php start_all_workman.php stop để tắt.

GatewayWorker sử dụng

Nếu trang web của bạn sử dụng giao thức Https thì WebSocket phải sử dụng giao thức wss. Tuy nhiên, giao thức wss không hỗ trợ định dạng IP:port. Thay vào đó, nó chỉ có thể ghi tên miền + url. Giao thức https và WebSocket không thể kết nối, bạn có thể sử dụng Nginx thực hiện proxy ngược và thêm đoạn mã sau vào máy chủ trong tệp cấu hình trang web.

location /connectWorkman (tên tùy thuộc vào bạn, không sử dụng cùng tên với các proxy ngược khác) { proxy_pass http://127.0.0.1:8283; proxy_http_version 1.1; nâng cấp proxy_set_header Kết nối proxy_set_header; X-Real- IP $remote_addr }

Sử dụng giao diện người dùng (uniapp)

init() { SocketTask = uni.connectSocket({ url: 'wss://chat.gdpaimaihui.com/auction', //Tiêu đề chính thức: { 'content-type': 'application/json' }, thành công: function( res) { console.log('Đã tạo kết nối WebSocket', res); }, failed: function(err) { uni.showToast({ title: 'Ngoại lệ mạng! ', biểu tượng: 'none' }); console.log(err); } }); //sự kiện nghe websocket SocketTask.onOpen((res) => { socketOpen = true canReconnect = true console.log( 'Nghe sự kiện mở kết nối WebSocket. ', res); //Sau khi websocket được kết nối, bạn có thể bắt đầu hẹn giờ và thỉnh thoảng thực hiện đo nhịp tim để ngăn nhịp tim dừng lại và ngắt kết nối này.timer = setInterval(() => { SocketTask.send({ data: 'Heartbeat', Success() { // console.log('Gửi nhịp tim thành công'); } }) }, 2000) }); ( onError) => { console.log('Đang nghe lỗi WebSocket. Thông báo lỗi', onError socketOpen = false if (canReconnect) { this.reconnect() canReconnect); = false } }); SocketTask.onMessage((res) => { console.log('Lắng nghe sự kiện tin nhắn mà WebSocket nhận được từ máy chủ. Tin nhắn được máy chủ trả về', res); } }), / /Kết nối lại kết nối lại( ) { if (!socketOpen) { let count = 0; kết nối lạiInterval = setInterval(() => { console.log("Đang cố gắng kết nối lại") uni.showToast({ title: 'Đang cố gắng kết nối lại', biểu tượng: 'none' }) this.init(); count++ console.log(); // Không còn kết nối lại sau một số lần nhất định if (count >= connectTimes) { clearInterval(reconnectInterval ) uni .showToast({ title: 'Ngoại lệ mạng hoặc lỗi máy chủ', biểu tượng: 'none' }) } }, kết nối lạiDelay) } }

Trên đây là nội dung mình biên soạn khi đang làm phần mềm truyền thông nội bộ cho công ty. Nếu có sai sót xin chỉ giáo. Nếu thấy hay thì hãy nhấn vào để giới thiệu và theo dõi nhé! Cảm ơn bạn~๑·́₃·̀๑ [花][花][花].

Cuối cùng, bài viết này về [workerman] uniapp+thinkPHP5 sử dụng GatewayWorker để đạt được giao tiếp thời gian thực kết thúc tại đây. Nếu bạn muốn biết thêm về [workerman]uniapp+thinkPHP5 sử dụng GatewayWorker để đạt được giao tiếp thời gian thực, vui lòng tìm kiếm bài viết CFSDN. tiếp tục Duyệt các bài viết liên quan, tôi hy vọng bạn sẽ ủng hộ blog của tôi trong tương lai! .

58 4 0
Chứng chỉ ICP Bắc Kinh số 000000
Hợp tác quảng cáo: 1813099741@qq.com 6ren.com
Xem sitemap của VNExpress