简明 Linux 系统编程 🐧
即 Linux 环境下的应用程序开发,开发环境 Ubuntu22
常用命令:man
Linux Programmer’s Manual
基本概念
程序:源代码、指令(静态)
进程:运行着的程序(动态)
线程:线程从属于进程,一个进程可以有多个线程,线程之间共享进程的资源
任务:具体要做的事情
1 2 3 4 5 6 7 8 9 10 11 12 13 #include <sys/types.h> #include <unistd.h> #include <stdio.h> int main () { pid_t pid; while (1 ) { printf ("pid = %d\n" , getpid()); printf ("ppid = %d\n" , getppid()); sleep(1 ); } return 0 ; }
pstree -p
查看系统进程树
创建进程 1 2 3 4 5 6 7 8 9 10 11 12 #include <sys/types.h> #include <unistd.h> #include <stdio.h> int main () { pid_t pid; pid = fork(); printf ("pid = %d\n" , pid); printf ("Hello world\n" ); return 0 ; }
1 2 3 4 5 6 7 8 9 10 11 #include <sys/types.h> #include <unistd.h> #include <stdio.h> int main () { pid_t pid1, pid2; pid1 = fork(); pid2 = fork(); printf ("pid1 = %d, pid2 = %d\n" , pid1, pid2); return 0 ; }
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 #include <sys/types.h> #include <unistd.h> #include <stdio.h> int main () { pid_t pid; int count = 0 ; pid = fork(); if (pid > 0 ) { for (int i = 0 ; i < 10 ; ++i) { printf ("hello world, count = %d\n" , count++); sleep(1 ); } } else if (pid == 0 ) { while (1 ) { printf ("gooood, count = %d\n" , count++); sleep(3 ); } } else { perror("fork" ); } return 0 ; }
监控子进程 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 #include <sys/types.h> #include <sys/wait.h> #include <stdio.h> #include <stdlib.h> #include <unistd.h> int main (int argc, char *argv[]) { pid_t child_pid; int numDead; int i; for (i = 1 ; i < argc; ++i) { switch (fork()) { case -1 : perror("fork()" ); exit (1 ); case 0 : printf ("Child %d started with PID = %d, sleeping %s\n" , i, getpid(), argv[i]); sleep(atoi(argv[i])); exit (0 ); default : break ; } } numDead = 0 ; while (1 ) { child_pid = wait(NULL ); if (child_pid == -1 ) { printf ("No more children, Byebye!\n" ); exit (0 ); } ++numDead; printf ("wait() return child PID %d(numDead = %d)\n" , child_pid, numDead); } return 0 ; }
创建线程 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 #include <pthread.h> #include <stdio.h> #include <unistd.h> #include <stdlib.h> void *thread_funciton (void *) ;int main () { pthread_t pthread; int ret; int count = 5 ; ret = pthread_create(&pthread, NULL , thread_funciton, &count); if (ret != 0 ) { perror("pthread_create" ); exit (1 ); } pthread_join(pthread, NULL ); printf ("The thread is over, process is over too. \n" ); return 0 ; } void *thread_funciton (void *arg) { int i; printf ("Thread begins running\n" ); for (i = 0 ; i < *(int *)arg; ++i) { printf ("Hello world\n" ); sleep(1 ); } return NULL ; }
线程数据共享 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 #include <pthread.h> #include <stdio.h> #include <unistd.h> #include <stdlib.h> void *thread1_funciton (void *) ;void *thread2_funciton (void *) ;int count = 0 ;int main () { pthread_t pthread1, pthread2; int ret; ret = pthread_create(&pthread1, NULL , thread1_funciton, NULL ); if (ret != 0 ) { perror("pthread1_create" ); exit (1 ); } ret = pthread_create(&pthread2, NULL , thread2_funciton, NULL ); if (ret != 0 ) { perror("pthread2_create" ); exit (1 ); } pthread_join(pthread1, NULL ); pthread_join(pthread2, NULL ); printf ("The thread is over, process is over too. \n" ); return 0 ; } void *thread1_funciton (void *arg) { printf ("Thread1 begins running\n" ); while (1 ) { printf ("Thread1 count = %d\n" , count++); sleep(1 ); } return NULL ; } void *thread2_funciton (void *arg) { printf ("Thread2 begins running\n" ); while (1 ) { printf ("Thread2 count = %d\n" , count++); sleep(1 ); } return NULL ; }
管道通信 无名管道 无名管道只适用于有“亲缘关系”的进程
创建管道
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 #include <unistd.h> #include <sys/types.h> #include <stdio.h> int main () { int fd[2 ]; int pid; if (pipe(fd) == -1 ) { perror("pipe" ); } pid = fork(); if (pid > 0 ) { close(fd[0 ]); sleep(5 ); write(fd[1 ], "ab" , 2 ); } else if (pid == 0 ) { char ch[2 ]; printf ("Child process is waiting for data:\n" ); close(fd[1 ]); read(fd[0 ], ch, 2 ); printf ("Read from pipe: %s" , ch); } return 0 ; }
管道大小
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 #include <unistd.h> #include <sys/types.h> #include <stdio.h> #include <sys/wait.h> int main () { pid_t pid; int fd[2 ]; if (pipe(fd) == -1 ) { perror("pipe" ); } pid = fork(); if (pid == 0 ) { int n = 0 ; char ch = '*' ; close(fd[0 ]); while (1 ) { write(fd[1 ], &ch, 1 ); printf ("count = %d\n" , ++n); } } else if (pid > 0 ) { waitpid(pid, NULL , 0 ); } return 0 ; }
管道交互
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 #include <unistd.h> #include <sys/types.h> #include <stdio.h> #include <sys/wait.h> int main () { pid_t pid; int fd[2 ]; if (pipe(fd) == -1 ) { perror("pipe" ); } pid = fork(); if (pid == 0 ) { char tmp[100 ]; close(fd[0 ]); while (1 ) { scanf ("%s" , tmp); write(fd[1 ], tmp, sizeof (tmp)); } } else if (pid > 0 ) { char tmp[100 ]; close(fd[1 ]); while (1 ) { printf ("Parent process is waiting for the data from pipe. \n" ); read(fd[0 ], tmp, sizeof (tmp)); printf ("read from pipe: %s\n" , tmp); } } return 0 ; }
双向传输
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 #include <unistd.h> #include <sys/types.h> #include <stdio.h> #include <sys/wait.h> #include <string.h> #include <ctype.h> int main () { pid_t pid; int fd[2 ]; int fd2[2 ]; if (pipe(fd) == -1 ) { perror("pipe" ); } if (pipe(fd2) == -1 ) { perror("pipe2" ); } pid = fork(); if (pid == 0 ) { char tmp[100 ]; int i; close(fd[1 ]); close(fd2[0 ]); while (1 ) { memset (tmp, '\0' , sizeof (tmp)); read(fd[0 ], tmp, sizeof (tmp)); for (i = 0 ; i < sizeof (tmp); ++i) { tmp[i] = toupper (tmp[i]); } write(fd2[1 ], tmp, sizeof (tmp)); } } else if (pid > 0 ) { char tmp[100 ]; close(fd[0 ]); close(fd2[1 ]); while (1 ) { memset (tmp, '\0' , sizeof (tmp)); printf ("Parent input: " ); scanf ("%s" , tmp); write(fd[1 ], tmp, sizeof (tmp)); memset (tmp, '\0' , sizeof (tmp)); read(fd2[0 ], tmp, sizeof (tmp)); printf ("After child change: %s\n" , tmp); } } return 0 ; }
有名管道 man 3 mkfifo
mkfifo, mkfifoat - make a FIFO special file (a named pipe)
读
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 #include <stdio.h> #include <sys/stat.h> #include <sys/types.h> #include <unistd.h> #include <fcntl.h> #include <string.h> int main () { int ret; int fd; char buf[100 ]; ret = mkfifo("./my_fifo" , 0666 ); if (ret != 0 ) { perror("mkfifo" ); } printf ("Prepare reading from named pipe:\n" ); fd = open("./my_fifo" , O_RDWR); if (fd == -1 ) { perror("open" ); } while (1 ) { memset (buf, '\0' , sizeof (buf)); read(fd, buf, sizeof (buf)); printf ("Read from named pipe: %s\n" , buf); sleep(1 ); } return 0 ; }
写
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 #include <stdlib.h> #include <stdio.h> #include <sys/stat.h> #include <sys/types.h> #include <unistd.h> #include <fcntl.h> #include <string.h> int main (int argc, char *argv[]) { int fd; char buf[100 ]; fd = open("./my_fifo" , O_WRONLY, 0666 ); if (fd == -1 ) { perror("open" ); } if (argc == 1 ) { printf ("Please send something to the named pipe:\n" ); exit (EXIT_FAILURE); } strcpy (buf, argv[1 ]); write(fd, buf, sizeof (buf)); printf ("Write to the pipe: %s\n" , buf); return 0 ; }
共享内存 亲缘关系 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 #include <stdio.h> #include <sys/ipc.h> #include <sys/shm.h> #include <sys/types.h> #include <unistd.h> #include <string.h> #include <wait.h> char msg[] = "Hello world" ;int main () { int shmid; pid_t pid; shmid = shmget(IPC_PRIVATE,1024 ,IPC_CREAT | 0666 ); pid = fork(); if (pid > 0 ) { char *p_addr; p_addr = shmat(shmid, NULL , 0 ); memset (p_addr, '\0' , sizeof (msg)); memcpy (p_addr, msg, sizeof (msg)); shmdt(p_addr); waitpid(pid, NULL , 0 ); } else if (pid == 0 ) { char *c_addr; c_addr = shmat(shmid, NULL , 0 ); printf ("Child process waits a short time... \n" ); sleep(2 ); printf ("Chile process read from shared memory: %s\n" , c_addr); shmdt(c_addr); } else { perror("fork" ); } return 0 ; }
非亲缘关系 写
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 #include <stdio.h> #include <sys/ipc.h> #include <sys/shm.h> #include <unistd.h> #include <string.h> #define MY_KEY 9527 char msg[] = "Hello world" ;int main () { int shmid; shmid = shmget(MY_KEY,1024 ,IPC_CREAT | 0666 ); char *p_addr; p_addr = shmat(shmid, NULL , 0 ); memset (p_addr, '\0' , sizeof (msg)); memcpy (p_addr, msg, sizeof (msg)); shmdt(p_addr); return 0 ; }
读
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 #include <stdio.h> #include <sys/ipc.h> #include <sys/shm.h> #include <unistd.h> #include <string.h> #define MY_KEY 9527 int main () { int shmid; shmid = shmget(MY_KEY,1024 ,IPC_CREAT | 0666 ); char *c_addr; c_addr = shmat(shmid, NULL , 0 ); printf ("Read from shared memory: %s" , c_addr); shmdt(c_addr); return 0 ; }
消息队列 亲缘关系 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 #include <stdio.h> #include <sys/ipc.h> #include <sys/shm.h> #include <sys/types.h> #include <unistd.h> #include <string.h> #include <wait.h> #include <sys/msg.h> #define MY_TYPE 9527 int main () { int msgid; pid_t pid; struct msgbuf { long mtype; char mtext[100 ]; int number; }; struct msgbuf buff ; msgid = msgget(IPC_PRIVATE, IPC_CREAT|0666 ); pid = fork(); if (pid > 0 ) { sleep(1 ); buff.mtype = MY_TYPE; printf ("Please enter a string you want to send: \n" ); gets(buff.mtext); printf ("Please enter a number you want to send: \n" ); scanf ("%d" , &buff.number); msgsnd(msgid, &buff, sizeof (buff) - sizeof (buff.mtype), 0 ); waitpid(pid, NULL , 0 ); } else if (pid == 0 ) { printf ("Child process is waiting for msg...\n" ); msgrcv(msgid, &buff, sizeof (buff) - sizeof (buff.mtype), MY_TYPE, 0 ); printf ("Child process read from msg: %s, %d" , buff.mtext, buff.number); msgctl(msgid, IPC_RMID, NULL ); } else { perror("fork" ); } return 0 ; }
ipcs -q
查看到该消息队列
ipcrm -q [消息队列qid]
删除消息队列
非亲缘关系 发送
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 #include <stdio.h> #include <sys/ipc.h> #include <sys/shm.h> #include <sys/types.h> #include <unistd.h> #include <string.h> #include <wait.h> #include <sys/msg.h> #define MY_TYPE 9527 #define MY_KEY 1314 int main () { int msgid; struct msgbuf { long mtype; char mtext[100 ]; int number; }; struct msgbuf buff ; msgid = msgget(MY_KEY, IPC_CREAT|0666 ); buff.mtype = MY_TYPE; printf ("Please enter a string you want to send: \n" ); gets(buff.mtext); printf ("Please enter a number you want to send: \n" ); scanf ("%d" , &buff.number); msgsnd(msgid, &buff, sizeof (buff) - sizeof (buff.mtype), 0 ); return 0 ; }
接收
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 #include <stdio.h> #include <sys/ipc.h> #include <sys/shm.h> #include <sys/types.h> #include <unistd.h> #include <string.h> #include <wait.h> #include <sys/msg.h> #define MY_TYPE 9527 #define MY_KEY 1314 int main () { int msgid; struct msgbuf { long mtype; char mtext[100 ]; int number; }; struct msgbuf buff ; msgid = msgget(MY_KEY, IPC_CREAT|0666 ); while (1 ) { printf ("Process is waiting for msg...\n" ); msgrcv(msgid, &buff, sizeof (buff) - sizeof (buff.mtype), MY_TYPE, 0 ); printf ("Process read from msg: %s, %d\n" , buff.mtext, buff.number); } return 0 ; }
信号量 无名信号量 parenti child 进程之间的示例
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 #include <semaphore.h> #include <stdio.h> #include <unistd.h> #include <stdlib.h> #include <sys/mman.h> int main () { pid_t pid; sem_t *sem_id = NULL ; sem_id = mmap(NULL , sizeof (sem_t ), PROT_READ | PROT_WRITE, MAP_SHARED | MAP_ANONYMOUS, -1 , 0 ); sem_init(sem_id, 1 , 0 ); pid = fork(); if (pid > 0 ) { while (1 ) { sem_wait(sem_id); printf ("This is paremt process.\n" ); sleep(1 ); } } else if (pid == 0 ) { while (1 ) { printf ("This is child process.\n" ); sleep(3 ); sem_post(sem_id); } } return 0 ; }
命名信号量 非亲缘进程之间的示例
发布
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 #include <stdio.h> #include <unistd.h> #include <stdlib.h> #include <semaphore.h> #include <fcntl.h> #include <sys/stat.h> int main () { int i = 0 ; sem_t *sem = NULL ; sem = sem_open("NAMED_SEM" , O_CREAT, 666 , 0 ); while (1 ) { printf ("Process 0: i = %d\n" , i++); sleep(1 ); sem_post(sem); } return 0 ; }
等待
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 #include <stdio.h> #include <unistd.h> #include <stdlib.h> #include <semaphore.h> #include <fcntl.h> #include <sys/stat.h> int main (void ) { sem_t *sem = NULL ; int i = 0 ; sem = sem_open("NAMED_SEM" , O_CREAT, 666 , 0 ); while (1 ) { sem_wait(sem); printf ("Process 1: i = %d\n" , i++); } return 0 ; }
ls -l /dev/shm/sem.NAMED_SEM
查看权限
修改代码后运行删去旧创建的同名信号量文件,可能会出现权限问题导致 sem_open 函数执行失败,sem 为空指针,后续程序出现 segmentation fault
信号量同步 线程间示例,修改至 线程数据共享 代码
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 #include <pthread.h> #include <stdio.h> #include <unistd.h> #include <stdlib.h> #include <semaphore.h> void *thread1_funciton (void *) ;void *thread2_funciton (void *) ;int count = 0 ;sem_t sem;int main () { sem_init(&sem, 0 , 0 ); pthread_t pthread1, pthread2; int ret; ret = pthread_create(&pthread1, NULL , thread1_funciton, NULL ); if (ret != 0 ) { perror("pthread1_create" ); exit (1 ); } ret = pthread_create(&pthread2, NULL , thread2_funciton, NULL ); if (ret != 0 ) { perror("pthread2_create" ); exit (1 ); } pthread_join(pthread1, NULL ); pthread_join(pthread2, NULL ); printf ("The thread is over, process is over too. \n" ); return 0 ; } void *thread1_funciton (void *arg) { while (1 ) { sem_wait(&sem); printf ("Thread1 count = %d\n" , count++); } return NULL ; } void *thread2_funciton (void *arg) { while (1 ) { printf ("Thread2 is running!\n" ); sleep(3 ); sem_post(&sem); } return NULL ; }
互斥锁 通常用于线程间任务的同步,修改至 线程数据共享 代码
sudo apt install glibc-doc
sudo apt install manpages-posix-dev
man pthread_mutex_init
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 #include <bits/types.h> #include <pthread.h> #include <stdio.h> #include <unistd.h> #include <stdlib.h> #include <semaphore.h> void *thread1_funciton (void *) ;void *thread2_funciton (void *) ;int count = 0 ;pthread_mutex_t mutex;int main () { pthread_mutex_init(&mutex, NULL ); pthread_t pthread1, pthread2; int ret; ret = pthread_create(&pthread1, NULL , thread1_funciton, NULL ); if (ret != 0 ) { perror("pthread1_create" ); exit (1 ); } ret = pthread_create(&pthread2, NULL , thread2_funciton, NULL ); if (ret != 0 ) { perror("pthread2_create" ); exit (1 ); } pthread_join(pthread1, NULL ); pthread_join(pthread2, NULL ); printf ("The thread is over, process is over too. \n" ); return 0 ; } void *thread1_funciton (void *arg) { int i; while (1 ) { pthread_mutex_lock(&mutex); for (i = 0 ; i < 3 ; ++i) { printf ("Hello world\n" ); sleep(1 ); } pthread_mutex_unlock(&mutex); sleep(1 ); } return NULL ; } void *thread2_funciton (void *arg) { sleep(1 ); int i; while (1 ) { pthread_mutex_lock(&mutex); for (i = 0 ; i < 3 ; ++i) { printf ("Hcjjjjjjj\n" ); sleep(1 ); } pthread_mutex_unlock(&mutex); sleep(1 ); } return NULL ; }
信号 用于任务间传递控制命令,而不是数据
kill -l
man 2 kill
parent 进程发送控制命令给 child 进程
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 #include <stdio.h> #include <unistd.h> #include <signal.h> #include <sys/types.h> int main () { pid_t pid; pid = fork(); if (pid > 0 ) { sleep(3 ); kill(pid, SIGKILL); } else if (pid == 0 ) { int i = 0 ; printf ("Child process id = %d\n" , getpid()); while (1 ) { printf ("Count to %d\n" , ++i); sleep(1 ); } } else { perror("fork()" ); } return 0 ; }
捕获命令后执行想要重定向的操作
man signal
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 #include <stdio.h> #include <unistd.h> #include <stdlib.h> #include <signal.h> void fun (int signo) ;int main () { int i = 0 ; printf ("pid = %d\n" , getpid()); signal(SIGINT, fun); signal(SIGKILL, fun); while (1 ) { printf ("Count to %d\n" , ++i); sleep(1 ); } return 0 ; } void fun (int signo) { if (signo == SIGINT) { printf ("You hava just triggered a ctrl+c operation.\n" ); exit (1 ); } else if (signo == SIGKILL) { printf ("Trig a SIGKILL signal.\n" ); } else if (signo == SIGQUIT) { printf ("Trig a SIGQUIT signal.\n" ); } }
1 2 3 4 5 6 7 8 9 10 11 #include <stdio.h> #include <unistd.h> #include <stdlib.h> #include <sys/types.h> #include <signal.h> int main (int argc, char *argv[]) { kill(atoi(argv[1 ]), SIGQUIT); return 0 ; }
网络编程 TCP 服务端 socket() → bind() → listen() → accept() → read()/recv() → write()/send() → close()
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 #include <stdio.h> #include <unistd.h> #include <sys/types.h> #include <sys/socket.h> #include <netinet/in.h> #include <arpa/inet.h> #define PORT_ID 8801 #define SIZE 100 int main () { int sockfd, client_sockfd; struct sockaddr_in my_addr , client_addr ; int addr_len; char welcome[SIZE] = "Welcome to connect to the server" ; sockfd = socket(AF_INET, SOCK_STREAM, 0 ); my_addr.sin_family = AF_INET; my_addr.sin_port = htons(PORT_ID); my_addr.sin_addr.s_addr = INADDR_ANY; bind(sockfd, (struct sockaddr *)&my_addr, sizeof (struct sockaddr)); listen(sockfd, 10 ); addr_len = sizeof (struct sockaddr); while (1 ) { printf ("Server is waiting for client wo connect:\n" ); client_sockfd = accept(sockfd, (struct sockaddr *)&client_addr, &addr_len); printf ("Client address = %s\n" , inet_ntoa(client_addr.sin_addr)); send(client_sockfd, welcome, sizeof (welcome), 0 ); printf ("Disconnect the client request.\n" ); close(client_sockfd); } close(sockfd); return 0 ; }
TCP 客户端 socket() → connect() → write()/send() → read()/recv() → close()
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 #include <stdio.h> #include <unistd.h> #include <sys/types.h> #include <sys/socket.h> #include <netinet/in.h> #include <arpa/inet.h> #include <stdlib.h> #define PORT_ID 8801 #define SIZE 100 int main (int argc, char *argv[]) { int sockfd; struct sockaddr_in server_addr ; char buf[SIZE]; if (argc < 2 ) { printf ("Usage: ./client [server IP address]\n" ); } sockfd = socket(AF_INET, SOCK_STREAM, 0 ); server_addr.sin_family = AF_INET; server_addr.sin_port = htons(PORT_ID); server_addr.sin_addr.s_addr = inet_addr(argv[1 ]); connect(sockfd, (struct sockaddr *)&server_addr, sizeof (struct sockaddr)); recv(sockfd, buf, SIZE, 0 ); printf ("Client receive from server: %s\n" , buf); close(sockfd); return 0 ; }
在使用时,应该检查返回值,以确保操作成功!
UDP 服务器端 socket() → bind() → recvfrom()/sento()
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 #include <stdio.h> #include <unistd.h> #include <sys/types.h> #include <sys/socket.h> #include <netinet/in.h> #include <arpa/inet.h> #define PORT_ID 8801 #define SIZE 100 int main () { int sockfd, client_sockfd; struct sockaddr_in my_addr , client_addr ; int addr_len; char welcome[SIZE] = "Welcome to connect to the server" ; char buf[SIZE]; sockfd = socket(AF_INET, SOCK_DGRAM, 0 ); my_addr.sin_family = AF_INET; my_addr.sin_port = htons(PORT_ID); my_addr.sin_addr.s_addr = INADDR_ANY; bind(sockfd, (struct sockaddr *)&my_addr, sizeof (struct sockaddr)); addr_len = sizeof (struct sockaddr); while (1 ) { printf ("Server is waiting for client wo connect:\n" ); recvfrom(sockfd, buf, SIZE, 0 , (struct sockaddr *)&client_addr, &addr_len); printf ("Server receive from client: %s\n" , buf); } close(sockfd); return 0 ; }
UDP 客户端 socket() → sendto()/recvfrom() → close()
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 #include <stdio.h> #include <unistd.h> #include <sys/types.h> #include <sys/socket.h> #include <netinet/in.h> #include <arpa/inet.h> #include <stdlib.h> #define PORT_ID 8801 #define SIZE 100 int main (int argc, char *argv[]) { int sockfd; int i; struct sockaddr_in server_addr ; char buf[SIZE]; if (argc < 2 ) { printf ("Usage: ./client [server IP address]\n" ); } sockfd = socket(AF_INET, SOCK_DGRAM, 0 ); server_addr.sin_family = AF_INET; server_addr.sin_port = htons(PORT_ID); server_addr.sin_addr.s_addr = inet_addr(argv[1 ]); for (i = 0 ; i < 10 ; ++i) { sprintf (buf, "%d\n" , i); sendto(sockfd, buf, SIZE, 0 , (struct sockaddr *)&server_addr, sizeof (struct sockaddr)); printf ("Client sends to server: %s: %s\n" , argv[1 ],buf); sleep(1 ); } close(sockfd); return 0 ;
并发服务器模型
方式一:预先创建多个 child 进程等待客户端的连接
方式二:客户端请求到来了再创建并发线程
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 #include <stdio.h> #include <sys/types.h> #include <sys/socket.h> #include <arpa/inet.h> #include <netinet/in.h> #include <unistd.h> #include <pthread.h> #define PORT_ID 8800 #define SIZE 100 void *thread_function (void *arg) ;struct sockaddr_in client_addr ;int client_sockfd;char welcome[SIZE] = "Welcome to connect to the sever!" ;int main (void ) { int sockfd; struct sockaddr_in my_addr ; int addr_len; pthread_t pthread; sockfd = socket(AF_INET, SOCK_STREAM, 0 ); my_addr.sin_family = AF_INET; my_addr.sin_port = htons(PORT_ID); my_addr.sin_addr.s_addr = INADDR_ANY; bind(sockfd, (struct sockaddr *)&my_addr, sizeof (struct sockaddr)); listen(sockfd, 10 ); addr_len = sizeof (struct sockaddr); while (1 ) { printf ("Server is waiting for client to connect:\n" ); client_sockfd = accept(sockfd, (struct sockaddr *)&client_addr, &addr_len); pthread_create(&pthread, NULL , thread_function, NULL ); } close(sockfd); return 0 ; } void *thread_function (void *arg) { printf ("Client IP address = %s\n" , inet_ntoa(client_addr.sin_addr)); send(client_sockfd, welcome, SIZE, 0 ); printf ("Disconnect the client request.\n" ); close(client_sockfd); pthread_exit(NULL ); return NULL ; }