gpt4 book ai didi

C#套接字数据报溢出

转载 作者:行者123 更新时间:2023-11-30 17:49:20 25 4
gpt4 key购买 nike

我是 c# 新手 =)

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

为什么程序在套接字缓冲区已满时接收数据?之后的一切不应该失去吗?可能发生数据包碎片?

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

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

关于C#套接字数据报溢出,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/21876089/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com