发布于 

简明 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;
// parent 进程返回子进程的id,子进程返回0
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;
// parent 和 child 是独立的, 放全局也是独立的
int count = 0;
pid = fork();
// parent process
if (pid > 0) {
// 运行结束不影响子进程的运行
for (int i = 0; i < 10; ++i) {
printf("hello world, count = %d\n", count++);
sleep(1);
}
// child process
} 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>

// run model: ./a.out 10 5 15 (三个子进程 10 5 15s 后运行结束)
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]);
// string -> int
sleep(atoi(argv[i]));
exit(0);
// parent
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");
// void* -> int*
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();
// parent write
if (pid > 0) {
// 关闭读端
close(fd[0]);
sleep(5);
write(fd[1], "ab", 2);
// while(1);
} else if (pid == 0) {
// child read
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();
// child process
if (pid == 0) {
int n = 0;
char ch = '*';
close(fd[0]);
while (1) {
write(fd[1], &ch, 1);
// 管道容量为 65536Byte
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();
// child process
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();
// child process
if (pid == 0) {
char tmp[100];
int i;
// fd 用来读 fd2 用来写
close(fd[1]);
close(fd2[0]);
while (1) {
memset(tmp, '\0', sizeof(tmp));
// 读取fd中的数据
read(fd[0], tmp, sizeof(tmp));
for (i = 0; i < sizeof(tmp); ++i) {
tmp[i] = toupper(tmp[i]);
}
// 将转换后的数据写入fd2
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: ");
// gets(tmp);
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];
// 创建有名管道 权限666
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;
// 开辟共享内存,权限0666 不需要root权限
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;
// key 设置为自定义的
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);
// 控制共享内存 删除
// shmctl(shmid, IPC_RMID, NULL);
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");
// fgets(buff.mtext, sizeof(buff.mtext), stdin);
gets(buff.mtext);
printf("Please enter a number you want to send: \n");
scanf("%d", &buff.number);
// 发送数据到队列
// if (msgsnd() ... ){}
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);
// 创建信号量
// pshared 1 表示进程之间的 需要借助进程之前的共享空间
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) {
// 无法修改 SIGKILL 的处理机制
printf("Trig a SIGKILL signal.\n");
} else if (signo == SIGQUIT) {
// 无法修改 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]), SIGKILL);
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";
// 1.socket()
sockfd = socket(AF_INET, SOCK_STREAM, 0);
// 2.bind()
my_addr.sin_family = AF_INET;
// 主机序转网络序
my_addr.sin_port = htons(PORT_ID);
my_addr.sin_addr.s_addr = INADDR_ANY;
//sockaddr_in * 转 sockaddr *
bind(sockfd, (struct sockaddr *)&my_addr, sizeof(struct sockaddr));
// 3.listen()
listen(sockfd, 10);
addr_len = sizeof(struct sockaddr);
while (1) {
printf("Server is waiting for client wo connect:\n");
// 4.accept()
client_sockfd = accept(sockfd, (struct sockaddr *)&client_addr, &addr_len);
// 二进制ip转点分十进制形式
printf("Client address = %s\n", inet_ntoa(client_addr.sin_addr));
// 5.send()
send(client_sockfd, welcome, sizeof(welcome), 0);
printf("Disconnect the client request.\n");
// 6.close()
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

// ./client [IP]
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");
}
// 1.socket()
sockfd = socket(AF_INET, SOCK_STREAM, 0);
// 2.connect
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));
// 3. recv()
recv(sockfd, buf, SIZE, 0);
printf("Client receive from server: %s\n", buf);
// 4.close()
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];
// 1.socket()
sockfd = socket(AF_INET, SOCK_DGRAM, 0);
// 2.bind()
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");
// 3. recvfrom 来保存客户端的信息
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

// ./client [IP]
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");
}
// 1.socket()
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]);
// 2.sendto()
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;
//1.socket()
sockfd = socket(AF_INET, SOCK_STREAM, 0);
//2.bind()
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));
//3.listen()
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;
}