【问题标题】:TCP Socket fast packet sendingTCP Socket 快速数据包发送
【发布时间】:2014-05-05 21:22:41
【问题描述】:

我有一类已登录的客户端:

public class LoggedIn_Class
{
    public Socket socket;
    public string name;
}

我有一个清单:

public static List<Object> LoggedIn_List = new List<Object>();

当有人登录我的服务器时,我将其添加到列表中:

LoggedIn_Class newClient = new LoggedIn_Class();

newClient.socket = currentSocket;
newClient.name = currentName;

LoggedIn_List.Add(newClient);

现在我正在尝试向每个客户端发送一个数据包:

foreach (LoggedIn_Class s in variables.LoggedIn_List.ToArray())
{
   s.socket.Send(Packet);
}

现在的问题是 foreach 处理项目太快而无法发送。这可以正常工作,但我认为这不是最好的解决方案...

foreach (LoggedIn_Class s in variables.LoggedIn_List.ToArray())
{
   s.socket.Send(Packet);
   Thread.Sleep(50);
}

有人对此有任何想法吗?我该怎么做才能等待发送结束?

【问题讨论】:

  • 你用的是什么类型的socket?什么协议?有例外吗?它是如何“不起作用”的?
  • Socket.Send 是一种同步操作——即它仅在您的数据发送后返回。您似乎将它与异步混淆(通过您描述它并查看您的方法)。这里还有其他问题。您是否有任何异常或有什么问题?
  • 我正在使用 TCP 套接字。客户端只是没有收到数据包,它没有任何异常。

标签: c# sockets tcp


【解决方案1】:

我正在使用 TCP 套接字。客户端只是没有收到数据包,它没有任何异常。

关于这个有很多答案。您真正的问题是您不了解基于流的协议的含义。使用 TCP,您不发送消息,而是发送字节流。

因此,接收方不能假定在一个socket.Receive 中接收到的所有内容与另一方使用socket.Send 发送的字节完全相同。

因此,您应该使用某种机制来检测何时收到完整的消息。通常,您可以为每条消息添加一个长度前缀,或者在每条消息后使用分隔符。

当您使用Thread.Sleep 时它起作用的原因是消息足够短,可以一次发送一个,并且您设法在发送下一条消息之前接收它们。没有延迟,nagle algorithm 可能会发挥作用并合并您的消息。

一个简单的实现:

public void Send(byte[] msg)
{
    var header = BitConverter.GetBytes(msg.Length);
    socket.Send(header, 0, header.Length);
    socket.Send(msg, 0, msg.Length);
}

接收方(可能有问题,但应该给你一个提示):

var buffer = new byte[4];
int bytesReceived = socket.Receive(buffer, 0, 4, ....);
if (bytesReceived < 4)
{
     bytesReceived = socket.Receive(buffer, bytesReceived, 4 - bytesReceived, ....);
     //this can fail too, probably should use a loop like below until
     //all four length bytes have been received.
}

var bytesToRead = BitConverter.GetInt32(buffer, 0);
var buffer = new byte[bytesToRead];
var offset = 0;

while (bytesToRead  > 0)
{
   var len = Math.Min(bytesToRead, buffer.Length);
   var read = socket.Receive(buffer, offset, len, .....);
   bytesToRead -= read;
   offset += read;
}

//now you got everything.

【讨论】:

  • 感谢您的出色回答,但您现在有什么建议?我应该切换到UDP?我正在将类转换为字节数组,并尝试将其发送给每个客户端。我的类通常包含字符串、整数和布尔值。
  • 使用 WCF 或在字节数组前加上一个 int。 UDP 不可靠,也不按顺序发送消息。因此,如果您必须以正确的顺序接收每条发送的消息,则 UDP 使用起来会更加复杂。
  • 在字节数组前面加上一个 int 是什么意思?我的数据包的第一个字节始终是标头,在客户端我有一个标头开关。或者你不是这个意思?对不起我的英语不好,但我真的不明白。
  • 更新了一个小例子
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2022-06-14
  • 2019-02-10
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多