关于重复套接字的问题,我不打算

时间:2013-05-21 11:06:53

标签: c# asp.net sockets

我正在使用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”功能)?

1 个答案:

答案 0 :(得分:2)

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

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的调用之类的内容非常不寻常。您的工作是了解协议,并决定要缓冲多少数据,然后将该缓冲区中的多少作为一个数据包处理,然后将其保留回下一个数据包。

另请参阅: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();