C# socket datagram overflow

I'm new in c# =)

I have a litle question about udp socket. I have a chat server that receives packets to a specific structure (udp datagram).

Why program receives data when the socket buffer is full? Does all that come after should not be be lost? Maybe packet fragmentation occurs?

Packet structure : udp_headers(28 byte)| dataIdentifier ( 4 byte)|name length(4 byte)|mesage length (4 bytes)|name(name length)|message(message length)

When I send a packet larger than the internal buffer. The program throws an exception:

ReceiveData Error: A message sent on a datagram socket was larger than the internal message buffer or some other network limit, or the buffer used to receive a datagram into was smaller than the datagram itself

All I need is to drop such packets before they cause this error. Is it possible?

Server code:

using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Windows.Forms;

using System.Net.Sockets;
using System.Net;
using System.Collections;

using ChatApplication;

namespace ChatServer
{
    public partial class Server : Form
    {
        #region Private Members

        // Structure to store the client information
        private struct Client
        {
            public EndPoint endPoint;
            public string name;
        }

        // Listing of clients
        private ArrayList clientList;

        // Server socket
        private Socket serverSocket;

        // Data stream
        private byte[] dataStream = new byte[1024];

        // Status delegate
        private delegate void UpdateStatusDelegate(string status);
        private UpdateStatusDelegate updateStatusDelegate = null;

        #endregion

        #region Constructor

        public Server()
        {
            InitializeComponent();
        }

        #endregion

        #region Events

        private void Server_Load(object sender, EventArgs e)
        {
            try
            {
                // Initialise the ArrayList of connected clients
                this.clientList = new ArrayList();

                // Initialise the delegate which updates the status
                this.updateStatusDelegate = new UpdateStatusDelegate(this.UpdateStatus);

                // Initialise the socket
                serverSocket = new Socket(AddressFamily.InterNetwork, SocketType.Dgram, ProtocolType.Udp);

                // Initialise the IPEndPoint for the server and listen on port 30000
                IPEndPoint server = new IPEndPoint(IPAddress.Any, 30000);

                // Associate the socket with this IP address and port
                serverSocket.Bind(server);

                // Initialise the IPEndPoint for the clients
                IPEndPoint clients = new IPEndPoint(IPAddress.Any, 0);

                // Initialise the EndPoint for the clients
                EndPoint epSender = (EndPoint)clients;

                // Start listening for incoming data
                serverSocket.BeginReceiveFrom(this.dataStream, 0, 1024, SocketFlags.None, ref epSender, new AsyncCallback(ReceiveData), epSender);

                lblStatus.Text = "Listening";
            }
            catch (Exception ex)
            {
                lblStatus.Text = "Error";
                MessageBox.Show("Load Error: " + ex.Message, "UDP Server", MessageBoxButtons.OK, MessageBoxIcon.Error);
            }
        }

        private void btnExit_Click(object sender, EventArgs e)
        {
            Close();
        }

        #endregion

        #region Send And Receive

        public void SendData(IAsyncResult asyncResult)
        {
            try
            {
                serverSocket.EndSend(asyncResult);
            }
            catch (Exception ex)
            {
                MessageBox.Show("SendData Error: " + ex.Message, "UDP Server", MessageBoxButtons.OK, MessageBoxIcon.Error);
            }
        }

        private void ReceiveData(IAsyncResult asyncResult)
        {
            try
            {
                byte[] data;

                // Initialise a packet object to store the received data
                Packet receivedData = new Packet(this.dataStream);

                // Initialise a packet object to store the data to be sent
                Packet sendData = new Packet();

                // Initialise the IPEndPoint for the clients
                IPEndPoint clients = new IPEndPoint(IPAddress.Any, 0);

                // Initialise the EndPoint for the clients
                EndPoint epSender = (EndPoint)clients;

                // Receive all data
                serverSocket.EndReceiveFrom(asyncResult, ref epSender);

                // Start populating the packet to be sent
                sendData.ChatDataIdentifier = receivedData.ChatDataIdentifier;
                sendData.ChatName = receivedData.ChatName;

                switch (receivedData.ChatDataIdentifier)
                {
                    case DataIdentifier.Message:
                        sendData.ChatMessage = string.Format("{0}: {1}", receivedData.ChatName, receivedData.ChatMessage);
                        break;

                    case DataIdentifier.LogIn:
                        // Populate client object
                        Client client = new Client();
                        client.endPoint = epSender;
                        client.name = receivedData.ChatName;

                        // Add client to list
                        this.clientList.Add(client);

                        sendData.ChatMessage = string.Format("-- {0} is online --", receivedData.ChatName);
                        break;

                    case DataIdentifier.LogOut:
                        // Remove current client from list
                        foreach (Client c in this.clientList)
                        {
                            if (c.endPoint.Equals(epSender))
                            {
                                this.clientList.Remove(c);
                                break;
                            }
                        }

                        sendData.ChatMessage = string.Format("-- {0} has gone offline --", receivedData.ChatName);
                        break;
                }

                // Get packet as byte array
                data = sendData.GetDataStream();

                foreach (Client client in this.clientList)
                {
                    if (client.endPoint != epSender || sendData.ChatDataIdentifier != DataIdentifier.LogIn)
                    {
                        // Broadcast to all logged on users
                        serverSocket.BeginSendTo(data, 0, data.Length, SocketFlags.None, client.endPoint, new AsyncCallback(this.SendData), client.endPoint);
                    }
                }

                // Listen for more connections again...
                serverSocket.BeginReceiveFrom(this.dataStream, 0, 1024, SocketFlags.None, ref epSender, new AsyncCallback(this.ReceiveData), epSender);

                // Update status through a delegate
                this.Invoke(this.updateStatusDelegate, new object[] { sendData.ChatMessage });
            }
            catch (Exception ex)
            {
                MessageBox.Show("ReceiveData Error: " + ex.Message, "UDP Server", MessageBoxButtons.OK, MessageBoxIcon.Error);
            }
        }

        #endregion

        #region Other Methods

        private void UpdateStatus(string status)
        {
            rtxtStatus.Text += status + Environment.NewLine;
        }

        #endregion
    }
}

This is udp sender and reciver in one . Use /s if you want listen

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Net;
using System.Net.Sockets;
using System.Threading;

namespace UDPTestClient
{
    class Program
    {
        static void RecvCompleted(object sender, SocketAsyncEventArgs e)
        {
            string Data = Encoding.ASCII.GetString(e.Buffer, e.Offset, e.BytesTransferred);
            e.Dispose();
            ReceiveUdp((Socket)e.UserToken);
            Console.WriteLine(Data);
        }

        static void SendCompleted(object sender, SocketAsyncEventArgs e)
        {
            int i = e.Count;
            e.Dispose();
            Console.WriteLine("{0} bytes send", i);
        }

        static void ReceiveUdp(Socket s)
        {
            SocketAsyncEventArgs e = new SocketAsyncEventArgs();
            //set buffer to 100 .Now it's work fine.
            e.SetBuffer(new byte[100], 0, 100);
            e.RemoteEndPoint = new IPEndPoint(IPAddress.Any, 0);
            e.UserToken = s;
            e.Completed += new EventHandler<SocketAsyncEventArgs>(RecvCompleted);
            s.ReceiveFromAsync(e);
        }

        static void SendUdp(Socket s, string Data)
        {
            SocketAsyncEventArgs e = new SocketAsyncEventArgs();
            byte[] buf = Encoding.ASCII.GetBytes(Data);
            e.SetBuffer(buf, 0, buf.Length);
            e.RemoteEndPoint = new IPEndPoint(IPAddress.Parse("127.0.0.1"), 3333);
            e.UserToken = s;
            e.Completed += new EventHandler<SocketAsyncEventArgs>(SendCompleted);
            s.SendToAsync(e);
        }

        static void Main(string[] args)
        {
            Socket s = new Socket(AddressFamily.InterNetwork, SocketType.Dgram, ProtocolType.Udp);
            if (args.Length != 0 && args[0] == "/s")
            {
                IPEndPoint ip = new IPEndPoint(IPAddress.Any, 3333);
                s.Bind(ip);
                ReceiveUdp(s);
            }
            else
            {
                SendUdp(s, "Hello!");
            }
            Console.ReadKey();
            s.Close();
        }
    }
}

UDP is a dumb protocol, as in, it does not actually have any knowledge of size or how to work with this. If you want to handle this before an exception occurs, you need to create a different structure for your communication. I would recommend that you do one of the following:

  • Use a polling mechanism, where the client requests a single update from the server, with a given size, then ensure that the buffer is large enough for this message.
  • Simply increase your buffer to the correct size.
  • Catch the exception and simply discard it, when the buffer overflows, then attempt to reestablish.
  • Use RecieveAsync to only get parts of the datagram at a time. See http://msdn.microsoft.com/en-us/library/dxkwh6zw(v=vs.110).aspx
  • 链接地址: http://www.djcxy.com/p/61904.html

    上一篇: 通过udp套接字的多个变量

    下一篇: C#套接字数据报溢出