CXO2
CXO2

Reputation: 648

Receiving Packet using Socket

I am new in the Socket Programming and I just want to ask something.

I was trying to create Simple Receiver and Sender packet between the Client and Server (well I am using same computer), but I having a problem...

The sending function is working properly, but I don't know how to receive the packet that was sent with exactly same size of packet.

For example, I send 5 bytes to the server from the client, I just want to server to receive only 5 bytes too, no more and no less and I want to do this with Socket, also i already include the size of packet with short (int16 2 bytes) format. Here my send packet code:

    public static void Send(Socket socket, byte[] buffer, int timeout)
    {
        int startTickCount = Environment.TickCount;
        int sent = 0;
        int offset = 0;
        int size = buffer.Length;

        // Add size of packet in the begin of data packet with short (int16) format
        List<byte> tmpdata = new List<byte>();
        tmpdata.AddRange(BitConverter.GetBytes((short)(buffer.Length + 2)));
        tmpdata.AddRange(buffer);
        buffer = tmpdata.ToArray();

        do
        {
            if (Environment.TickCount > startTickCount + timeout)
                throw new Exception("Sending packet was timeout.");
            try
            {
                sent += socket.Send(buffer, offset + sent, size - sent, SocketFlags.None);
            }
            catch (SocketException ex)
            {
                if (ex.SocketErrorCode == SocketError.WouldBlock ||
                    ex.SocketErrorCode == SocketError.IOPending ||
                    ex.SocketErrorCode == SocketError.NoBufferSpaceAvailable)
                {
                    Thread.Sleep(30);
                }
                else
                    throw ex;
            }
        } while (sent < size);
    }

Can someone help me?


Thanks Damien for the fix And I was found the solution, but I am afraid this will consume memory usage since it looping each byte, here the code:

    public static byte[] Receive(Socket socket)
    {
        System.Net.Sockets.NetworkStream ns = new NetworkStream(socket);
        int b = (byte)1;
        List<byte> databuf = new List<byte>();

        while ((b = ns.ReadByte()) != -1)
            databuf.Add((byte)b);

        return databuf.ToArray();
    }

There are any better solution without NetworkStream or maybe better performance? Thanks

Upvotes: 0

Views: 2183

Answers (2)

OpenMinded
OpenMinded

Reputation: 486

There are any better solution without NetworkStream or maybe better performance?

NetworkStream acts as a higher level wrapper for Socket, so you could do the same thing using it directly:

var targetStream = new MemoryStream();
var buffer = new byte[receiveBufferSize];
int bytesReceived = 0;

while ((bytesReceived = socket.Receive(buffer)) > 0)
{
    targetStream.Write(buffer, 0, bytesReceived);
}

Also there are SendAsync and ReceiveAsync methods in Socket that work well when you need to perform multiple concurrent operations. But they are more complicated:

var receive = new SocketAsyncEventArgs();
var receiveBuffer = new byte[receiveBufferSize];
receive.SetBuffer(receiveBuffer, 0, receiveBuffer.Length);
receive.Completed += HandleReceived;

if (!socket.ReceiveAsync(receive))
{
    HandleReceived(this, receive);
}

Upvotes: 1

Damien_The_Unbeliever
Damien_The_Unbeliever

Reputation: 239824

You've not shown your receiving code, but one bug can be easily fixed:

    // Add size of packet in the begin of data packet with short (int16) format
    List<byte> tmpdata = new List<byte>();
    tmpdata.AddRange(BitConverter.GetBytes((short)(buffer.Length + 2)));
    tmpdata.AddRange(buffer);
    buffer = tmpdata.ToArray();
    int size = buffer.Length; //Moved from higher up, now that buffer is a different size

At the receiving side, you should have similar code - loop until you've read 2 bytes, use that to create a short that is the total size to receive, subtract 2 (honestly, I'd just avoid adding 2 in the code above and have the size sent as the size ignoring the actual bytes used to encode the size), and then loop again until you've read the whole message.

Upvotes: 3

Related Questions