07/09/2018, 16:03

Gọi Ruby từ Erlang

Viết lại thư viện đã có sẵn của ngôn ngữ khác ít khi nào là nhiệm vụ thú vị, nên thường có chiêu thức nối ngôn ngữ này với ngôn ngữ kia với những cái tên mỹ miều như: interface, extension, external, foreign, mẹ ơi v.v. Chung qui bản chất của chiêu thức này chỉ là truyền thông tin từ chỗ này sang ...

Viết lại thư viện đã có sẵn của ngôn ngữ khác ít khi nào là nhiệm vụ thú vị, nên thường có chiêu thức nối ngôn ngữ này với ngôn ngữ kia với những cái tên mỹ miều như: interface, extension, external, foreign, mẹ ơi v.v. Chung qui bản chất của chiêu thức này chỉ là truyền thông tin từ chỗ này sang chỗ khác.

Hãy thử viết thư viện Revaler cho phép các ngôn ngữ khác gọi Ruby:

  • Tạo Ruby server.
  • Server nhận chuỗi kí tự từ client.
  • Chuỗi kí tự được evaluate trên server, kết quả được ép thành kiểu chuỗi rồi trả về cho client.

Cách trên tuy tổng quát nhưng còn đơn giản. Còn có thể cải tiến bằng cách gói chuỗi kí tự (chuỗi trả về hoặc gửi đi hoặc cả hai) bằng định dạng nào đó, chẳng hạn JSON hoặc SOAP.

Qui định dữ liệu

Ta qui định dạng của dữ liệu gửi từ client đến server và ngược như sau:

  • 4 byte đầu tiên dùng để chứa thông tin về chiều dài chuỗi kí tự phía sau. Thứ tự các byte theo chuẩn big-endian.
  • Các byte tiếp theo là chuỗi kí tự.

Tạo Ruby server

Mặc dù Ruby có sẵn thư viện để lập trình mạng, nhưng chúng ta dùng thư viện dễ dùng hơn nhiều là EventMachine để tạo server. EventMachine rất phổ biến và nhiều tài liệu. Cơ chế chung khi tạo server bằng EventMachine như sau:

  • Viết callback module có các hàm post_init, receive_data, unbind.
  • Khi có client connect đến, EventMachine sẽ tạo object ứng với connection này, rồi dùng tính năng include của Ruby để nhúng module ta tạo vào object này.
  • Khi có sự kiện (bởi vậy mới gọi là EventMachine) nào đó liên quan đến connection, thì hàm trong module ta tạo sẽ tự động được gọi.

Ruby dùng String để lưu chuỗi dữ liệu nhị phân. Để biến một số x thành chuỗi dữ liệu nhị phân theo big-endian: [x].pack('N'), nghĩa là biến số thành mảng, rồi dùng hàm pack của mảng. Để lấy giá trị của byte từ chuỗi kí tự, có thể dùng hàm unpack và/hoặc slice của chuỗi.

Evaluate

Các ngôn ngữ động như Ruby, PHP, Python, JavaScript, Erlang v.v. đều có tính năng evaluate chuỗi kí tự để cho ra kết quả gì đó. Ví dụ kết quả của eval("x = 1; y = 2; x + y") là 3.

Đi kèm với khái niệm evaluate là khái niệm binding, còn có những tên mỹ miều khác như context, environment v.v. Ví dụ nếu môi trường đã có sẵn biến z có giá trị 3, thì eval("z + 3") sẽ ra kết quả là 6, mặc dù bản thân chuỗi "z + 3" không cho biết z là gì giá trị ra sao. Do đó, lệnh eval trong các ngôn ngữ thường có 2 tham số: eval(string, binding). Sau khi evaluate, môi trường bị thay đổi, ta cần lưu lại môi trường để dùng cho lần evaluate tiếp theo.

Erlang client

Dựa vào qui định dữ liệu, có thể viết client cho bất kì ngôn ngữ nào có hỗ trợ lập trình socket. Phần này bàn cách viết client cho Erlang.

Cũng như Ruby, Erlang có sẵn thư viện để lập trình mạng tên là gen_tcp. Nhưng khác Ruby là thư viện này rất dễ dùng. Ngoài ra, thư viện này còn có tính năng tự động xử lí 4 byte header do ta chỉ định. Khi tạo kết nối đến server, chỉ cần chỉ định {packet, 4} là khi truyền dữ liệu đi gen_tcp tự động thêm 4 byte đầu tiên và khi nhận dữ liệu nó tự động tách 4 byte đầu tiên.

Tham khảo

  • Erlectricity
  • RBridge
  • Interoperability
0