Tôi thích ứng với bài đăng dài này. Tôi đã làm cho nó càng nhỏ càng tốt trong khi vẫn truyền tải được vấn đề.Rất lạ Vấn đề gửi dữ liệu qua Ổ cắm trong C#
Ok điều này khiến tôi phát điên. Tôi có một khách hàng và một chương trình máy chủ, cả trong C#. Máy chủ gửi dữ liệu đến máy khách thông qua Socket.Send(). Máy khách nhận dữ liệu qua Socket.BeginReceive và Socket.Receive. Giao thức giả của tôi như sau: Máy chủ gửi một giá trị song song (ngắn) cho biết độ dài của dữ liệu thực tế được theo sau bởi dữ liệu thực tế. Máy khách đọc hai byes đầu tiên một cách không đồng bộ, chuyển đổi các byte thành một đoạn ngắn và ngay lập tức đọc nhiều byte từ socket một cách đồng bộ.
Bây giờ điều này hoạt động tốt cho một chu kỳ mỗi vài giây hoặc lâu hơn nhưng khi tôi tăng tốc độ, mọi thứ trở nên kỳ lạ. Dường như khách hàng sẽ đọc ngẫu nhiên dữ liệu thực tế khi nó đang cố gắng đọc từ độ dài hai byte. Sau đó nó sẽ cố gắng chuyển đổi hai byte tùy ý này thành một đoạn ngắn dẫn đến giá trị hoàn toàn không chính xác, gây ra sự cố. Đoạn mã sau là từ chương trình của tôi nhưng được cắt bớt để chỉ hiển thị các dòng quan trọng.
phương pháp phía máy chủ để gửi dữ liệu:
private static object myLock = new object();
private static bool sendData(Socket sock, String prefix, byte[] data)
{
lock(myLock){
try
{
// prefix is always a 4-bytes string
// encoder is an ASCIIEncoding object
byte[] prefixBytes = encoder.GetBytes(prefix);
short length = (short)(prefixBytes.Length + data.Length);
sock.Send(BitConverter.GetBytes(length));
sock.Send(prefixBytes);
sock.Send(data);
return true;
}
catch(Exception e){/*blah blah blah*/}
}
}
phương pháp Client-side để tiếp nhận dữ liệu:
private static object myLock = new object();
private void receiveData(IAsyncResult result)
{
lock(myLock){
byte[] buffer = new byte[1024];
Socket sock = result.AsyncState as Socket;
try
{
sock.EndReceive(result);
short n = BitConverter.ToInt16(smallBuffer, 0);
// smallBuffer is a 2-byte array
// Receive n bytes
sock.Receive(buffer, n, SocketFlags.None);
// Determine the prefix. encoder is an ASCIIEncoding object
String prefix = encoder.GetString(buffer, 0, 4);
// Code to process the data goes here
sock.BeginReceive(smallBuffer, 0, 2, SocketFlags.None, receiveData, sock);
}
catch(Exception e){/*blah blah blah*/}
}
}
server-side code để tái tạo vấn đề đáng tin cậy:
byte[] b = new byte[1020]; // arbitrary length
for (int i = 0; i < b.Length; i++)
b[i] = 7; // arbitrary value of 7
while (true)
{
sendData(socket, "PRFX", b);
// socket is a Socket connected to a client running the same code as above
// "PRFX" is an arbitrary 4-character string that will be sent
}
Nhìn vào mã ở trên, người ta có thể xác định rằng máy chủ sẽ mãi gửi số 1024, độ dài của tổng số dữ liệu, bao gồm tiền tố, dưới dạng ngắn (0x400), tiếp theo là "PRFX" trong mã nhị phân ASCII theo sau là một loạt 7 (0x07). Máy khách sẽ đọc vĩnh viễn hai byte đầu tiên (0x400), giải thích rằng là 1024, lưu trữ giá trị đó dưới dạng n và sau đó đọc 1024 từ luồng.
Đây thực sự là những gì nó thực hiện trong 40 lần lặp đầu tiên, nhưng, một cách tự nhiên, khách hàng sẽ đọc hai byes đầu tiên và giải thích chúng là 1799, không phải 1024! 1799 trong hex là 0x0707 là hai liên tiếp 7's !!! Đó là dữ liệu chứ không phải độ dài! Điều gì đã xảy ra với hai byte đó? Điều này xảy ra với bất kỳ giá trị nào tôi đặt trong mảng byte, tôi chỉ chọn 7 vì nó rất dễ thấy mối tương quan với 1799.
Nếu bạn vẫn đọc vào thời điểm này, tôi hoan nghênh sự cống hiến của bạn.
Một số quan sát quan trọng:
- Giảm chiều dài của b sẽ làm tăng số lần lặp trước khi vấn đề xảy ra nhưng không ngăn cản các vấn đề xảy ra
- Thêm một sự chậm trễ đáng kể giữa mỗi lần lặp của vòng lặp có thể ngăn sự cố xảy ra
- Điều này KHÔNG xảy ra khi sử dụng cả máy khách và máy chủ trên cùng một máy chủ và kết nối qua địa chỉ lặp lại.
Như đã đề cập, điều này khiến tôi phát điên! Tôi luôn có thể giải quyết các vấn đề lập trình của mình nhưng vấn đề này đã hoàn toàn làm tôi bối rối. Vì vậy, tôi ở đây cầu xin cho bất kỳ tư vấn hoặc kiến thức về chủ đề này.
Cảm ơn bạn.
Đây là vấn đề tôi gặp phải tại một thời điểm. Hãy thử đọc dữ liệu từ mạng trong một vòng lặp while cho đến khi bạn đọc lượng dữ liệu được chỉ định trong tham số "length" – Kurru
Đăng nhập lại 1024; nó có thể tất nhiên không chỉ khi đọc tiêu đề 2 byte –
@Marc - tôi có nghĩa là thông qua việc ghi giá trị trả về của Receive, bạn sẽ thấy ít hơn 1024 trong trường hợp thử nghiệm nhất định nếu mạng cơ bản cung cấp ít hơn toàn bộ thông điệp trong một Nhận. –