【发布时间】:2011-01-12 19:55:55
【问题描述】:
我正在构建一个简单的 tcp/ip 聊天程序,但我很难单独发送消息。例如,如果我发送两条消息并且两者的内容都大于可以容纳 20 个字符的缓冲区,则发送第一条消息的 20 个字符,然后发送下一条消息的 20 个字符,然后发送第一条消息的其余部分,然后最后一条消息的其余部分。因此,当我解析和连接字符串时,我得到两条消息,分别是第一条消息的开头和第二条消息的开头以及第一条消息的结尾和第二条消息的结尾。我想知道如何发送消息,并将下一条消息排队,直到第一条消息已经发送。作为旁注,我使用的是异步方法调用而不是线程。
我的代码:
客户:
protected virtual void Write(string mymessage)
{
var buffer = Encoding.ASCII.GetBytes(mymessage);
MySocket.BeginSend(buffer, 0, buffer.Length,
SocketFlags.None,EndSendCallBack, null);
if (OnWrite != null)
{
var target = (Control) OnWrite.Target;
if (target != null && target.InvokeRequired)
{
target.Invoke(OnWrite, this, new EventArgs());
}
else
{
OnWrite(this, new EventArgs());
}
}
}
还有两个混在一起的电话:
client.SendMessage("CONNECT",Parser<Connect>.TextSerialize(connect));
client.SendMessage("BUDDYLIST","");
最后是读取函数(我在每条消息的开头使用一个数字来知道消息何时结束,用括号括起来):
private void Read(IAsyncResult ar)
{
string content;
var buffer = ((byte[]) ar.AsyncState);
int len = MySocket.EndReceive(ar);
if (len > 0)
{
string cleanMessage;
content = Encoding.ASCII.GetString(buffer, 0, len);
if (MessageLength == 0)
{
MessageLength = int.Parse(content.Substring(1, content.IndexOf("]", 1) - 1));
cleanMessage = content.Replace(content.Substring(0, content.IndexOf("]", 0) + 1), "");
}
else
cleanMessage = content;
if(cleanMessage.Length <1)
{
if(MySocket.Connected)
MySocket.BeginReceive(buffer, 0, buffer.Length, SocketFlags.None, new AsyncCallback(Read), buffer);
return;
}
MessageLength = MessageLength > cleanMessage.Length? MessageLength - cleanMessage.Length : 0;
amessage += cleanMessage;
if(MessageLength == 0)
{
if (OnRead != null)
{
var e = new CommandEventArgs(this, amessage);
Control target = null;
if (OnRead.Target is Control)
target = (Control)OnRead.Target;
if (target != null && target.InvokeRequired)
target.Invoke(OnRead, this, e);
else
OnRead(this, e);
}
amessage = String.Empty;
}
MySocket.BeginReceive(buffer, 0, buffer.Length, SocketFlags.None, new AsyncCallback(Read), buffer);
return;
}
}
【问题讨论】:
-
TCP 不适用于消息的概念。它提供了一个流,仅此而已。您需要在此基础上编写一种机制来将流拆分为消息。
-
我在字符串开头的括号中有一个数字,用于知道消息何时结束,即[3]嘿。问题是我会得到 [3]h 然后是 [3]y nad 然后是 'ow' 然后是 'you' 如果我发送了 '[3]how' 和 '[3]' 你。仅当缓冲区为 4 时。
-
所以你发送“[3]how[3]you”并接收“[3]h[3]yowyou”?对我来说听起来难以置信。但我通常用单线程编写我的网络代码。我怀疑您的线程代码编写不正确。
-
但是 TCP 允许在流中的任何字节之间插入数据包边界,它也可以连接多条消息。对 Send 和 Receive 的调用之间没有 1to1 映射。除非您以不正确的方式使用线程,否则顺序是保留的。
-
这种情况总是发生在 TCP/IP 上,不可能知道她的感受。