"Copyright Notice: respect for the original, reproduced please retain the source: blog.csdn.net/shallnet or .../gentleliu, the article is for learning communication only, do not use for commercial purposes"
In two process communication, there are two processes that exchange information with each other, and some are more complex than the previous section. In general, there is a service process that waits for the client process to connect, and the client process and the service process have the following three ways of exchanging data:
The client process sends a request for a global data from the service process, and the service process returns the data (for short, get requests);
The client process sends a request to set the service process global data (for short, set request);
The client process sends a request to set the service process global data, and returns a data after the service process is set, (set and get coexist);
In this section we will complete a socket interprocess communication that can be used in real-world applications.
There may be many kinds of get and set requests described above, and the data used for each request is different, so we need to define a type for each request, where the service process can know what data the client process needs to process, and each request service process should return the resulting return value of its processing Since it is two process communication, there must be a data exchange, so there must be data sent and received, as well as the need to know the size of the data to the end. So we first define the data structure (similar to the TCP/IP protocol packet format) between two processes, based on this need:
typedef struct _IPC_SOCK_MSG_T { int msg_type;//request type int msg_rc;//Service process result return value int msg_ buflen;//the size of the interchange data Char msg_buf[sock_ipc_max_buf];//The contents of the interchange data} ipc_sock_msg_t;
When a service process receives a client process request, it first determines the type of request and processes it according to the request type. We first define an array of functions that all requests to be processed before the service process receives the request are registered with the function array, and the processing function is found based on the request type Index after the request is received.
The function array is as follows:
static int (*sln_ipc_ser_func[sln_ipc_max_type]) ( void *recvbuf, int recv_size, void *sendbuf, int *send_size) ;
Before the service process receives processing, it registers the function that needs to be processed in the function array, as follows:
int Sln_ipc_ser_func_init (void) { int i; for (i = 0; i < Sln_ipc_max_type; i++) { sln_ipc_ser_func[i] = NULL; } SLN_IPC_SER_FUNC[SLN_IPC_TYPE_0X1] = sln_ipc_handle_0x1; SLN_IPC_SER_FUNC[SLN_IPC_TYPE_0X2] = sln_ipc_handle_0x2; return 0;}
After the service process starts listening, wait for the connection:
The listener code is similar to the previous section example:
#if Use_af_unix fd = Sln_ipc_ser_afunix_listen (sock_ipc_name); if (FD < 0) { return-1; } #else fd = Sln_ipc_ser_afinet_listen (sock_ipc_ser_listen_port); if (FD < 0) { return-1; } #endif
The service process receives the data sent by the client process and gives it to the function Sln_ser_handle to handle:
static intsln_ipc_ser_accept (int listenfd) { int connfd; ssize_t Recvlen; ipc_sock_msg_t recv_msg; socklen_t Addrlen; #if use_af_unix struct sockaddr_un cltaddr; #else struct sockaddr_in cltaddr; #endif addrlen = sizeof (CLTADDR); for (;;) { CONNFD = Accept (LISTENFD, (struct sockaddr *) &cltaddr, &addrlen); if (CONNFD < 0) { fprintf (stderr, "Accept:%s\n", Strerror (errno)); Continue; } if (Recvlen = Sln_ipc_recv (CONNFD, &recv_msg, sizeof (ipc_sock_msg_t))) < 0) { continue; } Sln_ser_handle (CONNFD, &recv_msg); Close (CONNFD); } return 0;}
Where the handler function Sln_ser_handle is implemented as:
static intsln_ser_handle (int sockfd, ipc_sock_msg_t *recv_msg) { ipc_sock_msg_t send_msg; memset (&send_msg, 0, sizeof (ipc_sock_msg_t)); Send_msg.msg_type = recv_msg->msg_type; if ((Recv_msg->msg_type >= sln_ipc_max_type) && (RECV_MSG->MSG_RC < 0)) { SEND_MSG.MSG_RC = Sln_ipc_rc_type; } else if (NULL = = Sln_ipc_ser_func[recv_msg->msg_type]) { SEND_MSG.MSG_RC = Sln_ipc_rc_func; } else { SEND_MSG.MSG_RC = Sln_ipc_ser_func[recv_msg->msg_type] ( recv_msg->msg_buf, recv_msg-> Msg_buflen, send_msg.msg_buf, &send_msg.msg_buflen); } if (Sln_ipc_send (SOCKFD, &send_msg, sizeof (ipc_sock_msg_t)) < 0) { return-1; } return 0;}
Call the service process handler that is registered at initialization time in function Sln_ser_handle to complete the request of the client process. The two functions that initialize the registration are:
static char gbuf[256] = "Hello, this is server!"; intsln_ipc_handle_0x1 (void *recvbuf, int recv_size, void *sendbuf, I NT *send_size) { printf ("=============%s->%d===========\n", __func__, __line__); memcpy (SendBuf, Gbuf, strlen (GBUF)); *send_size = strlen (gbuf); return SLN_IPC_RC_OK;} intsln_ipc_handle_0x2 (void *recvbuf, int recv_size, void *sendbuf, int *send_size) { printf ("=============%s->% D===========\n ", __func__, __line__); memcpy (Gbuf, Recvbuf, recv_size); *send_size = 0; return SLN_IPC_RC_OK;}
The processing function takes 4 parameters, namely: Receive data buffer, received data size, send data buffer, send data size. The first two parameters are input parameters, the last two parameters are the parameters that return the output, the service process needs to process the customer request according to the data sent by the customer process, and then return the data that the service process needs to return and the result (completion or failure), and the processing result is returned in the return value of the handler function.
Here's a look at the implementation of the customer process:
Intsln_ipc_clt_conn (int msg_type, int *ret_code, void *sendbuf, int sendlen, void *rec vbuf, int *recvlen) {int connfd; ssize_t ret_size; Socklen_t Addrlen; ipc_sock_msg_t send_msg, recv_msg; #if Use_af_unix if (connfd = Sln_ipc_clt_afunix_conn_init (sock_ipc_name)) < 0) {return-1; } addrlen = sizeof (struct sockaddr_un), #else if (connfd = Sln_ipc_clt_afinet_conn_init (sock_ipc_ser_listen_port)) & Lt 0) {return-1; } addrlen = sizeof (struct sockaddr_in), #endif if (Connect (CONNFD, (struct sockaddr *) &seraddr, Addrlen) < 0) {fprintf (stderr, "Connect:%s\n", Strerror (errno)); return-1; } memset (&send_msg, 0, sizeof (ipc_sock_msg_t)); Send_msg.msg_type = Msg_type; if (NULL! = sendbuf) {Send_msg.msg_buflen = Sendlen; memcpy (Send_msg.msg_buf, SendBuf, Sendlen); } if (ret_size = Ipc_send (CONNFD,&SEND_MSG, 3 * sizeof (int) + Sendlen)) < 0) {return-1; } if ((Ret_size = Ipc_recv (CONNFD, &recv_msg, sizeof (ipc_sock_msg_t))) < 0) {return-1; } if (Recv_msg.msg_type! = send_msg.msg_type) {printf ("Error msg type!\n"); return-1; } *ret_code = RECV_MSG.MSG_RC; if (NULL! = recvbuf) {*recvlen = Recv_msg.msg_buflen; memcpy (Recvbuf, Recv_msg.msg_buf, Recv_msg.msg_buflen); } return 0;}
The interface that the client process invokes is simpler to implement, just to tell the service process the type of processing I requested (Msg_type), and the data (SENDBUF) and size (Sendlen) that need to be transferred, the service process returns the processing result (ret_ Code) and the return data (RECVBUF) and size (Recvlen).
Example source code for this section:
http://download.csdn.net/detail/gentleliu/8140479
About Linux IPC (ii): socket-based interprocess communication (bottom)