C#套接字数据报溢出

我是新来的c#=)

我有一个关于udp socket的问题。 我有一个聊天服务器,接收数据包到特定的结构(udp数据报)。

为什么程序在套接字缓冲区已满时接收数据? 所有后来的事情都不应该丢失吗? 也许数据包碎片发生?

数据包结构:udp_headers(28字节)| dataIdentifier(4字节)|名称长度(4字节)|消息长度(4字节)|名称(名称长度)|消息(消息长度)

当我发送比内部缓冲区大的数据包时。 该程序引发异常:

ReceiveData错误:在数据报套接字上发送的消息大于内部消息缓冲区或其他网络限制,或者用于接收数据报的缓冲区小于数据报本身

我需要的只是在导致此错误之前丢弃这些数据包。 可能吗?

服务器代码:

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

这是udp发件人和收件人之一。 使用/ s,如果你想听

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是一个哑巴协议,因为它实际上没有任何大小的知识或如何处理这个问题。 如果您想在发生异常之前处理此问题,则需要为您的通信创建不同的结构。 我会建议您执行以下操作之一:

  • 使用轮询机制(客户机从服务器请求一个给定大小的单个更新),然后确保缓冲区足够大,可用于此消息。
  • 只需将您的缓冲区增加到正确的大小。
  • 捕捉异常并简单地放弃它,当缓冲区溢出时,然后尝试重新建立。
  • 使用RecieveAsync一次只能获取部分数据报。 请参阅http://msdn.microsoft.com/en-us/library/dxkwh6zw(v=vs.110).aspx
  • 链接地址: http://www.djcxy.com/p/61903.html

    上一篇: C# socket datagram overflow

    下一篇: Socket Programming in C and Unserialize the Response