C# 套接字数据报溢出 [英] C# socket datagram overflow

查看:42
本文介绍了C# 套接字数据报溢出的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我是 C# 新手 =)

I'm new in c# =)

我有一个关于 udp 套接字的小问题.我有一个聊天服务器,它接收特定结构的数据包(udp 数据报).

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

为什么程序会在socket缓冲区满时接收数据?之后的一切难道不应该丢失吗?可能会出现数据包碎片?

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

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

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 错误:在数据报套接字上发送的消息大于内部消息缓冲区或某些其他网络限制,或者用于接收数据报的缓冲区小于数据报本身

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?

服务器代码:

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

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 是一个愚蠢的协议,因为它实际上不知道大小或如何使用它.如果你想在异常发生之前处理这个,你需要为你的通信创建一个不同的结构.我建议您执行以下操作之一:

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:

  1. 使用轮询机制,客户端从服务器请求单个更新,具有给定的大小,然后确保缓冲区足够大以容纳此消息.
  2. 只需将缓冲区增加到正确的大小即可.
  3. 捕获异常并简单地丢弃它,当缓冲区溢出时,然后尝试重新建立.
  4. 使用 RecieveAsync 一次只能获取部分数据报.看http://msdn.microsoft.com/en-us/library/dxkwh6zw(v=vs.110).aspx

这篇关于C# 套接字数据报溢出的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆