Client server socket C#

前端 未结 2 1174
情深已故
情深已故 2020-12-12 07:19

I am working on socket C#. I\'ve implemented a client server application using socket, but the problem is that the client doesn\'t receive all data sent by the server.

相关标签:
2条回答
  • 2020-12-12 07:34

    First of all. If you're implementing some kind of streaming feature ( tcp/udp/file ) you should consider using some kind of protocol.

    What is a protocol? It's just a scheme to use when streaming data. Example:

    [4Bytes - length][lengthBytes - message][1Byte - termination indicator]

    Knowing the protocol you can read all of the incoming bytes simply as such :

    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
    

    Remember that you have to subtract thease 4 bytes in the length before sending the message.

    EDIT:

    Simple example on how to send and receive data using shared protocol.

    // 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"
    

    Making it simpler

    This technique forces you to use desired protocol which in this example will be :

    First 4 bytes sizeof(int) are indicating the length of the incoming packet Every byte further is your packet until the end.

    So right now you should make ProtocolHelper object:

    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);
        }
    }
    

    Now ( depending on method you've chosen to read from network ) you have to send and receive your message.

    // 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"
    
    0 讨论(0)
  • 2020-12-12 07:53

    You're limiting the size of received messages by 2KB as you're using new byte[2000]. I think you could either:

    • Size up you buffer to meet you message's size needs; and/or
    • Split you message into more than one socket messages.

    Given that 4-8K is a good size for buffering socket messages and assuming RAM size is not a issue I would start with that, say, new byte[8000].

    Also, you can send socket messages splitted in chunks. Maybe this is a good idea for the case. For example, if you have msg as the message (or object) you want to send:

    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);
        }
    }
    

    And when receiving, you can also split the reception in chunks, so you can control you buffer (and therefore you memory consumption). After hanlding the whole message, you should wait for another message from the client to do more stuff. Source

    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);
    }
    
    0 讨论(0)
提交回复
热议问题