简体   繁体   中英

Client server socket C#

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.

Here is the client application code. What should I do so that it would receive all data sent by the server?

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

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"

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

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM