March3
March3

Reputation: 93

problems about getting repeated sockets which i do not intend

I'm working on a messenger program using c#, and have some issues.

The server, client has three connections(each for chatting, filetrans, cardgames).

For the first, and second connection, it's working just fine.

But the problem occurred on the third one, which handles less amount of packet types compared to the first two sockets.

It's not about not receiving the packet or not getting a connection, but it's getting(or sending) more then one(which I intend to send) packets at a time. The server log keeps on saying that on one click, the server receives about 3~20 same packets and sends them to the targeted client.

Before my partial codes for the third connection, I'll explain how this thing is suppose to work.

The difference between connection1,2 and connection3(which is making this issue) is only the time when I make the connection. The 1,2 makes it's connection on the main form's form_load function, and works fine.

The connection 3 makes connection when I load the gaming form(not the main form). Also, the first two socket's listening thread are on the main form, and the third has it's listening thread on it's own form. That's the only difference that I can find. The connections, and listening threads are the very same. Here are my codes for the gaming form.

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;
    }

}

I really don't know why I'm having this problem. Is it about the connection point? or is it about the receiving point? Or is it about the sending point? If I establish this connection on the same place to the connection1,2(which is on the main form. If i do this, I should make the "GPACKET" function running on the main form as well)?

Upvotes: 1

Views: 105

Answers (1)

Marc Gravell
Marc Gravell

Reputation: 1062780

This looks like a classic "assume we read an entire packet", where by "packet" here I mean your logical message, not the underlying transport packet. For example:

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

Firstly, it strikes me as very off that read wouldn't be needed in Desirialize, but: what makes you think we read an entire packet? we could have read:

  • one entire packet (only)
  • half of one packet
  • one byte
  • three packets
  • the last 2 bytes of one packet, 1 entire packet, and the first 5 bytes of a third packet

TCP is just a stream; all that Read is guaranteed to give you is "at least 1 byte and at most {count} bytes, or an EOF". It is very unusual that calls to Write would map anything like the calls to Read. It is your job to understand the protocol, and decide how much data to buffer, and then how much of that buffer to treat as one packet vs holding them back for the next packet(s).

See also: How many ways can you mess up IO?, in partuclar "Network packets: what you send is not (usually) what you get".


To fill exactly a 4096 byte buffer:

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();

Upvotes: 2

Related Questions