I. QNX message Overview
QNX messages can be divided into synchronous messages and asynchronous messages. Asynchronous messages mainly reflect a notification mechanism. synchronous messages mainly refer to the process in which messages need mutual cooperation between the two parties during the transmission process.
Ii. Basic concepts of QNX message transmission
1. channels and links
Message transmission is based on the server and client mode. qnx6 abstracts the "channel" concept. A channel is the entry to a service. As for how many threads a channel actually serves, it is all about the server. If a server has multiple services, it can also open multiple channels. Before sending a message to a channel, the client needs to establish a connection before sending the message to the channel. In this way, the same client can establish multiple connections with the same channel if needed.
2. name_space)
In the communication between the client and the server, to make it easy for the client to know the server's Nd/Pid/chid, the server process can register a path name and associate it with the nd, PID, and chid of the service channel. The client only needs to request the path name of the connected version server.
3. Client Server Communication under QNX synchronization signal
1. Client Model
1) Call name_open (PATH) to connect to the server channel to obtain a connection ID
3) Call the API to send a message and wait for the server to respond
4) After receiving the response, call name_close () to close the connection.
2. Server Model
1) Call name_attach to register a namespace and create a channel
2) receive and process messages
3) Response Message Processing result
4) name_detach delete the name from the namespace
3. Client Server Message transmission process
1) The server registers a namespace and waits for the client to connect.
2) connect the client to the namespace
3) The client calls the msgsend interface to send messages to the server, and the client is blocked from sending messages.
4) The server calls the msgreceive interface to receive data, and the client is blocked in response.
5) The server processes the message and calls the msgreply function to send the Response Message.
6) The client returns the result from the msgsend function to remove blocking.
4. Use multiple messages to improve efficiency
Iov_t is used to "collect" data. That is to say, several pieces of data can be transmitted at a time. The header and databuf are two non-adjacent memories, but they are passed to the receivebuffer at the server end, which is continuous.
Setiov (& IOV [0], & header, sizeof (header ));
Setiov (& IOV [1], databuf, datalen );
Msgsendvs (connectionid, IOV, 2, replybf, replylen );
5. message transmission direction and msgdeliverevent ()
When the client sends a message to the server, the server cannot immediately respond and the client does not want to wait. In this case, the correct method is to tell the client that the request will be processed after a period of time, and the client can continue to run. Once the server completes the task, the server needs to tell the client that the request is complete in some ways.
Client: Prepare a notification event and send it to the server using msgsend (), which means: "If XXX happens, please use this event to notify me ".
Server: After receiving the message, record the rcvid and the passed events, and then respond to "OK, now ".
Client: with the server's response, the client is no longer blocked and can do other things.
......
Server: at a certain time point, the "XXX situation" required by the client is met, and the server calls msgdeliverevent (rcvid, event) to notify the client
Client: After receiving the notification, use msgsend () to send the "where is the data in XXX ?"
Server: Use msgreply () to return data to the client
Int msgdeliverevent (INT rcvid, const struct sigevent * event );
The event server does not need to modify the rcvid, which is received by the server from the client. This ID is meaningless when the server responds to the client. In addition, msgdeliverevent is a non-blocking function.
6. Common APIs
Channelcreate (), channeldestroy ()
Connectattach (), connectdetach ()
Msgdeliverevent ()
Msgerror ()
Msgread (), msgreadv ()
Msgreceive (), msgreceivepulse (), msgreceivev ()
Msgreply (), msgreplyv ()
Msgsend (), msgsendnc (), msgsendsv (), msgsendsvnc (), msgsendv (),
Msgsendvnc (), msgsendvs (), msgsendvsnc ()
Msgwrite (), msgwritev ()
Name_attach (), name_close (), name_detach (), and name_open ()
7. Summary
1) The client specifies the Server Response Buffer when sending messages to the service.
2) When the server sends a message (msgreply) to the client, the parameter is passed as the return value of msgsend.
3) When msgreceive is enabled, the server can pass parameters to obtain information about the messages sent by the client.
4) when the client opens the service namespace, the system will send a _ io_connect message to the server.
5) when the client is disconnected or the namespace is closed, the server receives the _ pulse_code_disconnect pulse.
6) when the client view removes the blocking from the reply block, the server will receive the _ pulse_code_unblock pulse.
7) when creating the namespace, The _ nto_chf_disconnect_nto_chf_coid_disconnect and _ nto_chf_unblock standards are automatically set. Therefore, the server can receive the corresponding system pulse.
Iv. Notification signal-pulse
1. Basic Concepts
Pulse is actually more like a short message, which is also sent on a "connection. The biggest feature of a pulse is that it is asynchronous. The sender does not have to wait for the receiver to respond and can continue the execution directly. However, this Asynchronization also imposes limitations on pulses. The amount of data that a pulse can carry is limited. There is only one eight-bit "code" domain to distinguish different pulses and to carry data with a 32-bit "value" domain. Pulse is mainly used for notification ). Not only are user programs, but the kernel also generates a special "system pulse" to notify the user program of a special situation.
2. Receive pulse
You can use msgreceivepulse () to receive only pulses. If the channel can receive messages or pulses, msgreceive () is used directly, as long as the receiving buffer (reveivebuf) can accommodate at least the next pulse (sizeof struct _ pulse. If the rcvid returned by msgreceive () is 0, a pulse is received. Otherwise, a message is received.
3. Pulse Signal Features
1) effective transmission of 40-bit data (8-bit pulse code, 32-bit data)
2) non-blocking for the sender
3) can be accepted like other messages
4) pulses are queued as long as the receiver is not blocking the waiting pulse.
5) If no pulse exists, the receiver blocks the waiting pulse.
4. related data structures and APIs
Struct _ pulse {
Uint16_t type;
Uint16_t subtype;
Int8_t code;
Uint8_t zero [3];
Union sigval value;
Int32_t scoId;
};
Value is a consortium
Union sigval {
Int sival_int;
Void * sival_ptr;
};
Int msgreceivepulse (INT chid,
Void * rmsg,
Int rbytes,
Struct _ msg_info * info );
5. asynchronous messages
1. Common asynchronous signal APIs
Asyncmsg_channel_create ()
Asyncmsg_channel_destroy ()
Asyncmsg_connect_attach ()
Asyncmsg_connect_detach ()
Asyncmsg_flush ()
Asyncmsg_put (),
Asyncmsg_get ()
Asyncmsg_free ()
Asyncmsg_malloc ()
2. API description
Int asyncmsg_channel_create (
Unsigned flags,
Mode_t mode,
Size_t buffer_size,
Unsigned max_num_buffer,
Const struct sigevent * eV,
INT (* recvbuf_callback )(
Size_t bufsize,
Unsigned num_bufs,
Void * bufs [],
Int flags,
Void * handle ),
Void * recvbuf_callback_handle );
Flags: Describes the channel attributes. The default value is _ nto_chf_async. If you set _ nto_chf_async_nonblock
When the program calls asyncmsg_get (), it will not block if there is no message.
Mode: Set channel attributes
Buff_size: Set the buffer size for storing messages.
Max_num_buffer: sets the maximum number of buffer zones for storing messages.
Ev: null or a pointer to the sigevent struct, used to specify an event. When a message can be received, this event is automatically sent.
Recvbuf_callback: null or a function pointer, which is used to allocate space to store received messages. When the value is null, malloc is used.
Recvbuf_callback_handle: it is passed to the recvbuf_callback function.
Note:
When recvbuf_callback is not null:
Every time you call asyncmsg_get (), a callback function is triggered (flags is set to asyncmsg_recvbuf_alloc, and bufs points to the message...). If you want to receive other messages, 1 is returned and 0 is returned to stop.
When asyncmsg_channel_destroy () is called, The callback function is triggered multiple times to release space. Flags is set to asyncmsg_recvbuf_free.
Int asyncmsg_channel_destroy (INT chid );
Chid: Channel ID
Note:
When recvbuf_callback is not null, each call triggers the release of space. By default, the call is free.
Return Value:
Success: Eok
Failed:-1-> errno
Int asyncmsg_connect_attach (
Uint32_t nd,
Pid_t PID,
Int chid,
Unsigned index,
Unsigned flags,
Const struct _ asyncmsg_connection_attr * ATTR );
Parameter description:
Nd/Pid/chid: Which computer/process ID/channel ID
Index: the lowest acceptable connection ID (starting value)
Flags:
_ Nto_cof_noshare: The application uses its own buffer. Otherwise, the application uses asyncmsg_malloc () to fill in the data and send it when asyncmsg_put () is called.
_ Nto_cof_nonblock: No need to block the wait. When the sending header is busy
ATTR:
Specify Connection Properties
Return Value:
Successful: Connection ID
Failed:-1
Int asyncmsg_connect_detach (INT coId );
Parameters:
CoId: Connection ID
Note:
Disconnect from the specified connection, and all the messages on the sending side are discarded. If all the messages are sent before this, the asyncmsg_flush () interface is called before this.
Return Value:
Success: Eok
Failed:-1
Int asyncmsg_flush (INT coId,
Int mode );
Parameter description:
CoId: Connection ID
Mode:
0. If you do not want to block the function, set asyncmsg_flush_nonblock.
Return Value:
Success: Eok
Failed:-1
Int asyncmsg_connect_attr (
Int coId,
Struct _ asyncmsg_connection_attr * old_attr,
Const struct _ asyncmsg_connection_attr * new_attr );
Parameter description:
CoId: Connection ID
Old_attr: Current attribute
New_attr: new attribute
Return Value:
Success: Eok
Failed:-1
Int asyncmsg_put (INT coId,
Const void * buff,
Size_t size,
Unsigned handle ),
INT (* call_back )(
Int err,
Void * Buf,
Unsigned handle ));
Int asyncmsg_putv (INT coId,
Const iov_t * IOV,
Int parts,
Unsigned handle,
INT (* call_back )(
Int err,
Void * Buf,
Unsigned handle ));
Parameter description:
CoId: Connection ID
Buff: Message Buffer
Size: Message Size
IOV: array of IOV messages
Parts: IOV array size
Handle: User-defined data is passed to the callback function to differentiate the package type.
Call_back: null or a function pointer, called after message transmission. If it is null
_ Asyncmsg_connection_attr is passed to asyncmsg_connect_attach and is called.
Struct _ asyncmsg_get_header * asyncmsg_get (INT chid );
Parameter description:
Chid: Channel ID
Note: A function can receive a maximum of five asynchronous messages. To receive more messages, you should call this interface cyclically. If null is returned and errno is eagain, the read is complete.
Return type:
Struct _ asyncmsg_get_header {
Struct _ msg_info Info;
Int err;
Iov_t * IOV;
Int parts;
Struct _ asyncmsg_get_header * next;
Unsigned reserve [2];
};
Note:
Info: asynchronous signal information structure
Err: Error status
Ivo: pointing to the message body
Parts: Ivo array size
Next: pointing to the next information struct
Return Value:
Success: information linked list
Failed: NULL
Void asyncmsg_free (void * BUF );
Parameter description:
Buf: memory release pointer
Note:
Asyncmsg_get () call promotes memory release
Void * asyncmsg_malloc (size_t size );
Note:
The function allocates space for sending messages.