操作系统不会销毁子进程,但会收集子进程的退出状态。进程正常或异常终止时,内核向其父进程发送SIGCHILD信号。父进程收到SIGCHILD,系统默认动作是忽略。可以自己设置捕捉函数。
操作系统不会主动把返回值传递给父进程,只有父进程发起请求时,操作系统才把返回值传给父进程。如果父进程没有主动索取子进程的结束状态,操作系统将一直保留返回值,并让子进程一直处于僵尸进程状态。
套接字属于操作系统,进程只是拥有代表套接字的文件描述符。fork出子进程后要及时关闭用不上的文件描述符,计数引用,只有文件描述符的引用都销毁后,才能销毁套接字。
使用标准I/O函数传输数据时,经过两个缓冲,I/O函数缓冲和套接字缓冲。套接字缓冲主要是为实现TCP协议而设立的,tcp超时重传时,数据就从套接字缓冲中取出重传。使用标准I/O函数(fgets,fputs)缓冲的目的是为了提高性能。(read,write属于系统调用)
fdopen:将文件描述符转换为FILE结构体指针。
fileno:FILE*转换为文件描述符。
fclose,关闭了对应的文件描述符,完全终止了套接字,而不是半关闭。
调用shutdown,无论复制出了(dup,dup2)多少文件描述符都进入半关闭状态,同时传递EOF。
select和epoll都属于条件触发,而边缘触发可以分离接收数据和处理数据的时间点。边缘触发即使输入缓冲收到数据(注册相应事件),服务端也能决定读取和处理这些数据的时间点,这样就给服务端的实现带来巨大的灵活性。
多进程模型缺点:创建进程带来一定开销,为了完成进程间数据交换需要特殊的IPC,上下文切换是创建进程时最大的开销。
分时使用cpu,需要“上下文切换”,运行进程A时将进程A的信息读入内存,接着运行进程B,将A的信息移出内存,再读入B的信息(寄存器)
直接上代码,代码略去了对异常的处理
/* 进程间通信 双工通信的管道 */ #include<stdio.h> #include<unistd.h> #define BUF_SIZE 30 int main() { int fds1[2], fds2[2]; pid_t pid; char str1[] = "who are you?"; char str2[] = "thank you for your message!"; char buf[BUF_SIZE]; pipe(fds1); pipe(fds2); pid = fork(); if (pid == 0) { write(fds1[1], str1, sizeof(str1)); read(fds2[0], buf, BUF_SIZE); printf("child output: %s\n", buf); } else{ read(fds1[0], buf, BUF_SIZE); printf("parent output: %s\n", buf); write(fds2[1], str2, sizeof(str2)); } return 0; }
1 /* 2 多进程服务器模型 3 */ 4 5 #include<stdio.h> 6 #include<stdlib.h> 7 #include<unistd.h> 8 #include<arpa/inet.h> 9 #include<sys/wait.h> 10 #include<sys/socket.h> 11 #include<signal.h> 12 #include<string.h> 13 14 #define BUF_SIZE 30 15 void read_childproc(int sig) 16 { 17 pid_t pid; 18 int status; 19 pid = waitpid(-1, &status, WNOHANG); 20 printf("remove child id is: %d\n", pid); 21 } 22 23 int main(int argc, char* argv[]) 24 { 25 struct sigaction act; 26 struct sockaddr_in serv_addr, clnt_addr; 27 int serv_sock, clnt_sock; 28 int clnt_addr_size; 29 pid_t pid; 30 char buf[BUF_SIZE]; 31 int str_len; 32 33 if (argc != 2) { 34 printf("usage %s <port>\n", argv[0]); 35 } 36 //捕捉函数设置 37 act.sa_handler = read_childproc; 38 sigemptyset(&act.sa_mask); 39 act.sa_flags = 0; 40 //信号注册 41 sigaction(SIGCHLD, &act, 0); 42 //tcp连接 43 serv_sock = socket(AF_INET, SOCK_STREAM, 0); 44 memset(&serv_addr, 0, sizeof(serv_addr)); 45 serv_addr.sin_family = AF_INET; 46 serv_addr.sin_addr.s_addr = htonl(INADDR_ANY); 47 serv_addr.sin_port = htons(atoi(argv[1])); 48 bind(serv_sock, (struct sockaddr*)&serv_addr, sizeof(serv_addr)); 49 listen(serv_sock, 5); 50 51 //有请求来就fork出进程来处理 52 while (1) 53 { 54 clnt_addr_size = sizeof(clnt_addr); 55 clnt_sock = accept(serv_sock, (struct sockaddr*)&clnt_addr, &clnt_addr_size); /*非阻塞在调用???默认不应该是阻塞的吗*/ 56 if (clnt_sock == -1) 57 continue; 58 else 59 puts("new client connect....."); 60 pid = fork(); 61 //child 处理连接请求 62 if (pid == 0) { 63 //关闭用不上的文件描述符 64 close(serv_sock); 65 while (str_len = read(clnt_sock, buf, BUF_SIZE)) 66 write(clnt_sock, buf, str_len); 67 close(clnt_sock); 68 printf("client disconnect...\n"); 69 return 0; 70 } 71 else { 72 close(clnt_sock); 73 } 74 } 75 //退出循环,关闭服务端 76 close(serv_sock); 77 return 0; 78 }
1 /* 2 select模型 3 */ 4 #include<stdio.h> 5 #include<unistd.h> 6 #include<sys/socket.h> 7 #include<sys/time.h> 8 #include<sys/select.h> 9 #include<stdlib.h> 10 #include<string.h> 11 #include<arpa/inet.h> 12 13 14 #define BUF_SIZE 100 15 16 int main(int argc, char* argv[]) 17 { 18 int serv_sock, clnt_sock; 19 int clnt_addr_size; 20 struct sockaddr_in serv_addr, clnt_addr; 21 char buf[BUF_SIZE]; 22 int fd_max, fd_num; 23 int str_len; 24 fd_set reads, temp; 25 struct timeval timeout; 26 if (argc != 2) 27 { 28 printf("usage ./file <port>\n"); 29 } 30 serv_sock = socket(AF_INET, SOCK_STREAM, 0); 31 memset(&serv_addr, 0, sizeof(serv_addr)); 32 serv_addr.sin_family = AF_INET; 33 serv_addr.sin_addr.s_addr = htonl(INADDR_ANY); 34 serv_addr.sin_port = htons(atoi(argv[1])); 35 bind(serv_sock, (struct sockaddr*) & serv_addr, sizeof(serv_addr)); 36 listen(serv_sock, 5); 37 FD_ZERO(&reads); 38 FD_SET(serv_sock, &reads); 39 fd_max = serv_sock; 40 41 //多进程模型中fork出一个子进程来处理连接请求,一个进程对应一个请求 42 //多路I/O复用,一个进程轮询处理多个请求select 43 while (1) 44 { 45 timeout.tv_sec = 5; 46 timeout.tv_usec = 5000; 47 temp = reads; //每次调用select之前要重新设置描述符集 48 fd_num = select(fd_max + 1, &temp, 0, 0, &timeout); 49 if (fd_num == -1) { 50 printf("select error\n"); 51 break; 52 } 53 if (fd_num == 0) { 54 printf("time-out\n"); 55 continue; 56 } 57 58 for (int i = 0; i < fd_max + 1; ++i) //fd_max为监视对象中最大的文件描述符,fd_max+1监视的文件描述符总数 59 { 60 if (FD_ISSET(i, &temp)) { 61 //判断i是否是新的请求连接 62 if (i == serv_sock) { 63 clnt_addr_size = sizeof(clnt_addr); 64 clnt_sock = accept(serv_sock, (struct sockaddr*) & clnt_addr, &clnt_addr_size); 65 FD_SET(clnt_sock, &reads);//加入clnt_sock到fd_set,每次循环开始,temp用reads赋值 66 if(fd_max < clnt_sock) 67 fd_max = clnt_sock; 68 printf("new clinet connect %d\n", clnt_sock); 69 } 70 //不是新的连接请求,收发数据 71 else { 72 str_len = read(i, buf, BUF_SIZE); 73 //数据读完,在fd_set中清除,并关闭文件描述符 74 if (str_len == 0) { 75 FD_CLR(i, &reads); 76 close(i); 77 printf("close client: %d\n", i); 78 } 79 else { 80 write(i, buf, str_len); 81 } 82 } 83 } 84 } 85 } 86 close(serv_sock); 87 return 0; 88 }
1 /* 2 epoll模型 3 */ 4 #include<stdio.h> 5 #include<stdlib.h> 6 #include<string.h> 7 #include<unistd.h> 8 #include<sys/socket.h> 9 #include<time.h> 10 #include<arpa/inet.h> 11 #include<sys/epoll.h> 12 13 #define BUF_SIZE 100 14 #define EPOLL_SIZE 50 15 16 int main(int argc, char* argv[]) 17 { 18 int serv_sock, clnt_sock; 19 struct sockaddr_in serv_addr, clnt_addr; 20 int clnt_addr_size; 21 char buf[BUF_SIZE]; 22 int str_len; 23 int efd, event_cnt; 24 struct epoll_event* ep_events; 25 struct epoll_event event; 26 if (argc != 2) { 27 printf("usage %s <port>\n", argv[0]); 28 } 29 serv_sock = socket(PF_INET, SOCK_STREAM, 0); 30 memset(&serv_addr, 0, sizeof(serv_addr)); 31 serv_addr.sin_family = AF_INET; 32 serv_addr.sin_addr.s_addr = htonl(INADDR_ANY); 33 serv_addr.sin_port = htons(atoi(argv[1])); 34 bind(serv_sock, (struct sockaddr*) & serv_addr, sizeof(serv_addr)); 35 listen(serv_sock, 5); 36 efd = epoll_create(EPOLL_SIZE);//创建epoll例程 37 ep_events = malloc(sizeof(struct epoll_event)*EPOLL_SIZE); 38 event.events = EPOLLIN; 39 event.data.fd = serv_sock; 40 epoll_ctl(efd, EPOLL_CTL_ADD, serv_sock, &event);//注册事件 41 42 //select对应的数据结构是文件描述符的数组,需要指定数组的范围,fd_max+1。 43 //epoll对应的数据结构是红黑树,epoll_create时返回的描述符就是根节点的fd, 44 //所以epoll_wait时只要指定根节点,对应的红黑树就是监视对象范围。对应的操作也就相当于增删修改节点 45 while (1) 46 { 47 event_cnt = epoll_wait(efd, ep_events, EPOLL_SIZE, -1); 48 if (event_cnt == -1){ 49 printf("epoll_wait error\n"); 50 break; 51 } 52 for (int i = 0; i < event_cnt; ++i) 53 { 54 if (ep_events[i].data.fd == serv_sock) { 55 clnt_addr_size = sizeof(clnt_addr); 56 clnt_sock = accept(serv_sock, (struct sockaddr*) & clnt_addr, &clnt_addr_size); 57 event.events = EPOLLIN; 58 event.data.fd = clnt_sock; 59 epoll_ctl(efd, EPOLL_CTL_ADD, clnt_sock, &event); 60 printf("new client connect: %d\n",clnt_sock); 61 } 62 else { //不是连接请求,进行收发数据 63 str_len = read(ep_events[i].data.fd, buf, BUF_SIZE);//select中的i就表示文件描述符 64 if (str_len == 0) { 65 epoll_ctl(efd, EPOLL_CTL_DEL, ep_events[i].data.fd, NULL); 66 close(ep_events[i].data.fd);//还要关闭对应的文件描述符 67 printf("close client: %d\n", ep_events[i].data.fd); 68 } 69 else { 70 write(ep_events[i].data.fd, buf, str_len); 71 } 72 } 73 } 74 } 75 close(serv_sock); 76 close(efd);//关闭红黑树根节点对应的描述符 77 return 0; 78 }
1 /* 2 存储I/O映射,共享内存mmap(读) 3 */ 4 #include<stdio.h> 5 #include<sys/types.h> 6 #include<sys/stat.h> 7 #include<unistd.h> 8 #include<stdlib.h> 9 #include<fcntl.h> 10 #include<sys/mman.h> 11 #define MAPLEN 0x1000 //4096字节 12 13 struct STU 14 { 15 int id; 16 char name[20]; 17 char sex; 18 }; 19 20 int main(int argc, char* argv[]) 21 { 22 struct STU* mm; 23 int fd; 24 if (argc != 2) { 25 printf("usage %s finename\n", argv[0]); 26 } 27 fd = open(argv[1], O_RDWR); 28 mm = mmap(0, MAPLEN, PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0); 29 if (mm == MAP_FAILED) { 30 printf("mmap failed"); 31 exit(1); 32 } 33 close(fd);//文件描述符和mmap无关,已经将fd代表的文件映射到了内存,可以关闭fd了 34 unlink(argv[1]);//调用unlink移除文件,以免占用磁盘空间 35 //int i = 0; 36 while (1) 37 { 38 printf("%d\n", mm->id); 39 printf("%s\n", mm->name); 40 printf("%c\n", mm->sex); 41 sleep(1); 42 } 43 munmap(mm, MAPLEN);//关闭mmap,以免造成内存泄漏 44 return 0; 45 }
1 /* 2 存储I/O映射,共享内存mmap(写) 3 */ 4 #include<stdio.h> 5 #include<sys/types.h> 6 #include<sys/stat.h> 7 #include<unistd.h> 8 #include<stdlib.h> 9 #include<fcntl.h> 10 #include<sys/mman.h> 11 #define MAPLEN 0x1000 //4096字节 12 13 struct STU 14 { 15 int id; 16 char name[20]; 17 char sex; 18 }; 19 20 int main(int argc, char* argv[]) 21 { 22 struct STU* mm; 23 int fd; 24 if (argc != 2) { 25 printf("usage %s finename\n", argv[0]); 26 } 27 fd = open(argv[1], O_RDWR | O_CREAT, 0777); 28 //扩展文件 29 lseek(fd, MAPLEN - 1, SEEK_SET); 30 write(fd, "\0", 1);//调用mmap映射文件之前,要先打开文件 31 mm = mmap(0, MAPLEN, PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0); 32 if (mm == MAP_FAILED) { 33 printf("mmap failed"); 34 exit(1); 35 } 36 close(fd);//文件描述符和mmap无关,已经将fd代表的文件映射到了内存,可以关闭fd了 37 int i = 0; 38 //循环写入,相当于每次都是在mm所指向的内存中写入新的结构体, 39 //读的时候也是读出该时刻结构体中的值,如果先打开写端,再打开读端读时会发现i不是从0开始, 40 //因为此时i已经写入0,然后覆盖到1,覆盖2,一直往下。。。 41 //如果先终端写端,则读端一直循环读到同一个数 42 while (1) 43 { 44 mm->id = i; 45 sprintf(mm->name, "zhang->%d\n", i); 46 if (i % 2 == 0) 47 mm->sex = 'm'; 48 else 49 mm->sex = 'w'; 50 ++i; 51 sleep(1); 52 } 53 munmap(mm, MAPLEN);//关闭mmap,以免造成内存泄漏 54 return 0; 55 }
1 /* 2 锁--互斥量 3 */ 4 #include<stdio.h> 5 #include<unistd.h> 6 #include<stdlib.h> 7 #include<pthread.h> 8 9 #define NUM_THREAD 100 10 pthread_mutex_t mutex; 11 long long num = 0; 12 13 void* thread_inc(void* arg) 14 { 15 int i; 16 pthread_mutex_lock(&mutex); 17 for (i = 0; i < 5000; i++) 18 { 19 num += 1; 20 } 21 pthread_mutex_unlock(&mutex); 22 return NULL; 23 } 24 void* thread_des(void* arg) 25 { 26 int i; 27 for (i = 0; i < 5000; i++) 28 { 29 pthread_mutex_lock(&mutex); 30 num -= 1; 31 pthread_mutex_unlock(&mutex); 32 } 33 return NULL; 34 } 35 36 int main(int argc, char* argv[]) 37 { 38 pthread_t thread_id[NUM_THREAD]; 39 int i; 40 pthread_mutex_init(&mutex,NULL); 41 for (i = 0; i < NUM_THREAD; ++i) 42 { 43 if (i % 2) { 44 pthread_create(&thread_id[i], NULL, thread_inc, NULL); 45 } 46 else { 47 pthread_create(&thread_id[i], NULL, thread_des, NULL); 48 } 49 } 50 //阻塞回收线程 51 for (i = 0; i < NUM_THREAD; ++i) 52 { 53 pthread_join(thread_id[i],NULL); 54 } 55 printf("result: %d\n", num); 56 pthread_mutex_destroy(&mutex); 57 return 0; 58 }
1 /* 2 锁--读写锁 3 3个线程不定时写同一全局资源,5个线程不定时读同一全局资源 4 */ 5 #include<stdio.h> 6 #include<unistd.h> 7 #include<pthread.h> 8 9 int counter; 10 pthread_rwlock_t rwlock; 11 12 void* th_write(void* arg) 13 { 14 int t; 15 while (1) 16 { 17 pthread_rwlock_wrlock(&rwlock); 18 t = counter; 19 usleep(100); 20 printf("write %x : counter=%d ++counter=%d\n", (int)pthread_self(), t, ++counter); 21 pthread_rwlock_unlock(&rwlock); 22 sleep(1); 23 } 24 } 25 26 void* th_read(void* arg) 27 { 28 while (1) 29 { 30 pthread_rwlock_rdlock(&rwlock); 31 printf("read %x : %d\n", (int)pthread_self(), counter); 32 pthread_rwlock_unlock(&rwlock); 33 sleep(1); 34 } 35 } 36 37 int main() 38 { 39 int i; 40 pthread_t t_id[8]; 41 pthread_rwlock_init(&rwlock, NULL); 42 for (i = 0; i < 3; i++) 43 { 44 pthread_create(&t_id[i], NULL, th_write, NULL); 45 } 46 for (i = 0; i < 5; i++) 47 { 48 pthread_create(&t_id[i+3], NULL, th_read, NULL); 49 } 50 51 for (i = 0; i < 8; i++) 52 { 53 pthread_join(t_id[i], NULL); 54 } 55 return 0; 56 }
1 /* 2 锁--条件变量 3 */ 4 #include<stdio.h> 5 #include<pthread.h> 6 #include<stdlib.h> 7 #include<unistd.h> 8 9 struct msg { 10 struct msg* next; 11 int num; 12 }; 13 14 struct msg* head; 15 pthread_cond_t has_product = PTHREAD_COND_INITIALIZER; 16 pthread_mutex_t lock = PTHREAD_MUTEX_INITIALIZER; 17 18 void* consumer(void* arg) 19 { 20 struct msg* mp; 21 for (;;) 22 { 23 pthread_mutex_lock(&lock); 24 while (head == NULL) { 25 pthread_cond_wait(&has_product, &lock); 26 } 27 mp = head; 28 head = mp->next; 29 pthread_mutex_unlock(&lock); 30 printf("consume %d\n", mp->num); 31 free(mp); 32 sleep(rand() % 5); 33 } 34 } 35 36 //生产者,生产完pthread_cond_signal唤醒pthread_cond_wait 37 void* producer(void* arg) 38 { 39 struct msg* mp; 40 for (;;) 41 { 42 mp = malloc(sizeof(struct msg)); 43 mp->num = rand() % 1000 + 1; 44 printf("produce %d\n", mp->num); 45 pthread_mutex_lock(&lock); 46 mp->next = head; 47 head = mp; 48 pthread_mutex_unlock(&lock); 49 pthread_cond_signal(&has_product); 50 sleep(rand() % 5); 51 } 52 } 53 54 int main(int argc,char* argv[]) 55 { 56 pthread_t pid, cid; 57 srand(time(NULL)); 58 pthread_create(&pid, NULL, producer, NULL); 59 pthread_create(&pid, NULL, consumer, NULL); 60 pthread_join(pid, NULL); 61 pthread_join(cid, NULL); 62 return 0; 63 }
1 /* 2 锁--信号量 3 */ 4 #include<stdio.h> 5 #include<unistd.h> 6 #include<pthread.h> 7 #include<semaphore.h> 8 9 static sem_t sem_one; 10 static sem_t sem_two; 11 static int num; 12 void* readnum(void* arg) 13 { 14 int i; 15 for (i = 0; i < 5; i++) 16 { 17 fputs("input num: ", stdout); 18 sem_wait(&sem_two); 19 //获得锁后开始生产,sem_two变为0,线程下次获取sem_two时阻塞,直到消费者sem_post(&sem_two),sem_two变为1才能继续获取 20 scanf("%d", &num); 21 sem_post(&sem_one); 22 } 23 return NULL; 24 } 25 26 void* accu(void* arg) 27 { 28 int sum = 0, i; 29 for (i = 0; i < 5; i++) 30 { 31 sem_wait(&sem_one); 32 sum += num; 33 sem_post(&sem_two); 34 } 35 printf("result: %d\n", sum); 36 return NULL; 37 } 38 39 int main(int argc, char* argv[]) 40 { 41 pthread_t t1, t2; 42 sem_init(&sem_one, 0, 0); 43 sem_init(&sem_two, 0, 1); 44 45 pthread_create(&t1, NULL, readnum, NULL); 46 pthread_create(&t2, NULL, accu, NULL); 47 48 pthread_join(t1, NULL); 49 pthread_join(t2, NULL); 50 51 sem_destroy(&sem_one); 52 sem_destroy(&sem_two); 53 return 0; 54 }
1 /* 2 进程间锁,mmap锁映射 3 */ 4 #include<stdio.h> 5 #include<pthread.h> 6 #include<unistd.h> 7 #include<sys/stat.h> 8 #include<fcntl.h> 9 #include<sys/types.h> 10 #include<string.h> 11 #include<sys/mman.h> 12 #include<sys/wait.h> 13 14 struct mt { 15 int num; 16 pthread_mutex_t mutex; 17 pthread_mutexattr_t mutexattr; 18 }; 19 20 int main() 21 { 22 int fd, i; 23 struct mt* mm; 24 pid_t pid; 25 fd = open("mt_test", O_CREAT | O_RDWR, 0777); 26 ftruncate(fd, sizeof(*mm));//扩展文件 27 mm = mmap(0, sizeof(*mm), PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0); 28 close(fd); 29 memset(mm, 0, sizeof(*mm)); 30 pthread_mutexattr_init(&mm->mutexattr); 31 /* 设置互斥对象为PTHREAD_PROCESS_SHARED共享,即可以在多个进程的线程访问,进程间锁。默认PTHREAD_PROCESS_PRIVATE 为同一进程的线程共享 ,线程间锁*/ 32 pthread_mutexattr_setpshared(&mm->mutexattr, PTHREAD_PROCESS_SHARED); 33 pthread_mutex_init(&mm->mutex, &mm->mutexattr); 34 pid = fork(); //父子进程对于mt_test都是shared 35 if (pid == 0) { 36 for (i = 0; i < 10; i++) 37 { 38 pthread_mutex_lock(&mm->mutex); 39 (mm->num)++; 40 printf("num: %d\n", mm->num); 41 pthread_mutex_unlock(&mm->mutex); 42 sleep(1); 43 } 44 } 45 else if (pid > 0) { 46 for (i = 0; i < 10; i++) 47 { 48 pthread_mutex_lock(&mm->mutex); 49 mm->num += 2; 50 printf("num: %d\n", mm->num); 51 pthread_mutex_unlock(&mm->mutex); 52 sleep(1); 53 } 54 wait(NULL); 55 } 56 pthread_mutex_destroy(&mm->mutex); 57 pthread_mutexattr_destroy(&mm->mutexattr); 58 munmap(mm, sizeof(*mm));//父子进程都需要释放mmap 59 unlink("mt_test");//临时文件 60 return 0; 61 }
1 /* 2 锁--文件锁(记录锁,字节范围锁) 3 */ 4 #include<stdio.h> 5 #include<sys/types.h> 6 #include<sys/stat.h> 7 #include<fcntl.h> 8 #include<unistd.h> 9 #include<stdlib.h> 10 11 int main(int argc, char* argv[]) 12 { 13 int fd; 14 struct flock f_lock; 15 if (argc != 2) { 16 printf("usage ./file <filename>\n"); 17 exit(1); 18 } 19 fd = open(argv[1], O_RDWR); 20 f_lock.l_type = F_WRLCK; 21 f_lock.l_whence = SEEK_SET; 22 f_lock.l_start = 0; 23 f_lock.l_len = 0; //对整个文件加锁 24 25 fcntl(fd, F_SETLKW, &f_lock); 26 printf("get flock\n"); 27 sleep(10); 28 f_lock.l_type = F_UNLCK; 29 fcntl(fd, F_SETLKW, &f_lock);//对文件解锁 30 printf("file unlock\n"); 31 32 close(fd); 33 return 0; 34 }
1 /* 2 多线程并发服务器端 3 每个线程去处理一个客户端请求 4 */ 5 6 #include<stdio.h> 7 #include<stdlib.h> 8 #include<string.h> 9 #include<unistd.h> 10 #include<sys/socket.h> 11 #include<time.h> 12 #include<arpa/inet.h> 13 #include<pthread.h> 14 15 #define MAX_CLNT 256 16 #define BUF_SIZE 100 17 pthread_mutex_t mutex; 18 int clnt_cnt = 0; 19 int clnt_socks[MAX_CLNT]; 20 21 void send_msg(char* message, int len) 22 { 23 int i; 24 pthread_mutex_lock(&mutex); 25 for (i = 0; i < clnt_cnt; i++) 26 { 27 write(clnt_socks[i], message, len); 28 } 29 pthread_mutex_unlock(&mutex); 30 } 31 32 void* handle_clnt(void* arg) { 33 int clnt_sock = *((int*)arg); 34 int str_len = 0, i; 35 char message[BUF_SIZE]; 36 //发给此时连接的全部客户端,主线程中客户端数组加锁就是为了一个不漏的发给此时的全部客户端,避免cpu分时造成线程获取到的客户端个数不统一 37 while ((str_len = read(clnt_sock, message, BUF_SIZE)) != 0) 38 send_msg(message, str_len); 39 pthread_mutex_lock(&mutex); 40 //在客户端数组里移除关闭连接的客户端 41 for (i = 0; i < clnt_cnt; i++) 42 { 43 if (clnt_socks[i] == clnt_sock) { 44 while (i++ < clnt_cnt - 1) { 45 clnt_socks[i] = clnt_socks[i + 1]; 46 } 47 break; 48 } 49 } 50 clnt_cnt--; 51 pthread_mutex_unlock(&mutex); 52 close(clnt_sock); 53 return NULL; 54 } 55 56 57 int main(int argc, char* argv[]) 58 { 59 int serv_sock, clnt_sock; 60 socklen_t clnt_addr_size; 61 struct sockaddr_in serv_addr, clnt_addr; 62 pthread_t id; 63 if (argc != 2) 64 { 65 printf("usage ./file <port>\n"); 66 exit(1); 67 } 68 serv_sock = socket(PF_INET, SOCK_STREAM, 0); 69 memset(&serv_addr, 0, sizeof(serv_addr)); 70 serv_addr.sin_family = AF_INET; 71 serv_addr.sin_addr.s_addr = htonl(INADDR_ANY); 72 serv_addr.sin_port = htons(atoi(argv[1])); 73 bind(serv_sock, (struct sockaddr*) & serv_addr, sizeof(serv_addr)); 74 listen(serv_sock, 5); 75 pthread_mutex_init(&mutex, NULL); 76 77 while (1) 78 { 79 clnt_addr_size = sizeof(clnt_addr); 80 clnt_sock = accept(serv_sock, (struct sockaddr*) & clnt_addr, &clnt_addr_size); 81 pthread_mutex_lock(&mutex); 82 clnt_socks[clnt_cnt++] = clnt_sock; 83 pthread_mutex_unlock(&mutex); 84 pthread_create(&id, NULL, handle_clnt, (void*)& clnt_sock); 85 pthread_detach(id);//引导线程销毁,线程置为分离态 86 printf("new client connect ip: %s\n", inet_ntoa(clnt_addr.sin_addr)); 87 } 88 close(serv_sock); 89 return 0; 90 }
1 #include<stdio.h> 2 #include<stdlib.h> 3 #include<string.h> 4 #include<unistd.h> 5 #include<sys/socket.h> 6 #include<time.h> 7 #include<arpa/inet.h> 8 #include<pthread.h> 9 10 #define BUF_SIZE 100 11 #define NAME_SIZE 20 12 char name[NAME_SIZE] = "[DEFAULT]"; 13 char msg[BUF_SIZE]; 14 15 void* send_message(void* arg) 16 { 17 int sock = *((int*)arg); 18 char name_msg[NAME_SIZE + BUF_SIZE]; 19 while (1) 20 { 21 fgets(msg, BUF_SIZE, stdin); 22 if (!strcmp(msg, "q\n")) { 23 close(sock); 24 exit(0); 25 } 26 sprintf(name_msg, "%s %s", name, msg); 27 write(sock, name_msg, strlen(name_msg)); 28 } 29 return NULL; 30 } 31 32 void* recv_message(void* arg) 33 { 34 int sock = *((int*)arg); 35 char name_msg[NAME_SIZE + BUF_SIZE]; 36 int str_len; 37 while (1) 38 { 39 str_len = read(sock, name_msg, NAME_SIZE + BUF_SIZE - 1); 40 if (str_len == -1) 41 return (void*)-1; 42 name_msg[str_len] = '\0'; 43 fputs(name_msg, stdout); 44 } 45 return NULL; 46 } 47 48 int main(int argc, char* argv[]) 49 { 50 int serv_sock; 51 struct sockaddr_in serv_addr; 52 pthread_t send_thread, recv_thread; 53 void* thread_return; 54 if (argc != 4) 55 { 56 printf("usage ./file <ip> <port> <name>\n"); 57 exit(1); 58 } 59 sprintf(name, "[%s]", argv[3]); 60 serv_sock = socket(PF_INET, SOCK_STREAM, 0); 61 memset(&serv_addr, 0, sizeof(serv_addr)); 62 serv_addr.sin_family = AF_INET; 63 serv_addr.sin_addr.s_addr = inet_addr(argv[1]); 64 serv_addr.sin_port = htons(atoi(argv[2])); 65 connect(serv_sock, (struct sockaddr*) & serv_addr, sizeof(serv_addr)); 66 67 pthread_create(&send_thread, NULL, send_message, (void*)&serv_sock); 68 pthread_create(&recv_thread, NULL, recv_message, (void*)& serv_sock); 69 70 pthread_join(send_thread, &thread_return); 71 pthread_join(recv_thread, &thread_return); 72 73 close(serv_sock); 74 return 0; 75 }
1 /* 2 死锁 3 */ 4 #include<stdio.h> 5 #include<unistd.h> 6 #include<pthread.h> 7 8 pthread_mutex_t mutex; 9 pthread_mutex_t lock = PTHREAD_MUTEX_INITIALIZER; 10 void* handle(void* arg) 11 { 12 int error; 13 printf("start\n"); 14 pthread_mutex_lock(&mutex); 15 sleep(2); 16 /*吃着碗里的看着锅里的,都不肯让步(第二种死法)*/ 17 //pthread_mutex_lock(&lock); 18 19 /*对同一互斥量加锁两次,自身陷入死锁状态,改用trylock能正常运行,trylock获取锁失败会返回错误编号,不会阻塞(第一种死法)*/ 20 //pthread_mutex_lock(&mutex); 21 /*error = pthread_mutex_trylock(&mutex); 22 printf("%d\n", error);*/ 23 pthread_mutex_unlock(&mutex); 24 sleep(5); 25 printf("end\n"); 26 return NULL; 27 } 28 29 int main() 30 { 31 pid_t pid; 32 pthread_t id; 33 pthread_mutex_init(&mutex, NULL); 34 pthread_create(&id, NULL, handle, NULL); 35 sleep(1); 36 37 pthread_mutex_lock(&lock); 38 pthread_mutex_lock(&mutex); 39 printf("get mutex\n"); 40 pthread_mutex_unlock(&mutex); 41 pthread_mutex_unlock(&lock); 42 43 pthread_join(id,NULL); 44 pthread_mutex_destroy(&mutex); 45 return 0; 46 }
1 /* 2 信号SIGCHILD处理僵尸进程 3 */ 4 #include<stdio.h> 5 #include<stdlib.h> 6 #include<unistd.h> 7 #include<signal.h> 8 #include<sys/wait.h> 9 10 void read_childproc(int sig) 11 { 12 int status; 13 pid_t id = waitpid(-1, &status, WNOHANG); 14 if (WIFEXITED(status)) { 15 printf("remove child id: %d\n", id); 16 printf("child send: %d\n", WEXITSTATUS(status)); 17 } 18 } 19 20 int main(int argc, char* argv[]) 21 { 22 pid_t pid; 23 struct sigaction act; 24 act.sa_handler = read_childproc; 25 sigemptyset(&act.sa_mask); 26 act.sa_flags = 0; 27 //注册 28 sigaction(SIGCHLD, &act, 0); 29 30 pid = fork(); 31 //child 32 if (pid == 0) 33 { 34 puts("I am child\n"); 35 sleep(10); 36 return 12; 37 } 38 else /*parent*/ 39 { 40 printf("I am parent,child id is: %d\n",pid); 41 pid = fork(); 42 //child second 43 if (pid == 0) { 44 puts("child second\n"); 45 sleep(10); 46 exit(24); 47 } 48 else { 49 printf("child second id is: %d\n", pid); 50 for (int i = 0; i < 5; i++) 51 { 52 puts("wait"); 53 sleep(5); 54 } 55 } 56 } 57 }
1 #include<stdio.h> 2 #include<unistd.h> 3 #include<sys/wait.h> 4 5 //static int a = 5; 6 int a = 5; 7 int main() 8 { 9 int b = 6; 10 pid_t pid; 11 pid = fork(); 12 if (pid == 0) { 13 a++; b++; 14 printf("a=%d b=%d\n", a, b); 15 } 16 else { 17 a += 2; b += 2; 18 printf("a=%d b=%d\n", a, b); 19 wait(NULL); 20 } 21 return 0; 22 }