Làm sao để tách string trong Winsock?

Thái Minh Hoàng Hà
(Jolly Joker)

Điều hành viên<br><a href="http://www.hn-ams.org/f
Khi làm chương trình giao tiếp mạng thì em gặp phải vấn đề như sau:
Nếu dùng winsock gửi dữ liệu liên tục thì phía bên kia khi nhận được sẽ bị hiện tượng các string dính lại với nhau, VD:
Dùng lệnh:
Sub cmdSend_click()
For i=1 to 3
wsckClient.SendData "Example"
Next i
End Sub

thì bên kia sẽ thu được:

Sub wsckServer_DataArrival(....)
Dim strData as string
wsckServer.GetData strData
'strData="ExampleExampleExample"
End Sub

Vậy có ai có giải pháp gì giúp em với, ngoại trừ cách dùng 1 hàm pause nào đó nhé, vì như thế không hay ;) . Em đã thử dùng cách đánh dấu điểm đầu và cuối của mỗi packet và dùng hàm Split để tách, nhưng hình như vẫn không ổn...:cry:
 
Chỉnh sửa lần cuối:
Em phải có hàm để biết được trạng thái của các packet mình nhận được.

Ví dụ như

Mã:
While(Some_Condition == False) {
  Read_Packet_to_Buffer
}
Analyze_Packet(Buffer)

Em có thể dùng một ký tự đặc biệt để nhận dạng đoạn kết thúc của packet. Condition có thể là số packet hay một ký tự đánh dấu TranstionEnd.

Cheer,
ĐTrang
 
Chỉnh sửa lần cuối:
Em đã thử một số cách rồi ạ, chẳng hạn như em thêm vào cuối mỗi packet chữ {ENDOFPACKET} để đánh dấu, rồi dùng hàm split cắt packet ra, nhưng nếu gửi dữ liệu liên tục thì vẫn gặp trục trặc, nhất là khi mạng bị quá tải hoặc mạng chậm, thậm chí chạy trên LAN 100mbps vẫn bị :(
Em đã thử viết chương trình cho listen port 12345 để xem thử mấy thằng hacker nó dùng cách nào trong NetBus, hóa ra cũng như vậy cả thôi nhưng ít khi bị lỗi lắm...:cry:
 
socket layer chỉ đảm bảo raw data được gửi/nhận đầy đủ và chính xác, hoàn toàn không biết gì về nội dung được gủi. Cho nên một message có khi nhận đựoc cả cục, có khi bị chia làm nhiều đợt (tuy nhiên thứ tự đến nơi vẫn đảm bảo) do cơ chế của socket, chứ không phải do đường truyền đâu.

Để proccess message chính xác thì cách đơn giản và hiệu quả nhât là em tự thiết kế một protocol trên application layer. Thêm vào mỗi packet một chuỗi như em làm cũng là một kiểu, nhưng hiệu quả hơn là nên gửi kèm kích thước của message, bên nhận chỉ cần đọc đúng số byte từ socket stream ra là ổn. Tốt hơn nữa là nên kèm theo một số trường khác chứa thông tin về dạng message (hay opcode), kich thước header vv..., sẽ có lợi cho checksum hoặc mở rộng về sau. Ví dụ:

TMHHxxxxMSGyyyyExample

TMHH đánh dấu bắt đầu message, xxxx chứa độ dài header duới dạng int (32bit), trong truờng hơp này là 0x03. MSG la opcode, tiếp theo là 32 bit chứa độ dài của message (0x07 cho Example).
 
Ngoài cách của anh Điềm là tạo một protocol trên application layer ra em có thể tham khảo một phương pháp khác không được chính thống và an toàn lắm nhưng có lợi điểm là size của packet sẽ nhỏ hơn -> truyền nhanh hơn trong những mạng tốc độ chậm đấy là thay vì sử dụng hàm split để tách string thì em phải tự tạo cho mình một hàm tạm gọi là "dynamic split" hoặc "flag check". Ví dụ giả sử ENDOFPACKET là string đánh dấu kết thúc packet thì em sẽ sử dụng một loop để đọc từng byte trong packet đó với condition là while(flag_check(char t) == false). Hàm flag check sẽ liên tục check từng byte của packet và nếu nó "green" liên tục "strlen("{ENDOFPACKET}")" lần thì tức là packet của em đã kết thúc. Mô tả nôm na:
int green_index = 1;
public bool flag_check(char t)
{
global green_index;
bool flag = false;
char[] a = new char[] {'E', 'D', 'O', 'F', 'P', 'A', 'C', 'K', 'E', 'T'};
if (t == a[green_index])
{
if(green_index == a.length)
{
flag = true;
}
else
{
flag = false; green_index++;
}
}
else
{
green_index = 1; flag = false;
}
return flag;
}

Lưu ý là để tránh trường hợp nhầm lẫn nếu trong packet contains chuỗi endofpacket thì em phải thêm một espace char nào đó (thường là "\") và cứ mỗi lần hit escape thì: skip checking flag ở 10 lần sau, ignore "\" và loại bỏ nhận dạng espace cho byte/char tiếp theo sau ("\\").

Nói chung cách này chỉ để tham khảo cho vui và có thể áp dụng vào những application đơn giản trong đường truyền nội bộ vì trên thực tế việc thiết lập định dạng cho từng phần của packet là việc rất cần thiết trên phương diện bảo mật và bảo đảm tính integrity cho dữ liệu vì bản thân packet của em có thể bị nhiễu hoặc bị hacker can thiệp trên đường truyền thế nên việc tạo ra header và định dạng cho packet sẽ có ưu điểm là hạn chế tối đa khả năng này mặc dầu việc làm này có thể làm tăng kích thước packet và hạn chế tốc độ.
 
Em muốn sử dụng một thư viện mã hóa nào đó như Blowfish hoặc Base64 để mã hóa thông tin gửi đi liệu có ổn không ạ? Nó có trở ngại gì cho việc gửi nhận dữ liệu không ạ? Em để ý thấy mấy IM như Yahoo hay MSN thường mã hóa sơ qua các packet thì phải!
Em sẽ thử áp dụng cách của các anh. Tại vì em đang viết một cái IM nhưng khó nhất là cái khâu gửi nhận này :(
À em cũng muốn hỏi thêm nữa ạ:
Ở server, mối khi có connection request thì em lại dùng cách là tăng một biến index lên, sau đó load một winsock mới để accept request. Cách này có cái bất lợi là sau một thời gian làm việc với các client nối/ngắt liên tục thì sẽ rất chiếm bộ nhớ và khó quản lý, mà chắc chắn sẽ gây nhiều lỗi khó chịu lắm. Các anh có thể giúp em làm một module VB chuyên về chuyện quản lý các instance của winsock để tránh lỗi trên không ạ, em xin cám ơn trước ạ!:D
 
Back
Bên trên