SendTo() RecvFrom()

BlitzMax Forums/BlitzMax Module Tweaks/SendTo() RecvFrom()

Tom(Posted 2005) [#1]
Not yet implemented as of v1.10, these 2 Methods extend the send & recieve capability of sockets.

SendTo() works similar to .Send(), except with .Send() you're supposed to connect to a socket before using it. With .SendTo() you do not have to connect a socket first, you simply specify the destination IP & Port.

RecvFrom() works just as .Recv() does, but you also pass the method two Integer variables (srcIP & srcPort). After the call to RecvFrom() (if there was data in the socket), the srcIP & srcPort variables will be filled with the IP & Port of the sender.

Add this code in '\mod\brl.mod\socket.mod\socket.bmx' somewhere after 'Type TSocket', compile with command line 'bmk makemods brl.socket'

Tested & working in Win32, they *should* work in Linux/Mac

Cya!
Tom

  Method SendTo( buf:Byte Ptr,count,destIP,destPort,flags=0 )
    Local n=sendto_( _socket,buf,count,flags,destIP,destPort )
    If n<0 Return 0
    Return n
  End Method

  Method RecvFrom( buf:Byte Ptr,count,srcIP Var,srcPort Var,flags=0 )
    Local n=recvfrom_( _socket,buf,count,flags,srcIP,srcPort )
    If n<0 Return 0
    Return n
  End Method



Vertex(Posted 2005) [#2]
Hi!
Problem if you use recv or recvfrom with an udp socket is that you must read the complete size of the data buffer. If you don't do this, then the message is cut to specific size and the rest where trashed.

Here the example for the UDPStream:


you would for example send a simple message to a specific ip, you can do this with:
Global Stream:TUDPStream

Stream = New TUDPStream
Stream.SetLocalPort(4321)

Stream.SetRemotePort(1234)
Stream.SetRemoteIP(TNetwork.IntIP("127.0.0.1"))

Stream.WriteLine("Hello World")

Stream.Close()
End


But if you would receive a message like:
Global Stream:TUDPStream

Stream = New TUDPStream
Stream.SetLocalPort(1234)

While Not KeyDown(KEY_ESCAPE)
   If Stream.ReadAvail() Then
      While Not Stream.Eof()
         Print ">"+Stream.ReadLine()
      Wend

      Stream.SetRemoteIP(Stream.GetMessageIP())
      Stream.SetRemotePort(Stream.GetMessagePort())
      Stream.WriteLine("OK")
   EndIf
Wend

Stream.Close()
End


It is not work, becouse ReadLine reads byte by byte and not the full databuffer. GetMessageIP/Port does work, but only one byte are analysted complete.

Any idea how do solve this?

cu olli


Gehhilfe(Posted 2005) [#3]
Hi Vertex,
i have a idea using banks to buffer the data
and the sending the bank with a extra Method.

See you Tim


Vertex(Posted 2005) [#4]
Gehilfe: Hmm, yes, that was what Blitz3D do with RecvUDPMsg. RecvUDPMsg reads all I think in a internal Blitz buffer and ReadLine and so on reads out of this buffer. But it must can do with recvfrom only. A TCP Socket can do this. I must test setsockop with a peek parameter, but I think, this does only work with windows.

cu olli


Tibit(Posted 2005) [#5]
I'm sorry but I don't get the problem. As far as I know, RecvFrom works for me? And I don't buffer. With UDP you get a message or not?

I think I've missed something but why would you ever, want to not read the whole UDP message?

Please explain more, I can probably help you then.


Vertex(Posted 2005) [#6]
"Hello World" consist of 13(String+Chr(13)+Chr(10) ) Bytes.

From brl.mod\stream.mod\stream.bmx:
	Method ReadLine$()
		Local str$,buf:Byte[1024],p
		Repeat
			Local n:Byte
			If Read( Varptr n,1 )<>1 Exit
			If n=0 Exit
			If n=10 Exit
			If n=13 Continue
			buf[p]=n ; p:+1
			If p<>buf.length Continue
			str:+String.FromBytes(buf,p)
			p=0
		Forever
		If p str:+String.FromBytes(buf,p)
		Return str
	End Method


You see, ReadLine want to read on this example 13 Bytes individually. One Byte need 1 call of recvfrom.

The networkbuffer consist of the 13 bytes. If you call recvfrom with 1 Byte size, than recvfrom returns SOCKET_ERROR and WSAGetlastError returns 10040 -> WSAEMSGSIZE.

http://msdn.microsoft.com/library/default.asp?url=/library/en-us/winsock/winsock/recvfrom_2.asp

WSAEMSGSIZE:
The message was too large to fit into the specified buffer and was truncated.


A message sent on a datagram socket was larger than the internal message buffer or some other network limit, or the buffer used to receive a datagram was smaller than the datagram itself.


Datagram Socket = UDP Socket

So 1 Byte is read, and the other 12 Bytes are deleted from the networkbuffer. A second call of recvfrom will fall.

cu olli


Gehhilfe(Posted 2005) [#7]
Vertex my Version with Buffering is running well.



And some Sampels

Const Port = 1234

Global Stream:TUDPStream

Stream = New TUDPStream
If Not Stream.SetLocalPort(Port) Then RuntimeError "Server can not bind to port: "+ Port

Repeat
	
	Delay 200
		
	If Stream.Recv() 
		While Not Stream.eof()
			Print "New Byte:" +	Stream.ReadByte()
		Wend
	EndIf
	
	FlushMem()	

Forever


Const Port = 5200

Global Stream:TUDPStream

Stream = New TUDPStream
If Not Stream.SetLocalPort(Port) Then RuntimeError "Server can not bind to port: "+ Port

Stream.SetRemoteIP TNetwork.IntIP("127.0.0.1")
Stream.SetRemotePort 1234

Stream.WriteByte(33)
Stream.WriteByte(33)
Stream.WriteByte(33)
Stream.WriteByte(33)
Stream.WriteByte(33)
Stream.WriteByte(33)
Stream.WriteByte(33)

Stream.Send()



Tom(Posted 2005) [#8]
I still don't get what you're on about. I'm not using streams, and as Wave said, sendTo() & recvFrom() are working fine for me too.

If there's a problem with sockets when using the additional code I posted, can you show us a simple example?

Thanks
Tom