Chinaunix首页 | 论坛 | 博客
  • 博客访问: 336841
  • 博文数量: 92
  • 博客积分: 2500
  • 博客等级: 少校
  • 技术积分: 960
  • 用 户 组: 普通用户
  • 注册时间: 2009-08-21 19:38
文章分类

全部博文(92)

文章存档

2010年(71)

2009年(21)

我的朋友

分类: 嵌入式

2009-08-24 21:49:31

Among several inter-process communication, I mainly have a insight into the pipe, named pipe and socket
 
Introduction of linux Several inter-process communication:

Pipe and named pipe: pipe can only be used to communicate between related process
                     named pipe however overcome this limit, it also allows unrelated inter-process communication;


Signal (Signal): signal is more complex means of communication used to notify the receiving process that a certain event occurs, except for inter-process communication, the process can also send a signal to the process itself; linux not only supports the early signs of Unix semantics function sigal , but also supports the standard semantics in line with Posix. signal function sigaction (In fact, the function is based on BSD, BSD use sigaction function to re-implement the signal function in order to achieve reliable and signal mechanism and unify the external interface);


Message Queue (MSMQ): Message Queuing is a message link table, including Posix message queue system V message queue. A process with sufficient permission can add messages to the queue.If a process of reading was given permission, it can read the message queue. Message queue to overcome the limit that the signal carrys small amount of information, pipes can only carry non-byte-stream format,and the small size of the buffer

Shared Memory: allow several processes access the same piece of memory space, it is the fastest form of IPC available. Against other communication mechanisms designed to lower operating efficiency. It is often associated with other communication mechanisms, such as semaphores, to achieve inter-process synchronization and mutual exclusion.

Semaphore: primarily as a process, and the mean of synchronization between different threads.


Socket: a more general inter-process communication mechanism that can be used in different inter-process communication between machines. Originally developed by the BSD branch of Unix systems developed, but now can generally be ported to other Unix-systems: Linux and System V variants support sockets.


1.1 The key concepts of pipe
Pipe is one of the first Unix IPC form Linux supports , it has following characteristics:
Pipe is half-duplex, data can only flow in one direction; requires both sides to communicate, you need to build two pipe lines;
Be used only for brothers, father and son process or processes (with the process of kinship);
Constitute a separate stand-alone file system: pipes for the pipe at both ends of the process is concerned, is a file, but it is not an ordinary file, it does not belong to a particular file system, but the own company, constitute a separate file system, and only existence in memory.
The data read and write: a process to write the contents of the pipe to pipe the other end of the process of reading. Write the contents of each are added at the end of the buffer in the pipe, and each time the head of sensed data from the buffer zone.

1.2 channels to create:
# include
int pipe (int fd [2])
 
 
The function of the pipeline to create a process that ends in the middle, in practical applications there is not much sense, therefore, after creating a pipe, we generally fork a child process, and a communication between father and son will be set through a pipe (therefore it is not difficult to introduce, as long as the two processes exist in kinship, kinship here refers to a common ancestor, can be the use of piped approaches to communication).
 
1.3 channels to read and write rules:
Pipe ends were used to describe the characters fd [0] and fd [1] to describe the need to note that the pipeline is fixed at both ends of the task. That the end can only be used for reading, from the description of the word fd [0] said, calling for the read-side pipe; the other end can only be used to write the word from the description of fd [1] to represent, calling for the pipe to write side. If you try to read data from the pipe end to write, or write data to the read-side pipe will cause an error. General file I/O functions can be used for pipes, such as close, read, write and so on.
Read data from the pipeline:
If the write end of pipe does not exist, that at the end of the data has been read, read the function returns number of bytes read is 0;
When the write end of pipe exists, if the request is greater than the number of bytes PIPE_BUF, then returned in the existing data pipelines the number of bytes, if the request is not greater than the number of bytes PIPE_BUF, then return to the pipeline of existing data bytes number (At this point, the pipeline is less than the requested amount of data the amount of data); or return the requested number of bytes (At this point, the pipeline is not less than the requested amount of data the amount of data). Note: (PIPE_BUF in include / linux / limits.h defined, different kernel versions may be different. Posix.1 request PIPE_BUF at least 512 bytes, red hat 7.2 for 4096).
Read the rules on the pipeline verification:
 
 
# include
# include
# include
main ()
(
         int pipe_fd [2];
         pid_t pid;
         char r_buf [100];
         char w_buf [4];
         char * p_wbuf;
         int r_num;
         int cmd;
       
         memset (r_buf, 0, sizeof (r_buf));
         memset (w_buf, 0, sizeof (r_buf));
         p_wbuf = w_buf;
         if (pipe (pipe_fd) <0)
         (
                 printf ( "pipe create error \ n");
                 return -1;
         )
       
         if ((pid = fork ())== 0)
         (
                 printf ( "\ n");
                 close (pipe_fd [1]);
                 sleep (3); / / ensure that the parent process, close the write side
             r_num = read (pipe_fd [0], r_buf, 100);
printf ( "read num is% d the data read from the pipe is% d \ n", r_num, atoi (r_buf));
               
                 close (pipe_fd [0]);
                 exit ();
         )
         else if (pid> 0)
         (
         close (pipe_fd [0 ]);// read
         strcpy (w_buf, "111");
         if (write (pipe_fd [1], w_buf, 4)! =- 1)
                 printf ( "parent write over \ n");
         close (pipe_fd [1 ]);// write
                 printf ( "parent close fd [1] over \ n");
         sleep (10);
         )
)
 

2.1 The key concepts of the FIFO
Pipe applications has a major constraint that it does not has a name, therefore, it only be used with a kinship of inter-process communication, so named pipe (named pipe or FIFO) is proposed, the restriction has been overcome. FIFO is different from the pipeline that it provides a path name associated with it, in order that FIFO file exists in the form of file system. In this way, even if the process does not exist it can create FIFO, the process of kinship, as long as you can access the path, they can communicate with each other with each other via FIFO (be able to access the path of the process and the creation of processes FIFO), so that, through the FIFO is not related to The process will also be able to exchange data. It is noteworthy that, FIFO strictly follow the FIFO (first in first out), for pipes and FIFO is always read from the beginning to return data, they put the data added to the end of the writing. They do not support, such as lseek () and other documents positioning operation.

2.2 The creation of the FIFO
# include
# include
int mkfifo (const char * pathname, mode_t mode)
 
 
The function's first parameter is a common path name, which is created FIFO's name. The second parameter with the open common file open () function of the mode parameters are the same. If the mkfifo The first parameter is a path name already exists, it will return EEXIST error, it is generally typical of the calling code will first check whether to return the error, if it does return the error, then open the FIFO as long as the function call can be a . General file I / O functions can be used for FIFO, such as close, read, write and so on.

2.3 FIFO open rules
Named pipe pipe more than one open operation: open.
Open FIFO rule:
If the current open operation is to read and open the FIFO, if the corresponding process has been to write and open the FIFO, then the current open operation will successfully return; Otherwise, it may block until the corresponding process for writing and open the FIFO (currently open operation set the blocking flag); or a successful return (the current open operation is not set blocking flag).
If the current open operation is to write and open the FIFO, if you already have the corresponding process for reading and open the FIFO, then the current open operation will successfully return; Otherwise, it may block until the corresponding process for reading and open the FIFO (currently open operation set the blocking flag); or, to return ENXIO error (currently open operation is not set blocking flag).
See validation rules on the opening attached 2.

2.4 FIFO read and write the rules
Read from the FIFO data:
Convention: If a process in order to read data from the FIFO block opens FIFO, so that read operations within the process set the blocking flag for the read operation.
If there is the process of writing to open FIFO, and currently there is no data within the FIFO, then set the blocking flag for the read operation, the will remain blocked. For the blocking flag is not set for the read operation returns -1, the current errno value of EAGAIN, reminding try again later.
For the blocked flag is set, said read operation, resulting in obstruction for two reasons: the current FIFO data inside, but there are other processes in reading these data; the other is that there is no data within the FIFO. Solution blocking reason is FIFO, a new data is written, regardless of the size of the amount of data to write the letter, and regardless of how much the amount of data read operation request.
Read the open block mark only the first read operation of this process, to exert the role, if this process has a number of read operation sequence, then the first read operation is awakened and complete the read operation, the other would be to perform read operations will no longer block , even in the implementation of the reading operation, FIFO there is no data in the same (in this case, read operation returns 0).
If there is no process to write to open FIFO, blocking flag is set to block read operations.
Note: If the FIFO contains data, you set the blocking flag FIFO read operation will not be less than the requested number of bytes in the number of bytes read and the blocking, this time, read operations will return the amount of data available in FIFO .
Writes to the FIFO data:
Convention: If a process in order to write data to the FIFO block opens FIFO, it said the write operation within the process to set the blocking flag for the write operation.
Set the blocking flag for the write operation:
When the amount of data to be written not more than PIPE_BUF when, linux will guarantee write atomicity. If the channel is idle at this time the buffer can not accommodate the number of bytes to write, then go to sleep, until when the buffer can accommodate the number of bytes to be written only when starting a one-time write operation.
When you want to write more than PIPE_BUF when the amount of data, linux will no longer be written to ensure atomicity. FIFO buffer has a free area, writing process would attempt to write data to the pipeline, write operation is finished all requests to write the data back.
Blocking flag is not set for write operations:
When you want to write more than PIPE_BUF when the amount of data, linux will no longer be written to ensure atomicity. Filled with all the free buffers in the FIFO, the write operation returns.
When the amount of data to be written not more than PIPE_BUF when, linux will guarantee write atomicity. If the current idle FIFO buffer can accommodate the number of bytes requested to write after finishing the essay successfully return; free FIFO buffer if the current request can not be written to accommodate the number of bytes, then returned EAGAIN error, write to remind the future;
 
Procedure 1: Write FIFO procedures
# include
# include
# include
# include
# define FIFO_SERVER "/ tmp / fifoserver"
main (int argc, char ** argv)
/ / Parameter for the forthcoming number of bytes to write
(
         int fd;
         char w_buf [4096 * 2];
         int real_wnum;
         memset (w_buf, 0,4096 * 2);
         if ((mkfifo (FIFO_SERVER, O_CREAT | O_EXCL) <0) & & (errno! = EEXIST))
                 printf ( "cannot create fifoserver \ n");
         if (fd ==- 1)
                 if (errno == ENXIO)
                         printf ( "open error; no reading process \ n");
               
         fd = open (FIFO_SERVER, O_WRONLY | O_NONBLOCK, 0);
         / / Set non-blocking flag
         / / fd = open (FIFO_SERVER, O_WRONLY, 0);
         / / Set blocking flag
         real_wnum = write (fd, w_buf, 2048);
         if (real_wnum ==- 1)
         (
                 if (errno == EAGAIN)
                         printf ( "write to fifo error; try later \ n");
         )
         else
                 printf ( "real write num is% d \ n", real_wnum);
         real_wnum = write (fd, w_buf, 5000);
         / / 5000 is used to test more than 4096 bytes when writing the non-atomicity
         / / real_wnum = write (fd, w_buf, 4096);
         / / 4096 is used to test not more than 4096 bytes to write atomicity when
       
         if (real_wnum ==- 1)
                 if (errno == EAGAIN)
                         printf ( "try later \ n");
)
 
 
 
3. Socket:
Socket for Linux is currently the most widely used kind of inter-process communication mechanism, The difference between other communication mechanisms is that inter-process communication can not only be made within a single machine but also different machine. However, because it does not support overtime and waiting for treatment, it can not be directly used for multi-process between the real-time communication.
Here introduces a multi-Socket-based communication between different processes. Its principle is to set up a process used as a communication server which can relay the communication between different processes. It first start a listening Socket to monitor the connection. And add its Descriptor number into defined fd_set ally, this fd_set ally is used to save listening Socket and the communication Socket Descriptor number formed later. Server use system call select to timely check whether data reaches this listening Socket. If there exists data, the side of custom must have set a connection request, then forming a new communication Socket to connect the custom, and add the Socket descriptor number into fd_set ally. Then check the new custom ID with the Socket descriptor number recorded in a ID register table.  If there is data reach a certain communication Socket, then this must be a client-initiated communication request, read data and remove Shouxin the client ID number, the ID registration form found in corresponding Socket description number, the data sent to the corresponding Socket through Shouxin the client.
All other processes as a client (client). Client's action is to first establish communications Socket connect to the server-side, and then carried out through correspondence Socket messenger and receiver.
 
The following specific procedures are given to descripe
First, the procedure is given Server-side, where there are two hypothetical clients to conduct real-time communication, ClientA send to characters 1 ClientB, ClientB send to characters 2 ClientA .
 
   # include
# include
# include
# include
# include
# include
# include
# include
int main ()
(
         int rcd;
         struct sockaddr_un server_sockaddr;
         int backlog;
         ushort ci;
         int watch_fd_list [3];
         fd_set catch_fd_set;
         fd_set watchset;
         int new_cli_fd;
         int maxfd;
         int socklen, server_len;
         struct sockaddr_un cli_sockaddr;
         struct (
                 char module_id;
                 int cli_sock_fd;
         ) Cli_info_t [2];
       
         for (ci = 0; ci <= 1; ci + +)
                 cli_info_t [ci]. cli_sock_fd =- 1;
               
         for (ci = 0; ci <= 2; ci + +)
                 watch_fd_list [ci] =- 1;
               
         int server_sockfd, client_sockfd;
       
         server_sockfd = socket (AF_UNIX, SOCK_STREAM, 0);
         server_sockaddr.sun_family = AF_UNIX;
         strcpy (server_sockaddr.sun_path, "server_socket");
         server_len = sizeof (server_sockaddr);
         rcd = bind (server_sockfd, (struct sockaddr *) & server_sockaddr, server_len);
       
         backlog = 5;
         rcd = listen (server_sockfd, backlog);
         printf ( "SERVER:: Server is waitting on socket =% d \ n", server_sockfd);
         watch_fd_list [0] = server_sockfd;
         FD_ZERO (& watchset);
         FD_SET (server_sockfd, & watchset);
         maxfd = watch_fd_list [0];
       
 

 
In the above procedure, Server generates listening Socket (server_sockfd), initialize Socket watch collection (watchset), and will add listening Socket into the Socket surveillance collection.
 
                   while (1) (
                 char ch;
                 int fd;
                 int nread;
               
                 catch_fd_set = watchset;
                 rcd = select (maxfd +1, & catch_fd_set, NULL, NULL, (struct tim *) 0);
               
 

 
In the above procedure, Server using select system calls the function checks whether there is data existing in any one of the monitoring socket ally.
 
                           if (rcd <0) (
                         printf ( "SERVER:: Server 5 \ n");
                         exit (1);
                 )
                 if (FD_ISSET (server_sockfd, & catch_fd_set)) (
                         socklen = sizeof (cli_sockaddr);
                         new_cli_fd = accept (server_sockfd, (struct sockaddr *) & (cli_sockaddr), & socklen);
                         printf ( "SERVER:: open communication with Client% s on socket% d \ n", cli_sockaddr.sun_path, new_cli_fd);
       
                         for (ci = 1; ci <= 2; ci + +) (
                                 if (watch_fd_list [ci]! = -1) continue;
                                 else (
                                         watch_fd_list [ci] = new_cli_fd;
                                         break;
                                 )
                         )
                         FD_SET (new_cli_fd, & watchset);
                         if (maxfd                                  maxfd = new_cli_fd;
                         )
                       
                         for (ci = 0; ci <= 1; ci + +) (
                                 if (cli_info_t [ci]. cli_sock_fd == -1) (
                                         cli_info_t [ci]. module_id = cli_sockaddr.sun_path [0];
                                         cli_info_t [ci]. cli_sock_fd = new_cli_fd;
                                         break;
                                 )
                         )
                               
                         continue;
                 )
               
 

 
In the above procedure, Server uses system call function FD_ISSET to check whether there is a client connection requests arriving Listening Socket, if the return value is greater than 0, Server generates a new communications Socket (new_cli_fd) for client to connect. The new generation into the Socket Communications Socket watch collection (FD_SET). The client's information (ID number and Socket description number) stored in the register table cli_info_t
 
           for (ci = 1; ci <= 2; ci + +) (
                         int dst_fd = -1;
                         char dst_module_id;
                         char src_module_id;
                         int i;
                         if (watch_fd_list [ci] ==- 1) continue;
                         if (! FD_ISSET (watch_fd_list [ci], & catch_fd_set)) (
                                 continue;
                         )
                         ioctl (watch_fd_list [ci], FIONREAD, & nread);
                         if (nread == 0) (
                                 continue;
                         )
                         read (watch_fd_list [ci], & dst_module_id, 1);
                         for (i = 0; i <= 1; i + +) (
                                 if (cli_info_t [i]. module_id == dst_module_id)
                                         dst_fd = cli_info_t [i]. cli_sock_fd;
                                  if (cli_info_t [i]. cli_sock_fd == watch_fd_list [ci])
                                 src_module_id = cli_info_t [i]. module_id;
                         )
                         read (watch_fd_list [ci], & ch, 1);
                         printf ( "SERVER:: char =% c to Client% c on socket% d \ n", ch, dst_module_id, dst_fd);
                         write (dst_fd, & src_module_id, 1);
                         write (dst_fd, & ch, 1);
                 )
         )
)
 

 
In the above program, if there is data to reach a certain communication Socket, Server, and then read data out Shouxin the client ID. In the ID registration form found in the corresponding client Shouxin Socket description number. Socket will be sent to the data through the corresponding client Shouxin
The procedure is given the client ClientA
ClientB program just char dst_module_id = 'B'; replaced by char dst_module_id = 'A'; char ch = '1 '; replaced by char char ch = '2'; can.
 
# include
# include
# include
# include
# include
# include
# include
int main () (
       
         int client_sockfd;
         int len;
         struct sockaddr_un server_sockaddr, cli_sockaddr;
         int result;
         char dst_module_id = 'B';
         char ch = '1 ';
         char src_module_id;
       
       
         client_sockfd = socket (AF_UNIX, SOCK_STREAM, 0);
       
         cli_sockaddr.sun_family = AF_UNIX;
         strcpy (cli_sockaddr.sun_path, "A");
         bind (client_sockfd, (struct sockaddr *) & cli_sockaddr, sizeof (cli_sockaddr));
         server_sockaddr.sun_family = AF_UNIX;
         strcpy (server_sockaddr.sun_path, "server_socket");
         len = sizeof (server_sockaddr);
       
         result = connect (client_sockfd, (struct sockaddr *) & server_sockaddr, len);
         if (result <0) (
                 printf ( "ClientA:: error on connecting \ n");
                 exit (1);
         )
       
         printf ( "ClientA:: succeed in connecting with server \ n");
         sleep (10);
         write (client_sockfd, & dst_module_id, 1);
         write (client_sockfd, & ch, 1);
         read (client_sockfd, & src_module_id, 1);
         read (client_sockfd, & ch, 1);
         printf ( "ClientA:: char from Client% c =% c \ n", src_module_id, ch);
         close (client_sockfd);
       
)
 

 
The following are the results of a sample implementation of the procedures
 
[root @ zhou test] #. / server &
[3] 4301
[root @ zhou test] # SERVER:: Server is waitting on socket = 3
. / clientA &. / clientB &
[4] 4302
[5] 4303
ClientA:: succeed in connecting with server
  SERVER:: open communication with Client A on socket 4
[root @ zhou test] # SERVER:: open communication with Client B on socket 5
ClientB:: succeed in connecting with server
SERVER:: char = 1 to Client B on socket5
ClientB:: char from Client A = 1
SERVER:: char = 2 to Client A on socket4
ClientA:: char from Client B = 2
 
Reference: "Linux application development technology explain"
 
阅读(1738) | 评论(0) | 转发(0) |
给主人留下些什么吧!~~