'Send a request or return packet to the remote process.
Generally it is not necessary to call this method directly; it is for internal use.
(The docstring has information that is nevertheless useful to the programmer
as it describes the internal protocol used to communicate between processes)
**Arguments:**
request         String describing the type of request being sent (see below)
reqId           Integer uniquely linking a result back to the request that generated
it. (most requests leave this blank)
callSync        \'sync\':  return the actual result of the request
\'async\': return a Request object which can be used to look up the
result later
\'off\':   return no result
timeout         Time in seconds to wait for a response when callSync==\'sync\'
opts            Extra arguments sent to the remote process that determine the way
the request will be handled (see below)
returnType      \'proxy\', \'value\', or \'auto\'
byteData        If specified, this is a list of objects to be sent as byte messages
to the remote process.
This is used to send large arrays without the cost of pickling.
Description of request strings and options allowed for each:
request        option         description
getObjAttr                    Request the remote process return (proxy to) an
attribute of an object.
obj            reference to object whose attribute should be
returned
attr           string name of attribute to return
returnValue    bool or \'auto\' indicating whether to return a proxy or
the actual value.
callObj                       Request the remote process call a function or
method. If a request ID is given, then the call\'s
return value will be sent back (or information
about the error that occurred while running the
function)
obj            the (reference to) object to call
args           tuple of arguments to pass to callable
kwds           dict of keyword arguments to pass to callable
returnValue    bool or \'auto\' indicating whether to return a proxy or
the actual value.
getObjValue                   Request the remote process return the value of
a proxied object (must be picklable)
obj            reference to object whose value should be returned
transfer                      Copy an object to the remote process and request
it return a proxy for the new object.
obj            The object to transfer.
import                        Request the remote process import new symbols
and return proxy(ies) to the imported objects
module         the string name of the module to import
fromlist       optional list of string names to import from module
del                           Inform the remote process that a proxy has been
released (thus the remote process may be able to
release the original object)
proxyId        id of proxy which is no longer referenced by
remote host
close                         Instruct the remote process to stop its event loop
and exit. Optionally, this request may return a
confirmation.
result                        Inform the remote process that its request has
been processed
result         return value of a request
error                         Inform the remote process that its request failed
exception      the Exception that was raised (or None if the
exception could not be pickled)
excString      string-formatted version of the exception and
traceback'

def send(self, request, opts=None, reqId=None, callSync='sync', timeout=10, returnType=None, byteData=None, **kwds):

    if self.exited:
        self.debugMsg('        send:    exited    already;    raise    ClosedError.')
        raise ClosedError()
    with self.sendLock:
        if (opts is None):
            opts = {}
        assert (callSync in ['off', 'sync', 'async']), 'callSync    must    be    one    of    "off",    "sync",    or    "async"'
        if (reqId is None):
            if (callSync != 'off'):
                reqId = self.nextRequestId
                self.nextRequestId += 1
        else:
            assert (request in ['result', 'error'])
        if (returnType is not None):
            opts['returnType'] = returnType
        try:
            optStr = pickle.dumps(opts)
        except:
            print '====        Error    pickling    this    object:        ===='
            print opts
            print '======================================='
            raise
        nByteMsgs = 0
        if (byteData is not None):
            nByteMsgs = len(byteData)
        request = (request, reqId, nByteMsgs, optStr)
        self.debugMsg('send    request:    cmd=%s    nByteMsgs=%d    id=%s    opts=%s', request[0], nByteMsgs, reqId, opts)
        self.conn.send(request)
        if (byteData is not None):
            for obj in byteData:
                self.conn.send_bytes(obj)
            self.debugMsg('        sent    %d    byte    messages', len(byteData))
        self.debugMsg('        call    sync:    %s', callSync)
        if (callSync == 'off'):
            return
    req = Request(self, reqId, description=str(request), timeout=timeout)
    if (callSync == 'async'):
        return req
    if (callSync == 'sync'):
        try:
            return req.result()
        except NoResultError:
            return req
