【发布时间】:2015-04-10 20:01:21
【问题描述】:
我需要在 C# 中实现一个 Socket 客户端。
socket服务器是一个软件,通过3000端口与我的C#客户端连接。
每条消息的组成如下:
- 某些字段:4 个字节
- 消息长度:2 个字节
- 某些字段:4 个字节
- 消息索引:2 个字节
- 一些字段:取决于“消息长度”字段
客户端接收时,缓冲区可以包含多个单条消息和重复消息。
我必须在消息中拆分缓冲区的内容,如果该消息尚未出现在此列表中,则将消息保存在列表中。
如果消息的索引在列表中,我了解该消息已经存在于列表中。
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Forms;
using System.Net;
using System.Net.Sockets;
namespace Client
{
public partial class Form1 : Form
{
public Form1()
{
InitializeComponent();
}
Socket sck = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
IPEndPoint endPoint = new IPEndPoint(IPAddress.Parse("127.0.0.1"), 3000);
private void btnC_Click(object sender, EventArgs e)
{
sck.Connect(endPoint);
if (sck.Connected)
{
Form1.ActiveForm.Text = Form1.ActiveForm.Text + " - Connected";
}
byte[] buffer = new byte[255];
int rec;
while (true)
{
buffer = new byte[255];
rec = sck.Receive(buffer, 0, buffer.Length, 0);
Array.Resize(ref buffer, rec);
/* Understand and Manage the messages */
}
}
}
}
您对实施正确的代码以理解和管理收到的消息有什么建议吗??
提前致谢!
法比奥
【问题讨论】:
-
为了简单起见,我首先使用
TcpClient而不是原始套接字。然后从流中读取——读取你知道的数据量,解释它,然后读取其余的。BinaryReader对此非常有帮助。 -
您需要查看消息框架。
-
在这种情况下使用 Tcp 会产生比您预期的要复杂得多的代码。例如,您也可能只收到消息的一部分。甚至只有一个字节是可能的,因此您甚至不知道消息长度,而只是接收它的第一部分。这是因为 TCP 是一种流协议。如果可能,请在您的情况下使用 UDP。使用 UDP,您将收到单个消息。这种设计要简单得多。用于客户端和服务器。
-
我通常使用state machine 完成此类处理。要从一种状态前进到下一种状态,您需要验证缓冲区是否包含至少一条完整的信息,例如一个完整的 12 字节消息头。您不断在缓冲区中累积数据并尝试根据当前状态和缓冲区内容转换到新状态。请注意,由于接收数据,可能会发生几种状态转换,例如您可能收到了 3 7/8 条新消息。
-
实际上你的代码在这一点上是毫无用处的。使用 TCP 套接字,事物是面向连接的。您将有一个侦听套接字,在其中调用 accept 将产生一个服务套接字,您可以在该套接字上开始接收数据。您将需要启动一个单独的线程来处理该套接字,并且仍然准备好接受列表套接字上的新连接。正如我所说,TCP 比 UDP 更复杂。 UDP 不是面向连接的,因此您的代码更加一致。因为你会有一个简单的recfrom,就是这样。