Hi ppl,
as I announced it, I would show how to send and receive datas via network correctly couse I saw many codes in this forum who does not. I tried to use some variablenames to make it clear. This routine can be optimized a lot but possible its not as clear as it is yet. Have fun.
Code: Select all
; How to send and receive Strings via network correctly
; The Send-Routine is quite simple
; You should use a threads to send datas, espacially on the server to avoid blockings.
; Here is nothing special but I will try to explain every line.
Procedure SendString(id,txt$) ; connected Socket, string$
; calculate bufferlength
length.l=Len(txt$)+1 ; String + EOL
length.l+4 ; Packet length at beginning
length.l+4 ; CRC32
*mem.l=GlobalAlloc_(#GMEM_FIXED | #GMEM_ZEROINIT, length.l) ; Allocate needed memory
PokeL(*mem.l,length.l) ; Store the Header (Size of Packet)
PokeS(*mem.l+4,txt$) ; Store String (Datas)
crc.l=CRC32Fingerprint(*mem.l+4,length.l- ; Create CRC32 Checksum - Not really needed
PokeL(*mem.l+length.l-4,crc.l) ; Store it at the end of the packet
Repeat ; Loop for Datasend
send=send_(id,*mem.l,length,0) ; Send our Datas
sended+send ; Count our sended Bytes
If send=#SOCKET_ERROR ; Check for socket error
wsaerror=wsagetlasterror_()
If wsaerror=#WSANOTINITIALISED:err$="Wsa not initialized":EndIf
If wsaerror=#WSAENETDOWN :err$="The Windows Sockets implementation has detected that the network subsystem has failed.":EndIf
If wsaerror=#WSAENOTCONN :err$="Socket not connected.":EndIf
If wsaerror=#WSAEINTR :err$="The (blocking) call was canceled using WSACancelBlocking":EndIf
If wsaerror=#WSAEINPROGRESS :err$="A blocking Windows Sockets operation is in progress.":EndIf
If wsaerror=#WSAENOTSOCK :err$="The descriptor is not a socket.":EndIf
If wsaerror=#WSAEOPNOTSUPP :err$="MSG_OOB was specified, but the socket is not of type SOCK_STREAM.":EndIf
If wsaerror=#WSAESHUTDOWN :err$="The socket has been shut down; it is not possible to recv on a socket after shutdown has been invoked with how set to 0 or 2.":EndIf
If wsaerror=#WSAEMSGSIZE :err$="The datagram was too large to fit into the specified buffer and was truncated.":EndIf
If wsaerror=#WSAEINVAL :err$="The socket has not been bound with bind.":EndIf
If wsaerror=#WSAECONNABORTED :err$="The virtual circuit was aborted due to timeout or other failure.":EndIf
If wsaerror=#WSAECONNRESET :err$="The virtual circuit was reset by the remote side.":EndIf
If wsaerror=#WSAEWOULDBLOCK :err$="The socket is marked as nonblocking":EndIf
; This is VERY importend to check for.
; If the TCP/IP Buffer is full and your datas can not send as fast as your app it sends, you get
; this error messages. You have to send your datas again and again till its complete.
; There is another methode too, but I think this is the easiest way.
If wsaerror=#WSAEWOULDBLOCK:send=0:sended=0:Delay(25):EndIf
EndIf ; Errorcheck
Until sended>=length Or send=#SOCKET_ERROR ; Loop as long as all Datas has been send
GlobalFree_(*mem) ; Free our Memory again
EndProcedure
; The following receive-code receives a string that is send with my send procedure above.
; I make it a little bit shorter as the normal one in our app couse that is MUCH bigger.
; Short explanation to the variables:
; totalreceived -> amount of datas that are allready received on the buffer
; receiveexpected -> The expected Size of the sended String
;
; The Datapackage is send in the following shema:
;
; Packetsite.l -> 4 Bytes Packetsize
; string$ -> unknown length, chr(0) terminated
; CRC32 -> optional a CRC32 at the end (not realy needed)
;
; HOW TO USE:
; The receive routine should only be called if an networkevent on this socket is received.
; The code shown here is only to handle one user, that means you can only use it on a clients side.
; If you want to use it on server side you will need a buffer for every user connected.
; The vars Totalreceived.l and receiveexpected.l should be in a list for every user too.
;
; After connecting to a server you have to catch incoming events you have to wait for.
; Use WSAAsyncSelect_() to do this. Its easy to use. Add the flags FD_Read to it. Thats all you need.
; Now you can use WaitWindowEvent() for waiting for network events too.
;
; Dont forget to initialize the network and allocate the *receivebuffer to eg 10000 Bytes first.
; Should be enough but depends on you stringsize.
; here we go...
; --->>> RECEIVEROUTINE 0 ; We allready know our Packetsize, so we can receive it
received=recv_(serversocket.l,*receivebuffer.l+totalreceived.l,receiveexpected-totalreceived,0) ; Receive and attach the datas to our buffer
If received#SOCKET_ERROR ;WSA Error detected? No? Then....
If received>0:totalreceived+received:EndIf ;add the received bytes to our Bytecounter in totalreceived
If totalreceived=PeekL(*receivebuffer.l) ; Is our packet complete?
command$=PeekS(*receivebuffer+4) ; Get our String from Memorybuffer +4 (couse 0 is packetsize)
totalreceived=0 ; Datapacket complete, reset value and wait for new one
receiveexpected=-1 ; Wait for new packetheader but do not execute the next part!
EndIf
Else
; YOUR ERRORHANDLING HERE
EndIf
EndIf
If totalreceived#SOCKET_ERROR
If received=4:receiveexpected=PeekL(*receivebuffer):EndIf ; Completed yet?
If received>0:totalreceived+received:EndIf ; Count our Received bytes (we need 4!)
EndIf
; Your Errorhandling here
EndIf
If receiveexpected=-1:receiveexpected=0:EndIf ; This is only to avoid receiving datas that has to wait in the queue
; Until the next event is processed
Mike
Tranquilizer/ Secretly!
http://www.secretly.de
Registred PureBasic User