我有一个客户端会从不同的线程向服务器发送大量数据。
数据包使用以下格式: PACKET_ID 内容 END_OF_PACKET_INDICATOR
我有以下onDataRecieved函数:
public void OnDataReceived(IAsyncResult asyn)
{
SocketPacket socketData = (SocketPacket)asyn.AsyncState;
int iRx = 0;
iRx = socketData.m_currentSocket.EndReceive(asyn);
char[] chars = new char[iRx + 1];
System.Text.Decoder d = System.Text.Encoding.UTF8.GetDecoder();
int charLen = d.GetChars(socketData.dataBuffer, 0, iRx, chars, 0);
MessageBox.Show("Incoming data: " + socketData.dataBuffer.Length.ToString() + " from socket(" + socketData.socket_id + ")");
char[] PACKET_END_IDENTIFIER = { (char)2, (char)1, (char)2, (char)1 };
for (int i = 0; i < iRx; i++)
{
GLOBAL_BUFFER.Add(chars[iRx]);
}
if (PacketEndReached(chars, PACKET_END_IDENTIFIER))
{
// done reading the data
PROCESS_PACKET(GLOBAL_BUFFER);
}
WaitForData(socketData.m_currentSocket, socketData.socket_id);
}
我的套接字缓冲区大小设置为100.如果我发送1000个字节,它们将被拆分为10个块,而onDataRecieved将被触发10次。
我需要做的就是继续将数据读入我的客户端发送的每个数据包的缓冲区,直到PacketEndReached被触发 然后将缓冲区传递给另一个处理数据的函数。
如果我定义GLOBAL_BUFFER来存储传入数据,那么如果客户端从多个线程发送数据,那么数据是否会混淆?我需要一种方法来读取我的客户发送的每个数据包的所有数据。
谢谢!
更新:
这是我目前的课程:
public partial class TCP_SERVER
{
const int MAX_CLIENTS = 3000;
const int MAX_SOCKET_BUFFER_SIZE = 10;
public AsyncCallback pfnWorkerCallBack;
private Socket m_mainSocket;
private Socket[] m_workerSocket = new Socket[MAX_CLIENTS];
private int m_clientCount = 0;
public GLOBAL_BUFFER;
public void StartServer(int listen_port)
public void OnClientConnect(IAsyncResult asyn)
public void ProcessIncomingData(char[] INCOMING_DATA, int CLIENT_ID)
public void OnDataReceived(IAsyncResult asyn)
}
正如您所见,GLOBAL_BUFFER是“全局”定义的。如果客户端发送需要10秒钟发送的packet_1,同时发送数据需要2秒的packet_2会混淆。我需要收集每个数据包的数据。
答案 0 :(得分:0)
只需使用Dictionary<String,List<Char>>
替换当前的GLOBAL_BUFFER
,
将不同的PACKET_ID数据存储到不同的List中。
我强烈建议您使用完美的Socket框架SuperSocket,不需要编写任何套接字代码,它将显着提高您的开发效率。
答案 1 :(得分:0)
如果可能的话,我建议允许每个客户端线程拥有自己的服务器连接。这样做有助于Winsock堆栈区分来自每个线程的消息,并避免消息之间的数据包流失。这将有效地使您从堆栈能够解密哪些消息(和消息部分)打算组合在一起,然后将它们作为完整的消息传递给您的应用程序。
如果将线程分离到不同的连接(或者保证一次只从客户端发送一条消息),那么非常原始的消息设计只能工作(可靠)。您在通信中使用非常原始的消息成帧技术,这将有助于您确定消息边界,但失败的原因是因为socketData.m_currentSocket.EndReceive(asyn);
只会告诉您接收的字节数引发事件时(不一定是消息中的总字节数)。我建议不要依赖它来告诉你已读取了多少字节,而是建议从异步处理程序中的循环中逐步读取传入消息,读取非常小的消息段,直到它发现消息字节序列结束。这样做会告诉您的事件何时退出阅读并将数据传递给其他人来处理它。
我通常采用消息框架的方式是在消息引人注目之前有一个(某些值在消息传递中很少见到),然后是消息的长度(编码为品味,我个人使用二进制编码以提高效率),消息内容,最后是消息末尾的第二个引人注目的消息。引人注目的用作协议中消息中断的逻辑队列,消息长度明确告诉服务器要等待多少字节。这样做,你可以保证收到必要的字节数(如果你不这样做就丢弃和/或抛出异常)它会在你可以编码的消息之间提供一个非常明确的边界,这允许间歇性现场检查和验证。