簡體   English   中英

客戶端服務器套接字 C#

[英]Client server socket C#

我正在研究套接字 C#。 我已經使用套接字實現了一個客戶端服務器應用程序,但問題是客戶端沒有收到服務器發送的所有數據。

這是客戶端應用程序代碼。 我應該怎么做才能接收服務器發送的所有數據?

strRecieved = "";
Socket soc = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);

IPEndPoint endPoint = new IPEndPoint(IPAddress.Parse("127.0.0.1"), 9001);
soc.Connect(endPoint);
byte[] msgBuffer = Encoding.Default.GetBytes(path);
soc.Send(msgBuffer, 0, msgBuffer.Length, 0);
byte[] buffer = new byte[2000];
int rec = soc.Receive(buffer);

strRecieved = String.Format(Encoding.Default.GetString(buffer));

首先。 如果您正在實現某種流功能(tcp/udp/file),您應該考慮使用某種協議

什么是協議? 這只是流式傳輸數據時使用的一種方案。 例子:

[4Bytes - 長度][lengthBytes - 消息][1Byte - 終止指示符]

了解協議后,您可以簡單地讀取所有傳入的字節:

byte[] buffer = new byte[4];
stream.ReadBytes(buffer, 0, 4); // cast that to int and read the rest

int packetLen = BitConverter.ToInt32(buffer, 0);
buffer = new byte[packetLen];
stream.ReadBytes(buffer, 0, buffer.Length); // all bytes that was sent

請記住,您必須在發送消息之前減去這 4 個字節的長度。

編輯:

關於如何使用共享協議發送和接收數據的簡單示例。

// sender.cs
string _stringToSend = "some fancy string";
byte[] encodedString = Encoding.UTF8.GetBytes(_stringToSend);
List<byte> buffer = new List<byte>();
buffer.AddRange(BitConverter.GetBytes(encodedString.Length));
buffer.AddRange(encodedString);
netStream.WriteBytes(buffer.ToArray(), 0, buffer.Count);
// netStream sent message in protocol [@LEN - 4Bytes][@MSG - @LENBytes]
// simply speaking something like: 5ABCDE

// receiver.cs
byte[] buffer = new byte[sizeof(int)];
netStream.ReadBytes(buffer, 0, buffer.Length);
// receiver got the length of the message eg. 5
int dataLen = BitConverter.ToInt32(buffer, 0);
buffer = new byte[dataLen];
// now we can read an actual message because we know it's length
netStream.ReadBytes(buffer, 0, buffer.Length);
string receivedString = Encoding.UTF8.GetString(buffer);
// received string is equal to "some fancy string"

讓它更簡單

此技術強制您使用所需的協議,在本例中為:

前 4 個字節sizeof(int)表示傳入數據包的長度,每個字節都是您的數據包,直到結束。

所以現在你應該讓ProtocolHelper對象:

public static class ProtocolHelper
{
    public byte[] PackIntoProtocol(string message)
    {
        List<byte> result = new List<byte>();
        byte[] messageBuffer = Encoding.UTF8.GetBytes(message);
        result.AddRange(BitConverter.GetBytes(messageBuffer.Length), 0); // this is the first part of the protocol ( length of the message )
        result.AddRange(messageBuffer); // this is actual message
        return result.ToArray();
    }

    public string UnpackProtocol(byte[] buffer)
    {
        return Encoding.UTF8.GetString(buffer, 0, buffer.Length);
    }
}

現在(取決於您選擇從網絡讀取的方法)您必須發送和接收您的消息。

// sender.cs
string meMessage = "network message 1";
byte[] buffer = ProtocolHelper.PackIntoProtocol(meMessage);
socket.Send(buffer, 0, buffer.Length, 0);

// receiver.cs
string message = string.Empty;
byte[] buffer = new byte[sizeof(int)]; // or simply new byte[4];
int received = socket.Receive(buffer);
if(received == sizeof(int))
{
    int packetLen = BitConverter.ToInt32(buffer);// size of our message
    buffer = new byte[packetLen]; 
    received = socket.Receive(buffer);
    if( packetLen == received ) // we have full buffer
    {
        message = PacketHelper.UnpackProtocol(buffer);
    }
}
Console.WriteLine(message); // output: "network message 1"

當您使用new byte[2000] ,您將接收到的消息的大小限制為 2KB。 我認為你可以:

  • 調整緩沖區大小以滿足您的消息大小需求; 和/或
  • 將您的消息拆分為多個套接字消息。

鑒於 4-8K 是緩沖套接字消息的合適大小,並且假設 RAM 大小不是問題,我將從new byte[8000]

此外,您可以發送分成塊的套接字消息。 也許這是一個好主意。 例如,如果您將msg作為要發送的消息(或對象):

private static async Task SendAnswer(Message msg, WebSocket socket)
{
    var answer = System.Text.Encoding.UTF8.GetBytes(JsonConvert.SerializeObject(msg).ToCharArray());

    var bufferSize = 8000;
    var endOfMessage = false;
    for (var offset = 0; offset < answer.Length; offset += bufferSize)
    {
        if (offset + bufferSize >= answer.Length)
        {
            bufferSize = answer.Length - offset;
            endOfMessage = true;
        }
        await socket.SendAsync(new ArraySegment<byte>(answer, offset, bufferSize),
            WebSocketMessageType.Text, endOfMessage, CancellationToken.None);
    }
}

並且在接收時,您還可以將接收分成塊,這樣您就可以控制緩沖區(從而控制內存消耗)。 處理完整個消息后,您應該等待來自客戶端的另一條消息來做更多的事情。 來源

private async Task ReceiveMessage(WebSocket webSocket)
{
    var buffer = new byte[8000];
    var result = await webSocket.ReceiveAsync(buffer, CancellationToken.None);
    while (!result.CloseStatus.HasValue)
    {
        string msg = Encoding.UTF8.GetString(new ArraySegment<byte>(buffer, 0, result.Count).ToArray());
        while (!result.EndOfMessage)
        {
            result = await webSocket.ReceiveAsync(buffer, CancellationToken.None);
            msg += Encoding.UTF8.GetString(new ArraySegment<byte>(buffer, 0, result.Count).ToArray());
        }

        //At this point, `msg` has the whole message you sent, you can do whatever you want with it.
        // [...]
        //After you handle the message, wait for another message from the client
        result = await webSocket.ReceiveAsync(buffer, CancellationToken.None);
    }
    await webSocket.CloseAsync(result.CloseStatus.Value, result.CloseStatusDescription, CancellationToken.None);
}

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM