问题
I've been trying to write a libzmq wrapper for Swift by building off of an existing wrapper called SwiftyZeroMQ. However, for our purposes, we require the usage of raw UDP which means we need to use ZeroMQ's Radio/Dish draft method.
I've been able to successfully write a wrapper for receiving data via the Dish socket but I'm now trying to write a wrapper for sending data via the Radio socket. There doesn't seem to be any stuff online regarding how to write a function to send data via the Radio socket but I did come across this. This function in the libzmq repo tests the sending of data via the radio socket so I figured why not try and replicate the function in Swift.
Here's what I've come up with:
Inside the Socket.swift file:
public func sendRadioMessage(_ group: String, data: NSData) throws{
var msg = zmq_msg_t.init();
var result : Int32;
let flags: SocketSendRecvOption = .none
result = zmq_msg_init(&msg);
if (result == -1) { throw ZeroMQError.last }
defer {
// Clean up message on scope exit
zmq_msg_close(&msg)
}
print("initial msg data = \(zmq_msg_data(&msg))")
print("initial data = \(data)")
memcpy(zmq_msg_data(&msg), (data as NSData).bytes, data.length);
print("msg size = \(zmq_msg_size(&msg))")
print("msg = \(zmq_msg_data(&msg))")
result = zmq_msg_set_group(&msg, group);
if (result == -1) { throw ZeroMQError.last }
result = zmq_msg_send(&msg, self.handle, flags.rawValue);
if (result == -1) { throw ZeroMQError.last }
print("sent \(result) bytes")
}
}
and that function is then called like this:
public func send(data: String) -> Bool{
do{
try radio?.sendRadioMessage(group, data: data.data(using: .utf8) as! NSData);
}
catch{
print("SEND COMMUNICATION error - \(error)");
return false;
}
return true;
}
obj.send(data: "Test Data")
This is the console output when running the program:
It seems to me then that the memcpy
function that I'm calling from Swift doesn't actually seem to be doing anything. Would this be due to the fact that I'm not passing the data payload properly to the memcpy
function? I'm a bit stuck.
回答1:
The API-documented zmq_msg_data()
function is fine & safe to "read" a data-part from a delivered ZeroMQ message.
The context of use & the order of parameters :
void* memcpy( void* dest,
const void* src,
std::size_t count
);
shows, that your code tries to "store" data into a zmq_msg_t
-instance, in spite of countless warnings in the ZeroMQ API documentation not to ever attempt to "touch", the less to manipulate data "directly", but by using member functions :
Never access
zmq_msg_t
members directly, instead always use thezmq_msg
family of functions.
Here, possibly using rather :
int zmq_msg_init_data ( zmq_msg_t *msg,
void *data, // <------- payload to load into *msg
size_t size,
zmq_free_fn *ffn, // ref. API details
void *hint // on this
);
So the illustrative example might be something alike this :
//
// Initialising a message from a supplied buffer
//
// *********************************************
void my_free ( void *data, void *hint ) // ------- a dealloc helper
{
free ( data );
}
/* ... */
void *data = malloc ( 6 ); // -------------------- a mock-up payload data
assert ( data );
memcpy ( data, "ABCDEF", 6 );
zmq_msg_t msg;
rc = zmq_msg_init_data ( &msg, data, 6, my_free, NULL );
assert ( rc == 0
&& "INF: zmq_msg_init_data() failed, saying"
&& zmq_strerror ( zmq_errno() ) // ------- a non-POSIX system workaround
);
Also note, that a proposed defense of :
result = zmq_msg_init( &msg );
if ...
did gave a sense in v2.x & v3.x, yet after moving into v4.x, it started to do nothing , as it keeps in ZeroMQ v4.3+ API, as is documented in due form and shape :
Return value
Thezmq_msg_init()
function always returns zero.
Some version-control and redesign efforts might be needed so as to keep handling this consistently between the port-version and the actual API-version.
来源:https://stackoverflow.com/questions/65367000/swift-memcpy-doesnt-have-any-effect-when-used-with-zmq-zmq-msg-data