gpt4 book ai didi

c# - 关于获得我不打算重复的套接字的问题

转载 作者:行者123 更新时间:2023-12-03 12:00:56 25 4
gpt4 key购买 nike

我正在使用 c# 开发一个信使程序,并且遇到了一些问题。

服务器,客户端有三个连接(每个用于聊天,文件传输,纸牌游戏)。

对于第一个和第二个连接,它工作得很好。

但是问题出现在第三个套接字上,与前两个套接字相比,它处理的数据包类型较少。

这不是关于没有收到数据包或没有获得连接,而是正在获取(或发送)
一次超过一个(我打算发送)数据包。服务器日志一直说
一次点击,服务器接收大约 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;
}

}

我真的不知道为什么我会遇到这个问题。
是关于连接点吗?还是关于接收点?还是关于发送点?如果我在连接1,2(在主窗体上。如果我这样做,我应该让“GPACKET”功能也在主窗体上运行)的同一个地方建立这个连接?

最佳答案

这看起来像是经典的“假设我们读取了整个数据包”,这里的“数据包”是指您的逻辑消息,而不是底层传输数据包。例如:

read = gameNetStream.Read(greceiveBuffer, 0, 1024 * 4);
...
Packet.Packet packet = (Packet.Packet)Packet.Packet.Desirialize(greceiveBuffer);

首先,我觉得 read 非常离谱 Desirialize 中不需要,但是:是什么让你认为我们读取了整个数据包?我们可以阅读:
  • 一整包(仅)
  • 一包的一半
  • 一个字节
  • 三包
  • 一个数据包的最后 2 个字节、1 个完整数据包和第三个数据包的前 5 个字节

  • TCP 只是一个流;所有这些 Read保证给你的是“至少 1 个字节,最多 {count} 个字节,或者一个 EOF”。调用 Write 是非常不寻常的。将映射任何类似于对 Read 的调用的内容.您的工作是了解协议(protocol),并决定要缓冲多少数据,然后将该缓冲区的多少视为一个数据包,而不是为下一个数据包保留它们。

    另见: How many ways can you mess up IO? ,特别是“网络数据包:你发送的不是(通常)你得到的”。

    要准确填充 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();

    关于c# - 关于获得我不打算重复的套接字的问题,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/16668491/

    25 4 0
    Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
    广告合作:1813099741@qq.com 6ren.com