Kiểm tra trạng thái socket
Khi làm việc với socket, việc kiểm tra trạng thái của nó trở nên cần thiết vì các mạng phân tán không đáng tin cậy như hệ thống tệp. Đặc biệt, kết nối có thể bị mất vì một lý do nào đó. Hàm SocketIsConnected
cho phép bạn tìm hiểu điều này.
bool SocketIsConnected(const int socket)
Hàm kiểm tra xem socket với tay cầm được chỉ định (lấy từ SocketCreate
) có được kết nối với tài nguyên mạng của nó (được chỉ định trong SocketConnect
) hay không và trả về true
trong trường hợp thành công.
Một hàm khác, SocketIsReadable
, cho bạn biết liệu có dữ liệu nào để đọc trong bộ đệm hệ thống liên quan đến socket hay không. Điều này có nghĩa là máy tính mà chúng ta đã kết nối tại địa chỉ mạng đã gửi (và có thể tiếp tục gửi) dữ liệu cho chúng ta.
uint SocketIsReadable(const int socket)
Hàm trả về số byte có thể đọc từ socket. Trong trường hợp lỗi, 0 được trả về.
Các lập trình viên quen thuộc với API hệ thống socket Windows/Linux biết rằng giá trị 0 cũng có thể là trạng thái bình thường khi không có dữ liệu đến trong bộ đệm nội bộ của socket. Tuy nhiên, hàm này hoạt động khác trong MQL5. Với bộ đệm socket hệ thống trống, nó suy đoán trả về 1, trì hoãn việc kiểm tra thực sự sự sẵn có của dữ liệu cho đến lần gọi tiếp theo của một trong các hàm đọc. Đặc biệt, tình huống này với kết quả giả 1 byte thường xảy ra, theo quy tắc, lần đầu tiên một hàm được gọi trên socket khi bộ đệm nội bộ nhận vẫn còn trống.
Khi thực thi hàm này, có thể xảy ra lỗi, nghĩa là kết nối được thiết lập qua SocketConnect
đã bị ngắt (trong _LastError
, chúng ta sẽ nhận được mã 5273, ERR_NETSOCKET_IO_ERROR).
Hàm SocketIsReadable
hữu ích trong các chương trình được thiết kế để đọc dữ liệu "không chặn" bằng SocketRead
. Vấn đề là hàm SocketRead
, khi không có dữ liệu trong bộ đệm nhận, sẽ đợi chúng đến, tạm dừng việc thực thi chương trình (theo giá trị thời gian chờ được chỉ định).
Mặt khác, việc đọc chặn đáng tin cậy hơn ở chỗ chương trình của bạn sẽ "thức dậy" ngay khi dữ liệu mới đến, nhưng việc kiểm tra sự hiện diện của chúng bằng SocketIsReadable
cần được thực hiện định kỳ, theo một số sự kiện khác (thường là trên bộ đếm thời gian hoặc trong một vòng lặp).
Cần đặc biệt cẩn thận khi sử dụng hàm SocketIsReadable
trong chế độ bảo mật TLS. Hàm trả về lượng dữ liệu "thô", mà trong chế độ TLS là một khối mã hóa. Nếu dữ liệu "thô" chưa tích lũy đủ kích thước của khối giải mã, thì lần gọi tiếp theo của hàm đọc SocketTlsRead
sẽ chặn thực thi chương trình, đợi phần còn thiếu. Nếu dữ liệu "thô" đã chứa một khối sẵn sàng để giải mã, hàm đọc sẽ trả về ít byte đã giải mã hơn số byte "thô". Về vấn đề này, khi TLS được bật, nên luôn sử dụng hàm SocketIsReadable
kết hợp với SocketTlsReadAvailable
. Nếu không, hành vi của chương trình sẽ khác với kỳ vọng. Thật không may, MQL5 không cung cấp hàm SocketTlsIsReadable
, tương thích với chế độ TLS và không áp đặt các quy ước được mô tả.
Hàm tương tự SocketIsWritable
kiểm tra xem socket được chỉ định có thể ghi vào tại thời điểm hiện tại hay không.
bool SocketIsWritable(const int socket)
Hàm trả về chỉ báo thành công (true
) hoặc lỗi (false
). Trong trường hợp sau, kết nối được thiết lập qua SocketConnect
sẽ bị ngắt.
Dưới đây là một script đơn giản SocketIsConnected.mq5
để kiểm tra các hàm. Trong các tham số đầu vào, chúng ta sẽ cung cấp cơ hội nhập địa chỉ và cổng.
input string Server = "www.mql5.com";
input uint Port = 443;
2
Trong trình xử lý OnStart
, chúng ta tạo một socket, kết nối với trang web và bắt đầu kiểm tra trạng thái của socket trong một vòng lặp. Sau lần lặp thứ hai, chúng ta buộc đóng socket, và điều này sẽ dẫn đến thoát khỏi vòng lặp.
void OnStart()
{
PRTF(Server);
PRTF(Port);
const int socket = PRTF(SocketCreate());
if(PRTF(SocketConnect(socket, Server, Port, 5000)))
{
int i = 0;
while(PRTF(SocketIsConnected(socket)) && !IsStopped())
{
PRTF(SocketIsReadable(socket));
PRTF(SocketIsWritable(socket));
Sleep(1000);
if(++i >= 2)
{
PRTF(SocketClose(socket));
}
}
}
}
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
Các mục sau được hiển thị trong nhật ký.
Server=www.mql5.com / ok
Port=443 / ok
SocketCreate()=1 / ok
SocketConnect(socket,Server,Port,5000)=true / ok
SocketIsConnected(socket)=true / ok
SocketIsReadable(socket)=0 / ok
SocketIsWritable(socket)=true / ok
SocketIsConnected(socket)=true / ok
SocketIsReadable(socket)=0 / ok
SocketIsWritable(socket)=true / ok
SocketClose(socket)=true / ok
SocketIsConnected(socket)=false / NETSOCKET_INVALIDHANDLE(5270)
2
3
4
5
6
7
8
9
10
11
12