[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

UDP network communication



Are there any good example files laying around that would help me put
together a program to send binary data using UDP to a Sun?  I have 3 problems
i am trying to tackle: (1) setting up the UDP communication, (2) parsing
incoming binary data into appropriate internal data structures as well as
structuring outgoing data, and (3) byte-swapping.  I am currently stuck on the
first and i believe the primary reason to be that there are not many UDP
examples in the Network manual.  For test purposes, I am using a 3630 and
XL400 running under Genera 8.1.  Once i get the UDP working between those two,
i will attempt to communicate between the '30 and a Solbourne running under
UNIX (actually OS/SMP 4.0D_Export or some such).

I am including my code along with the sample application i have been using to
test it.  This code does not worry the binary problem or the byte swapping; it
just tries to get the machines to talk to each other using UDP.  Some functions
are defined twice so that i can use the simpler version for testing.

My primary problem seems to be that the data is not being packaged correctly.
The starting and ending index of the message received is always 8 and 8.
Should i be sending an array?  The few examples do not indicate that.  I have
tried sending a string and an integer.  Neither gets there.  Should i explicitly
be sending size information?  

I want to use the response-array for the ACK.  I didn't find i really needed
the start and end indices.  Do i really need to set these?

Here is the code:

;;; -*- Syntax: COMMON-LISP; Base: 10; mode: lisp; package: USER; -*-

;;;--------------------------------------------------------------------------------
;;;			       UDP SOCKET HANDLER
;;;
;;;    This file defines the underlying functions for using TCP-IP/Unix sockets
;;; with the message handler.  
;;;
;;;--------------------------------------------------------------------------------
  
cl-user::(provide 'udp-socket)


;;; Define the socket protocol.
;;; Use the function (net:invoke-service-on-host :socket (net:parse-host "host-name"))
;;; to get the USER end of the bidirectional stream on a LISP Machine.

;;; This defines the client (user) end. For most cases this will be a Unix machine,
;;; but it can be a Symbolics
(net:define-protocol :udp-socket (:udp-socket :datagram)
  (:desirability 0.8)
  (:invoke (service)
     (net:get-connection-for-service service)))



;;; Add a socket handler to the network
;;; This defines the server end, which will always be a Symbolics.
(net:define-server :udp-socket
		    (:medium :datagram
		     :reject-unless-trusted t
		     :who-line t
		     :host user-host
		     :request-array (msg-array msg-start msg-end)
		     :response-array (ack-array ack-start ack-end)
		     )
;   (cond ((eq msg-start msg-end) nil 0)
;	 (t
	  (read-datagram msg-array msg-start msg-end)
	  ;; returns 2 values: t/nil for request accepted and byte index after response
	  (ack-datagram ack-array ack-start ack-end msg-array msg-start msg-end);))
)


(tcp:add-udp-port-for-protocol :udp-socket 2010.)		; UDP port number for sockets


(defvar *SOCKET-MESSAGES* nil)			;List of arrays which are messages received
(defvar *HEADER-LENGTH* 24)   ;the header is 24 bytes long
(defvar *time-between-retries* 5)	; 5 Seconds between retransmissions

(defun read-datagram (msg-array start end)
  (push
    (copy-vector-part msg-array start (1- end)) ;; end is beyond actual end 
    *SOCKET-MESSAGES*))      



(defun ack-datagram (ack-array ack-start ack-end msg-array msg-start msg-end)
  ;; make sure that there is a header; if no header, reject the message
  (cond ((> *header-length* msg-end)
	 (values nil 0))
	(t
	 (setf ack-start 0 ack-end 24)
	 (setf (aref ack-array 0) (aref msg-array (+ msg-start 1))) ;; destination
	 (setf (aref ack-array 1) (aref msg-array msg-start)) ;; source
	 (setf (aref ack-array 2) *header-length*) ;; length
	 (setf (aref ack-array 3) 0) ;; type
	 (setf (aref ack-array 4) (+ msg-start 4)) ;; transaction id
	 (setf (aref ack-array 5) 0) ;; retry count
	 (values t *header-length*))))
 

(defun ack-datagram (ack-array ack-start ack-end msg-array msg-start msg-end)
  (setq ack-array (copy-vector-part msg-array msg-start (1- msg-end))
	ack-start 0
	ack-end (array-total-size ack-array))
  (values t ack-end))

(defun parse-message (message)
  (print-vector message)
)


(defun udp-receive (&optional (no-hang nil)  (parse nil))
  (when (numberp no-hang) (setq no-hang (round (* no-hang 60))))
  (let ((message
	  (cond ((eq t no-hang)
		 (pop *SOCKET-MESSAGES*))
		(t
		 (process-wait-with-timeout "No Message" no-hang
		   #'(lambda ()
		       (pop *SOCKET-MESSAGES*)))))))
    (if parse
	(parse-message message))
    message))


(defun udp-transmit (message host-name &optional (hang nil))
  (cond ((numberp hang)				; Change units from seconds to 60ths
	 (setq hang (round (* hang 60))))	; and make sure its a fixnum
	((eq hang t)				; Wait a long time
	 (setq hang (* 60 60 60 24))))		; a day - I certainly won't wait any longer
  (do ((initial-time (time:time))
       result)
      ((or (setq result
		 (net:invoke-service-on-host
		   :udp-socket
		   (net:parse-host host-name) message))	; Successful transmit
	   (null hang)				; Don't want to wait
	   (time:time-elapsed-p hang initial-time))	; Waited long enough
       result)
    (sleep *time-between-retries* :Sleep-Reason "Waiting to Retry Transmit")))



 

Here is a little application for one end.  I am using the same app with send and receive
reversed and calling out different hosts on the other end:


(defun udp-app ()
  (let ((hang 10)
	(no-hang 10) ;; wait until messsage available to receive
	(parse nil)) ;; don't parse received message

    ;; send a message to Banff
    (format t "~%Transmit returned ~A"
	    (udp-transmit "Hi Rick!" "Banff" hang))
;    (read-line)
    ;; receive a message from Banff
;    (format t "~?" "~%Message Text: ~A"
;	    (udp-receive no-hang parse))
;    (read-line)
    ))




ANY input would be appreciated.  Any sample code would be very useful!

--Robin R. Kladke
Martin Marietta, Denver, CO