我正在使用c#编写一个messenger程序,并且有一些问题。
服务器,客户端有三个连接(每个连接用于聊天,文件传输,卡片游戏)。
对于第一个和第二个连接,它工作得很好。
但问题出现在第三个问题上,与前两个套接字相比,它处理的数据包类型更少。
这不是关于没有收到数据包或没有获得连接,但它正在获取(或发送) 一次一个(我打算发送)数据包。服务器日志继续这样说 只需单击一下,服务器就会收到大约3~20个相同的数据包并将它们发送到目标客户端。
在我对第三个连接的部分代码之前,我将解释这个东西是如何起作用的。
connection1,2和connection3(发生此问题)之间的区别只是时间 当我建立连接。 1,2使它在主窗体的form_load函数上连接,并且工作正常。
当我加载游戏表单(不是主表单)时,连接3建立连接。还有,第一个 两个套接字的监听线程在主窗体上,第三个有它的监听线程 自己的形式。这是我能找到的唯一区别。连接和监听线程是 同样的。这是我的游戏表格代码。
public void GPACKET() //A Thread function for receiving packets from the server
{
int read = 0;
while (isGameTcpClientOnline)
{
try
{
read = 0;
read = gameNetStream.Read(greceiveBuffer, 0, 1024 * 4);
if (read == 0)
{
isGameTcpClientOnline = false;
break;
}
}
catch
{
isGameTcpClientOnline = false;
gameNetStream = null;
}
Packet.Packet packet = (Packet.Packet)Packet.Packet.Desirialize(greceiveBuffer);
switch ((int)packet.Type)
{
case (int)PacketType.gameInit:
{
gameinit = (GameInit)Packet.Packet.Desirialize(greceiveBuffer);
//codes for handling the datas from the packet...
break;
}
case (int)PacketType.gamepacket:
{
gp = (GamePacket)Packet.Packet.Desirialize(greceiveBuffer);
//codes for handling the datas from the packet...
break;
}
}
}
}
public void setPacket(bool turn) //makes the packet, and sends it to the server..
{
if (turn)
turnSetting(false);
else
turnSetting(true);
gps = new GamePacket();
gps.Type = (int)PacketType.gamepacket;
gps.isFirstPacket = false;
gps.sym = symbol;
gps.ccapacity = cardCapacity;
gps.currentList = current_list[0].Tag.ToString();
gps.isturn = turn;
gps.opname = opid;
List<string> tempList = new List<string>();
foreach (PictureBox pb in my_list)
{
tempList.Add(pb.Image.Tag.ToString());
}
gps.img_list = tempList;
Packet.Packet.Serialize(gps).CopyTo(this.gsendBuffer, 0);
this.Send();
label5.Text = symbol + ", " + current_list[0].Tag.ToString();
}
public void Send() //actually this part sends the Packet through the netstream.
{
gameNetStream.Write(this.gsendBuffer, 0, this.gsendBuffer.Length);
gameNetStream.Flush();
for (int j = 0; j < 1024 * 4; j++)
{
this.gsendBuffer[j] = 0;
}
}
我真的不知道为什么我遇到这个问题。 是关于连接点吗?还是关于接收点?或者它是关于发送点?如果我在connection1,2的同一个地方建立这个连接(在主窗体上。如果我这样做,我应该在主窗体上运行“GPACKET”功能)?
答案 0 :(得分:2)
这看起来像经典的“假设我们读取整个数据包”,其中“数据包”在这里我的意思是你的逻辑消息,而不是底层传输数据包。例如:
read = gameNetStream.Read(greceiveBuffer, 0, 1024 * 4);
...
Packet.Packet packet = (Packet.Packet)Packet.Packet.Desirialize(greceiveBuffer);
首先,我非常关注read
中不需要Desirialize
,但是:是什么让你认为我们读了整个数据包?我们原来可以读到:
TCP只是一个流;所有Read
保证给你的是“至少1个字节,最多{count}个字节,或者EOF”。调用Write
会映射到Read
的调用之类的内容非常不寻常。您的工作是了解协议,并决定要缓冲多少数据,然后将该缓冲区中的多少作为一个数据包处理,然后将其保留回下一个数据包。
另请参阅:How many ways can you mess up IO?,在partuclar“网络数据包:你发送的内容不是(通常)你得到的内容。”
准确填充4096字节缓冲区:
int expected = 4096, offset = 0, read;
while(expected != 0 &&
(read = gameNetStream.Read(greceiveBuffer, offset, expected)) > 0)
{
offset += read;
expected -= read;
}
if(expected != 0) throw new EndOfStreamException();