1. 共享内存
#include
#include
#include
int main ()
{
int segment_id;
char* shared_memory;
struct shmid_ds shmbuffer;
int segment_size;
const int shared_segment_size = 0x6400;
/* Allocate a shared memory segment. */
segment_id = shmget (IPC_PRIVATE, shared_segment_size, IPC_CREAT | IPC_EXCL | S_IRUSR | S_IWUSR);
/* Attach the shared memory segment. */
printf ("the segment_id: %d/n", segment_id);
shared_memory = (char*) shmat (segment_id, 0, 0);
printf ("shared memory attached at address %p/n", shared_memory);
/* Determine the segment’s size. */
shmctl (segment_id, IPC_STAT, &shmbuffer);
segment_size = shmbuffer.shm_segsz;
printf ("segment size: %d/n", segment_size);
/* Write a string to the shared memory segment. */
sprintf (shared_memory, "Hello, world.");
/* Detach the shared memory segment. */
shmdt (shared_memory);
/* Reattach the shared memory segment, at a different address. */
shared_memory = (char*) shmat (segment_id, (void*) 0x5000000, 0);
printf ("shared memory reattached at address %p/n", shared_memory);
/* Print out the string from shared memory. */
printf ("%s/n", shared_memory);
/* Detach the shared memory segment. */
shmdt (shared_memory);
/* Deallocate the shared memory segment. */
shmctl (segment_id, IPC_RMID, 0);
return 0;
}
2. mapped memory
#include
#include
#include
#include
#include
#include
#include
#define FILE_LENGTH 0x100
/* Return a uniformly random number in the range [low, high]. */
int random_range (unsigned const low, unsigned const high)
{
unsigned const range = high - low + 1;
return low + (int)(((double) range) * rand() / (RAND_MAX + 1.0));
}
int main (int argc, char* const argv[])
{
int fd;
void* file_memory;
/* Seed the random number generator. */
srand (time (NULL));
/* Prepare a file large enough to hold an unsigned integer. */
fd = open (argv[1], O_RDWR | O_CREAT, S_IRUSR | S_IWUSR);
lseek (fd, FILE_LENGTH+1, SEEK_SET);
write (fd, "", 1);
lseek (fd, 0, SEEK_SET);
/* Create the memory mapping. */
file_memory = mmap (0, FILE_LENGTH, PROT_WRITE, MAP_SHARED, fd, 0);
close (fd);
/* Write a random integer to memory-mapped area. */
sprintf((char*) file_memory, "%d/n", random_range (-100, 100));
/* Release the memory (unnecessary because the program exits). */
munmap (file_memory, FILE_LENGTH);
return 0;
}
3. Pipes (管道)
管道是一种允许单向通讯的通讯设备. 数据写入写入端, 而从读出端读出. 数据以写入时的相应顺序被读出. 典型的,管道可以用于 一个进程中的两个线程 或 父进程和子进程之间 的通讯. 管道具有以下特性---1 管道的数据容量是有限的. 在写数据的时候, 如果没有空间可写, 那么写进程被阻塞, 直到有空间; 同样读数据的时候, 如果没有数据,都进程同样被阻塞, 知道有数据可读. 因此 管道是自动同步两个进程的 (写进程 和 读进程). 2 对于管道文件描述符的调用, 只有在创建它的进程及子进程中才是有效的. 一个进程的文件描述符是不能够传递给不相关进程的. 然而当一个进程调用 fork 时, 文件描述符被拷贝到子进程. 因此, 管道只能链接有关系的进程.
以下是个应用示例:
#include
#include
#include
/* Write COUNT copies of MESSAGE to STREAM, pausing for a second between each. */
void writer (const char* message, int count, FILE* stream)
{
for (; count > 0; --count) {
printf ("In writer function. /n");
/* Write the message to the stream, and send it off immediately. */
fprintf (stream, "%s/n", message);
fflush (stream);
/* Snooze a while. */
sleep (1);
}
}
/* Read random strings from the stream as long as possible. */
void reader (FILE* stream)
{
char buffer[1024];
/* Read until we hit the end of the stream. fgets reads until
either a newline or the end-of-file. */
while (!feof (stream)
&& !ferror (stream)
&& fgets (buffer, sizeof (buffer), stream) != NULL){
printf ("===/n");
fputs (buffer, stdout);
printf ("In reader function./n");
}
}
int main ()
{
int fds[2];
pid_t pid;
/* Create a pipe. File descriptors for the two ends of the pipe are
placed in fds. */
pipe (fds);
/* Fork a child process. */
pid = fork ();
if (pid == (pid_t) 0) {
FILE* stream;
printf ("In the child process. /n");
/* This is the child process. Close our copy of the write end of
the file descriptor. */
close (fds[1]);
/* Convert the read file descriptor to a FILE object, and read
from it. */
stream = fdopen (fds[0], "r");
reader (stream);
close (fds[0]);
}
else {
/* This is the parent process. */
FILE* stream;
printf ("In the parent process. /n");
/* Close our copy of the read end of the file descriptor. */
close (fds[0]);
/* Convert the write file descriptor to a FILE object, and write
to it. */
stream = fdopen (fds[1], "w");
writer ("Hello, world.", 5, stream);
close (fds[1]);
}
return 0;
}
应用中的一种情况: 重定向标准 输入, 输出 和 错误流
你经常可能遇到创建一个子进程, 然后把管道的一端作为它的标准输入 或 输出. 调用 dup2 , 你可以把一个文件描述符 和 另一个文件描述符等同起来. 例如, 把一个进程的标准输入重定向到一个文件描述符 fd, 可以这样做:
dup2 (fd, STDIN_FILENO);
#include
#include
#include
#include
int main ()
{
int fds[2];
pid_t pid;
/* Create a pipe. File descriptors for the two ends of the pipe are
placed in fds. */
pipe (fds);
/* Fork a child process. */
pid = fork ();
if (pid == (pid_t) 0) {
/* This is the child process. Close our copy of the write end of
the file descriptor. */
close (fds[1]);
/* Connect the read end of the pipe to standard input. */
dup2 (fds[0], STDIN_FILENO);
/* Replace the child process with the “sort” program. */
execlp ("sort", "sort", 0);
}
else {
/* This is the parent process. */
FILE* stream;
/* Close our copy of the read end of the file descriptor. */
close (fds[0]);
/* Convert the write file descriptor to a FILE object, and write
to it. */
stream = fdopen (fds[1], "w");
fprintf (stream, "This is a test./n");
fprintf (stream, "Hello, world./n");
fprintf (stream, "My dog has fleas./n");
fprintf (stream, "This program is great./n");
fprintf (stream, "One fish, two fish./n");
fflush (stream);
close (fds[1]);
/* Wait for the child process to finish. */
waitpid (pid, NULL, 0);
}
return 0;
}
针对以上应用 (从子进程接受数据 或 向子进程发送数据) 有种更为简单的方法,利用 popen, pclose 方法.
#include
#define MAXSTRS 5
int main(void)
{
int cntr;
FILE *pipe_fp;
char *strings[MAXSTRS] = {"echo", "bravo", "alpha", "charlie", "delta"};
/* Create one way pipe line with call to popen() */
if((pipe_fp = popen("sort", "w")) == NULL)
{
perror("popen");
exit(1);
}
/* Processing loop */
for(cntr=0; cntr fputs(strings[cntr], pipe_fp);
fputc('/n', pipe_fp);
}
/* Close the pipe */
pclose(pipe_fp);
return(0);
}
popen ("sort", "w") 创建一个子进程执行 sort 命令, "w" 参数表明, 此进程想要发送数据给子进程. popen 返回管道的一端, 另一端被连接到子进程的标准输入端. 当写操作完成的时候, pclose 关闭了子进程的流, 等待子进程的结束. 如果第二个参数是 "r" , 那么popen返回子进程的标准输出流, 父进程就可以从此流读出数据. 如果有错误发生, popen 将会返回 NULL 指针.
4 FIFOs
A first-in, first-out (FIFO) file is a pipe that has a name in the filesystem. 任何进程都可以打开或关闭 FIFO; 管道两端的进程不需要有关系 (例如, 父子关系). FIFOs 亦可称作 named pipes (命名管道). 一个 FIFO 可以有多个 reader 或 writer.
#include
#include
#include
#include
]
#include
#define FIFO_FILE "MYFIFO"
int main(void)
{
FILE *fp;
char readbuf[80];
/* Create the FIFO if it does not exist */
umask(0);
mknod(FIFO_FILE, S_IFIFO|0666, 0);
while(1)
{
printf("i am zhaoyognliang!/n");
fp = fopen(FIFO_FILE, "r");
fgets(readbuf, 80, fp);
printf("Received string: %s/n", readbuf);
fclose(fp);
}
return(0);
}
#include
#include
#define FIFO_FILE "MYFIFO"
int main(int argc, char* argv[])
{
FILE *fp;
if(argc!=2){
printf("USAGE:fifoclient [string]/n");
exit(1);
}
if(NULL == (fp = fopen(FIFO_FILE, "w"))){
perror("fopen");
exit(1);
}
fputs(argv[1], fp);
fclose(fp);
return(0);
}
5. Sockets
Socket 是一个双向通信设备,可以用来和在同一机器或是不同机器上的进程通信. 当创建socket的时候, 你必须指定三个参数: communication style, namespace, and protocol. communication style 控制socket怎样对待传输数据 和 定义通讯伙伴的数量. 当数据通过socket发送的时候, 数据被分割成一块块. (packets) Communication style 决定这些数据包怎么被处理 以及是怎么标识的. 有两种communication style: 1. Connection 2. Datagram .( 具体含义请查阅其它文献资料.) For the communication style parameter, useconstants beginning with SOCK_. Use SOCK_STREAM for a connection-style socket, or use SOCK_DGRAM for a datagram-style socket.
namespace 定义socket地址怎么书写. 有两种namespace : 1 local namespace. 2 internet namespace. For the namespace parameter, use constants beginning with PF_ (abbreviating“protocol families”). For example, PF_LOCAL or PF_UNIX specifies the local namespace,and PF_INET specifies Internet namespaces.
protocol 指定数据如何传输. 有以下协议: 1. TCP/IP 2. AppleTalk network protocol 3. UNIX local communication protocol.
Related System Calls:
socket—Creates a socket
closes—Destroys a socket
connect—Creates a connection between two sockets
bind—Labels a server socket with an address
listen—Configures a socket to accept conditions
accept—Accepts a connection and creates a new socket for the connection
注意: 只有运行在同一机器上的进程才能用 local namespace sockets 进行通信.
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/socket.h>
#include <sys/un.h>
#include <unistd.h>
/* Read text from the socket and print it out. Continue until the
socket closes. Return nonzero if the client sent a “quit”
message, zero otherwise. */
int server (int client_socket)
{
while (1) {
int length;
char* text;
/* First, read the length of the text message from the socket. If
read returns zero, the client closed the connection. */
if (read (client_socket, &length, sizeof (length)) == 0)
return 0;
/* Allocate a buffer to hold the text. */
text = (char*) malloc (length);
/* Read the text itself, and print it. */
read (client_socket, text, length);
printf ("%s/n", text);
/* If the client sent the message “quit,” we’re all done. */
if (!strcmp (text, "quit")){
free (text);
return 1;
}
/* Free the buffer. */
free (text);
}
}
int main (int argc, char* const argv[])
{
const char* const socket_name = argv[1];
int socket_fd;
struct sockaddr_un name;
int client_sent_quit_message;
/* Create the socket. */
socket_fd = socket (PF_LOCAL, SOCK_STREAM, 0);
/* Indicate that this is a server. */
name.sun_family = AF_LOCAL;
strcpy (name.sun_path, socket_name);
bind (socket_fd, &name, SUN_LEN (&name));
/* Listen for connections. */
listen (socket_fd, 5);
/* Repeatedly accept connections, spinning off one server() to deal
with each client. Continue until a client sends a “quit” message. */
do {
struct sockaddr_un client_name;
socklen_t client_name_len;
int client_socket_fd;
/* Accept a connection. */
client_socket_fd = accept (socket_fd, &client_name, &client_name_len);
/* Handle the connection. */
client_sent_quit_message = server (client_socket_fd);
/* Close our end of the connection. */
close (client_socket_fd);
}
while (!client_sent_quit_message);
/* Remove the socket file. */
close (socket_fd);
unlink (socket_name);
return 0;
}
#include <stdio.h>
#include <string.h>
#include <sys/socket.h>
#include <sys/un.h>
#include <unistd.h>
/* Write TEXT to the socket given by file descriptor SOCKET_FD. */
void write_text (int socket_fd, const char* text)
{
/* Write the number of bytes in the string, including
NUL-termination. */
int length = strlen (text) + 1;
write (socket_fd, &length, sizeof (length));
/* Write the string. */
write (socket_fd, text, length);
}
int main (int argc, char* const argv[])
{
const char* const socket_name = argv[1];
const char* const message = argv[2];
int socket_fd;
struct sockaddr_un name;
/* Create the socket. */
socket_fd = socket (PF_LOCAL, SOCK_STREAM, 0);
/* Store the server’s name in the socket address. */
name.sun_family = AF_LOCAL;
strcpy (name.sun_path, socket_name);
/* Connect the socket. */
connect (socket_fd, &name, SUN_LEN (&name));
/* Write the text on the command line to the socket. */
write_text (socket_fd, message);
close (socket_fd);
return 0;
}