Page 1 of 1

Recv_() and send_() questions.

Posted: Fri Oct 23, 2020 4:32 am
by Ty1003
So I have an application that uses networking, E.G., initNetwork(), NetworkServerEvent() etc etc. However, I am having issues with Packet mixing. E.G., if two packets are sent at the same time, the text get scrambled together. I tried to solve it with a delay but this makes it lag, for quite obvious reasons. I heard about recv_() and send_(), and tried to add them, but from the looks of it, I would have to rewrite my entire client/server to use these. Is this really the best rout? Is there another way on Windows to make packet mixing not happen?
Thanks

Re: Recv_() and send_() questions.

Posted: Fri Oct 23, 2020 10:14 am
by cas
If i understand correctly, you are sending in multiple threads at the same time and you are using global buffer? To solve this, you must allocate local buffer for each thread or use mutex.

Re: Recv_() and send_() questions.

Posted: Fri Oct 23, 2020 11:23 am
by leonhardt
maby mk-soft's network lib is the good choice for you.
viewtopic.php?f=12&t=73882
compiler option: thread safe

Re: Recv_() and send_() questions.

Posted: Fri Oct 23, 2020 2:16 pm
by Ty1003
Okay,
Firstly, no, the issue is if more than one packet is sent at aaround the same time, the text from them gets mashed.
And second, I'll take a look at that lib.
Thanks all for the suggestions!

Re: Recv_() and send_() questions.

Posted: Fri Oct 23, 2020 5:40 pm
by Bitblazer
Did you use an UDP connection or a TCP connection?

Re: Recv_() and send_() questions.

Posted: Fri Oct 23, 2020 8:22 pm
by Ty1003
I think it's just TCP, I just used InitNetwork() and OpenNetworkConnection().

Re: Recv_() and send_() questions.

Posted: Fri Oct 23, 2020 10:31 pm
by infratec
This is a coding question.

So write a small (working) version of your code and show it in this section.
Something with your receive code is wrong.

Every packet come on its own and since the client is known, it can not mixed up.
(If it is handled correct). API functions changes nothing on the receive logic.

Re: Recv_() and send_() questions.

Posted: Sat Oct 24, 2020 11:32 am
by Bitblazer
Ty1003 wrote:I think it's just TCP, I just used InitNetwork() and OpenNetworkConnection().
If you used OpenNetworkConnection, the default connection mode will be TCP. The order with TCP will be maintained, so the problem is in your code. Show your implementation, so we can help :)

Re: Recv_() and send_() questions.

Posted: Sat Oct 24, 2020 2:11 pm
by cas
Ty1003 wrote:Okay,
Firstly, no, the issue is if more than one packet is sent at aaround the same time, the text from them gets mashed.
And second, I'll take a look at that lib.
Thanks all for the suggestions!
Please, at least, since you are not providing example code that shows your problem, provide an example of "mashed" data.
For example, if you send 2 packets
packet1: "abcd"
packet2: "1234"

and you receive "abcd1234" in a single read but you want to receive each of them separately then you must add a header to each network packet that indicates its size if packets do not have fixed size. If all packets are fixed size then you can specify number of bytes to read when you receive them.

Re: Recv_() and send_() questions.

Posted: Sat Oct 24, 2020 2:35 pm
by Ty1003
Alright, here are the networking parts of my code. I took out the gadget and sound playing bits, as I don't think they would effect it at all.

Server

Code: Select all

Global NewMap Users.S()
#MSG_WAITALL=$8
Declare Main()
Procedure Main()
  OpenConsole("Talk Server.")
  InitNetwork()
  Protected Port=6832
  Delay(50)
  If CreateNetworkServer(0,Port)
    PrintN("Server created (Port "+Str(Port)+").")
    If ReadFile(0,"MOTD.txt")
      Protected MOTD.S=ReadString(0)
    EndIf
    Repeat
      Protected SEvent=NetworkServerEvent()
      If SEvent
        Protected ClientID=EventClient()
        Select SEvent
          Case #PB_NetworkEvent_Connect
            ID=ClientID
            PrintN(""+ID+" has connected !")
          Case #PB_NetworkEvent_Data
            *Buffer=AllocateMemory(1000)
            recv_(ClientID,*Buffer,1000,#MSG_WAITALL)
            ID=ClientID
            Protected PeekedMem.S=""
            PeekedMem=PeekS(*Buffer,-1,#PB_UTF8)
            Debug PeekedMem
            If Left(PeekedMem,1)="@"
              Protected Name.S=Mid(PeekedMem,2)
              Users(Str(ID))=Name
              Protected MOTDString.S="@MOTD "+MOTD
              send_(Val(MapKey(Users())),@MOTDString,StringByteLength(MOTDString),#Null)
              recv_(ID,*Buffer,1000,#MSG_WAITALL)
              Protected NameString.S=Name+" has connected"
              ForEach Users()
                send_(Val(MapKey(Users())),@NameString,StringByteLength(NameString),#Null)
              Next
            Else
              If FindMapElement(Users(),Str(ID))
                Protected Chat.S=Users()+": "+PeekedMem
                PrintN(Chat)
                ForEach Users()
                  send_(Val(MapKey(Users())),@Chat,StringByteLength(Chat),#Null)
                Next
              EndIf
            EndIf
            FreeMemory(*Buffer)
          Case #PB_NetworkEvent_Disconnect
            ID=ClientID
            PrintN(""+ID+" has disconnected !")
        EndSelect
      EndIf
    ForEver
    CloseNetworkServer(0)
  Else
    PrintN("Can't create the server (port in use ?).")
  EndIf
EndProcedure
Main()
And client

Code: Select all

InitNetwork()
Protected Port=6832
Protected Name.S=InputRequester("Name","Please enter your name.","")
If Name=""
  End
EndIf
Protected ConnectionID=OpenNetworkConnection("127.0.0.1",Port)
If ConnectionID
  send_(ConnectionID,@Name,StringByteLength(Name),#Null)
  Protected TempName.S="@"+Name
  send_(ConnectionID, @TempName,StringByteLength(TempName),#Null)
  Repeat
    Protected SEvent=NetworkClientEvent(ConnectionID)
    Select SEvent
      Case #PB_NetworkEvent_Disconnect
        ConnectionID=0
        PlaySound(Disconnect)
        Break
      Case #PB_NetworkEvent_Data
        If ConnectionID=0
          Break
        EndIf
        Protected *Buffer=AllocateMemory(1000)
        recv_(ConnectionID,*Buffer,1000,#MSG_WAITALL)
        Protected Message.S=PeekS(*Buffer,-1,#PB_UTF8)
        If FindString(Message,": ")=0
          If FindString(Message,"has connected")<>0
            PlaySound(Online)
          ElseIf Left(Message,5)="@MOTD"
            Message=Mid(Message,6)
          EndIf
        Else
          PlaySound(Chat)
        EndIf
        AddGadgetItem(#History_List,-1,Message)
        FreeMemory(*Buffer)
    EndSelect
    Protected Event=WaitWindowEvent(1)
    Select Event
      Case #PB_Event_Menu
        Select EventMenu()
          Case #Send
            If GetActiveGadget()=#Chat_Field
              Protected Content.S=GetGadgetText(#Chat_Field)
              If Content=""
                PlaySound(Empty)
                Continue
              Else
                SendNetworkString(ConnectionID,Content,#PB_UTF8)
                SetGadgetText(#Chat_Field,"")
                PlaySound(Send)
              EndIf
            EndIf
        EndSelect
      Case #PB_Event_Gadget
        Select EventGadget()
          Case #Exit_Button
            CloseNetworkConnection(ConnectionID)
            End
        EndSelect
    EndSelect
  ForEver
EndIf
That is missing the gadget and sound loading/playing code, but you should be able to get the idea. The problem I was having was with mixing packets, and so I tried switching to send_() and recv_() from the WinAPI, but now nothing gets sent at all :D :D.

// Edit: Code tags were added and the code indentation was corrected (Kiffi)

Re: Recv_() and send_() questions.

Posted: Sat Oct 24, 2020 6:39 pm
by mk-soft
TCP/IP only takes care of this with a handshake, which allows data up to 64 KB to be sent and received in packets in the correct order. ISO model layer 4.

This means that the data is transmitted piece by piece as packets (local network approx. 1500 byte, Internet a little less approx. 1492 byte)

Your data which is sent and received is in the ISO model layer 5 to 7 and you have to take care of the content yourself, you also have to take care of the protocols like http(s) FTP, etc.

SendNetworkData only enters the data for sending into the send buffer and ReceiveNetworkData only fetches the data already received into the receive buffer.

If all packets have arrived in the whole large (up to 64 kb), you have to check yourself, because it is possible that a part of the data has already arrived

This also means that if you call SendNetwork twice, all data will be available when the receive buffer is queried.

Common methods of transmitting data is to use a header (for example, Modbus/TCP),
Work with control characters (StartOfText #STX$, EndOfText #ETX$),
or
As with HTTP in Text Header to include the size of the data

Re: Recv_() and send_() questions.

Posted: Sat Oct 24, 2020 7:40 pm
by Bitblazer
Why do you use a wild mix of purebasic network library and api calls?

That can create 'interesting' problems due to internal buffering. It could be interesting to trace what actually happens in such a case with wireshark and WinApiOverride. Basically the network api sequence might be different to what you think it is. Try using only the purebasic network functions first.

Re: Recv_() and send_() questions.

Posted: Sat Oct 24, 2020 8:05 pm
by Ty1003
Hi.
Initially, I did use just PB calls. But the MOTD and online packet, for example would get mashed. Or if two users sent a chat at the same time. So I tried using recv_() and send_() to insure the packet arrives before sending the next one, but it doesn't work... :(

Re: Recv_() and send_() questions.

Posted: Sat Oct 24, 2020 9:01 pm
by mk-soft
Not read what I have written?

The same applies to API Send and Receive

Here an example with short text sending over UDP and control character STX, ETX
Link: viewtopic.php?f=12&t=74200

Re: Recv_() and send_() questions.

Posted: Mon Nov 30, 2020 11:10 pm
by RichAlgeni
Did you get your server to work correctly Ty1003?