下面是自我测试
-
简述并发多线程服务器的流程
-
简述并发多进程服务器的流程
-
什么是并发服务器
并发服务器:多个客户端接入服务器-->多线程+socket\ 多进程+socket
1 并发多线程服务器
1:ser.c服务器端 2:cli.c客户端 功能:在ser.c运行起来后,多个终端运行客户端程序cli.c后,实现多个 客户端接入服务器的效果 /*=============================================================== * Copyright (C) 2020 All rights reserved. * * 文件名称:ser.c * 创 建 者:liujing * 创建日期:2020年07月24日 * 描 述: * * 更新日志: * ================================================================*/ #include <stdio.h> #include <string.h> #include <stdlib.h> #include <strings.h> #include <sys/socket.h> #include <netinet/in.h> #include <netinet/ip.h> /* superset of previous */ #include <pthread.h> void thread_func(void*arg) { printf("\n进入进程thread_func\n \n newid = %d\n",*(int*)arg); int id = *(int*)arg; //read / write 读取操作文件描述服 char buf[32]; char sendbuf[32] = "HELLO WORD"; int ret; while(1) { ret = read(id,buf,32); write(id,sendbuf,32); puts(buf); sleep(1); if(ret == 0) //当read / write函数返回0,说明客户端退出,socket连接断开 { printf("\nbreak\n"); break; //退出循环 } } close(id); printf("\n退出线程thread_func:%d\n",id); } void main() { //1:获取socket描述符 int socketid; //AF_INET=IPv4 //SOCK_STREAM=socket流 //0=协议默认 socketid = socket(AF_INET,SOCK_STREAM,0); if(socketid!=EOF) { printf("\n获取ID成功\n"); } else { perror("\n获取ID失败\n"); } //2:socket网络地址绑定socket描述符 //socket网络地址赋值 --> For AF_INET see ip(7) struct sockaddr_in sockaddr; sockaddr.sin_family = AF_INET; sockaddr.sin_port = 5001; //5000~65535是用户段口号 //将点分十进制的IP地址转化为32位地址,存储在sockaddr.sin_addr if(1 == inet_pton(AF_INET,"192.168.43.70",(void*)&sockaddr.sin_addr)) { printf("\n转换IP-->32位成功\n"); } else { perror("\n转化IP-->位失败\n"); } //socket描述符绑定网络地址 if(bind(socketid,(struct sockaddr*)&sockaddr,sizeof(sockaddr)) == EOF) { perror("\nbind function error\n"); } else { printf("\nbind function success\n"); } //将网络套接字转化为被动套接字,进入监听状态 if(0 == listen(socketid,5)) { printf("\n listen function success\n"); } else { perror("\nlisten function error:\n"); } //等待客户端请求连接 struct sockaddr_in cliaddr; int clilen = 0; int newid = -1; //由于多个客户端接入同一个服务器需要多个socket描述符,所以将accept函数放在while(1)中 while(1) { printf("\n阻塞等待接入\n"); //每次newid不一样 newid = accept(socketid,(struct sockaddr*)&cliaddr,&clilen); if(newid == -1) { perror("\naccept function error\n"); } else { printf("\naccept function success\n"); } //在成功与客户端连接后,为客户端创建进程 pthread_t tid; //线程对象 /*创建线程;如果有2个客户端接入,就会创建2个线程,这2个线程 2个名为thread_func的一抹一样的函数,类似与2个平行宇宙*/ pthread_create(&tid,NULL,(void*)thread_func,(void*)&newid); //脱离线程与mian的关联 pthread_detach(tid); } close(socketid); printf("\nmain end\n"); } /*=============================================================== * Copyright (C) 2020 All rights reserved. * * 文件名称:cli.c * 创 建 者:liujing * 创建日期:2020年07月25日 * 描 述: * * 更新日志: * ================================================================*/ #include <stdio.h> #include <string.h> #include <stdlib.h> #include <strings.h> #include <sys/types.h> /* See NOTES */ #include <sys/socket.h> #include <netinet/in.h> #include <netinet/ip.h> /* superset of previous */ void main() { //1.获取网络套结字描述符 int socketid; socketid = socket(AF_INET,SOCK_STREAM,0); //AF_INET=IPv4 //SOCK_STREAM=socket流 //0=协议默认 if(socketid!=EOF) { printf("\n获取ID成功\n"); } else { perror("\n获取ID失败\n"); } //2.连接服务器 //socket网络地址赋值 --> For AF_INET see ip(7) struct sockaddr_in sockaddr; //接受客户端的网络地址结构体 sockaddr.sin_family = AF_INET;//接受客户端的网络地址结构体的大小 sockaddr.sin_port = 5001; //5000~65535是用户段口号 //将点分十进制的IP地址转化为32位地址,存储在sockaddr.sin_addr if(1 == inet_pton(AF_INET,"192.168.43.70",(void*)&sockaddr.sin_addr)) { printf("\n转换IP-->32位成功\n"); } else { perror("\n转化IP-->位失败\n"); } if(0 == connect(socketid,(struct sockaddr*)&sockaddr,sizeof(sockaddr))) { printf("\nconnet function success\n"); } else { perror("connect funtion error"); } //3.通信 char buf[32] = "hello word"; char getbuf[32] = { 0}; int ret; while(1) { write(socketid,buf,32); //注意:服务器的收发的字节大小应该保持一致 ret = read(socketid,getbuf,32); puts(getbuf); sleep(1); if(ret == 0) { printf("\n退出循环\n"); break; } } close(socketid); printf("\nend\n"); } ==================================================================== 客户端1的运行截图如下: farsight@ubuntu:~/Desktop$ ./cli 获取ID成功 转换IP-->32位成功 connet function success HELLO WORD HELLO WORD HELLO WORD HELLO WORD HELLO WORD HELLO WORD HELLO WORD HELLO WORD HELLO WORD HELLO WORD HELLO WORD HELLO WORD HELLO WORD HELLO WORD HELLO WORD HELLO WORD HELLO WORD HELLO WORD HELLO WORD HELLO WORD HELLO WORD HELLO WORD HELLO WORD HELLO WORD HELLO WORD HELLO WORD HELLO WORD HELLO WORD HELLO WORD HELLO WORD HELLO WORD HELLO WORD HELLO WORD HELLO WORD ^C farsight@ubuntu:~/Desktop$ ==================================================================== 服务器端的运行截图如下: farsight@ubuntu:~/Desktop$ ./cli 获取ID成功 转换IP-->32位成功 connet function success HELLO WORD HELLO WORD HELLO WORD HELLO WORD HELLO WORD ^C farsight@ubuntu:~/Desktop$ ==================================================================== 客户端2的运行截图如下: farsight@ubuntu:~/Desktop$ ./ser 获取ID成功 转换IP-->32位成功 bind function success listen function success 阻塞等待接入 accept function success 阻塞等待接入 进入进程thread_func newid = 4 hello word hello word hello word hello word hello word hello word hello word hello word hello word hello word hello word hello word hello word hello word hello word accept function success 阻塞等待接入 进入进程thread_func newid = 5 hello word hello word hello word hello word hello word hello word hello word hello word hello word hello word hello word hello word break 退出线程thread_func:5 hello word hello word hello word hello word hello word hello word hello word hello word hello word hello word hello word hello word hello word hello word break 退出线程thread_func:4
2 并发多进程服务器
利用多进程与socket编程,实现多个客户端接入服务器的效果 =============================================================== * Copyright (C) 2020 All rights reserved. * * 文件名称:ser.c * 创 建 者:liujing * 创建日期:2020年07月24日 * 描 述: * * 更新日志: * ================================================================*/ #include <stdio.h> #include <string.h> #include <stdlib.h> #include <strings.h> #include <sys/socket.h> #include <netinet/in.h> #include <netinet/ip.h> /* superset of previous */ #include <pthread.h> #include <unistd.h> void main() { //1:获取socket描述符 int socketid; //AF_INET=IPv4 //SOCK_STREAM=socket流 //0=协议默认 socketid = socket(AF_INET,SOCK_STREAM,0); if(socketid!=EOF) { printf("\n获取ID成功\n"); } else { perror("\n获取ID失败\n"); } //2:socket网络地址绑定socket描述符 //socket网络地址赋值 --> For AF_INET see ip(7) struct sockaddr_in sockaddr; sockaddr.sin_family = AF_INET; sockaddr.sin_port = 5001; //5000~65535是用户段口号 //将点分十进制的IP地址转化为32位地址,存储在sockaddr.sin_addr if(1 == inet_pton(AF_INET,"192.168.43.69",(void*)&sockaddr.sin_addr)) { printf("\n转换IP-->32位成功\n"); } else { perror("\n转化IP-->位失败\n"); } //socket描述符绑定网络地址 if(bind(socketid,(struct sockaddr*)&sockaddr,sizeof(sockaddr)) == EOF) { perror("\nbind function error\n"); } else { printf("\nbind function success\n"); } //将网络套接字转化为被动套接字,进入监听状态 if(0 == listen(socketid,5)) { printf("\n listen function success\n"); } else { perror("\nlisten function error:\n"); } //等待客户端请求连接 struct sockaddr_in cliaddr; int clilen = 0; int newid = -1; //由于多个客户端接入同一个服务器需要多个socket描述符,所以将accept函数放在while(1)中 while(1) { printf("\n阻塞等待接入\n"); //每次newid不一样 newid = accept(socketid,(struct sockaddr*)&cliaddr,&clilen); if(newid == -1) { perror("\naccept function error\n"); } else { printf("\naccept function success\n"); } //创建子进程 pid_t pid; pid = fork(); //判读进程 if(pid > 0) //父亲进程 { } else if(pid == 0) //子进程 { printf("\n>>进入子进程\n"); char sonbuf[32] = { 0};//接受缓存 int son_ret; while(1) { son_ret = read(newid,sonbuf,32); write(newid,"HELLO WORD",32); puts(sonbuf); sleep(2); if(son_ret == 0) { printf("\nson pthread over\n"); //关闭socket close(newid); break; } } } else { perror("\n进程错误\n"); } } close(socketid); printf("\nmain end\n"); } =============================================================== * Copyright (C) 2020 All rights reserved. * * 文件名称:cli.c * 创 建 者:liujing * 创建日期:2020年07月25日 * 描 述: * * 更新日志: * ================================================================*/ #include <stdio.h> #include <string.h> #include <stdlib.h> #include <strings.h> #include <sys/types.h> /* See NOTES */ #include <sys/socket.h> #include <netinet/in.h> #include <netinet/ip.h> /* superset of previous */ void main() { //1.获取网络套结字描述符 int socketid; socketid = socket(AF_INET,SOCK_STREAM,0); //AF_INET=IPv4 //SOCK_STREAM=socket流 //0=协议默认 if(socketid!=EOF) { printf("\n获取ID成功\n"); } else { perror("\n获取ID失败\n"); } //2.连接服务器 //socket网络地址赋值 --> For AF_INET see ip(7) struct sockaddr_in sockaddr; //接受客户端的网络地址结构体 sockaddr.sin_family = AF_INET;//接受客户端的网络地址结构体的大小 sockaddr.sin_port = 5001; //5000~65535是用户段口号 //将点分十进制的IP地址转化为32位地址,存储在sockaddr.sin_addr if(1 == inet_pton(AF_INET,"192.168.43.69",(void*)&sockaddr.sin_addr)) { printf("\n转换IP-->32位成功\n"); } else { perror("\n转化IP-->位失败\n"); } if(0 == connect(socketid,(struct sockaddr*)&sockaddr,sizeof(sockaddr))) { printf("\nconnet function success\n"); } else { perror("connect funtion error"); } //3.通信 char buf[32] = "hello word"; char getbuf[32] = { 0}; int ret; while(1) { write(socketid,buf,32); //注意:服务器的收发的字节大小应该保持一致 ret = read(socketid,getbuf,32); puts(getbuf); sleep(1); if(ret == 0) { printf("\n退出循环\n"); break; } } close(socketid); printf("\nend\n"); } =============================================================== 客户端1的运行效果如下: farsight@ubuntu:~/Desktop$ ./cli 获取ID成功 转换IP-->32位成功 connet function success HELLO WORD HELLO WORD HELLO WORD HELLO WORD HELLO WORD HELLO WORD HELLO WORD HELLO WORD HELLO WORD HELLO WORD HELLO WORD ^C farsight@ubuntu:~/Desktop$ =============================================================== =============================================================== 客户端2的运行效果如下: farsight@ubuntu:~/Desktop$ ./cli 获取ID成功 转换IP-->32位成功 connet function success HELLO WORD HELLO WORD HELLO WORD HELLO WORD HELLO WORD HELLO WORD HELLO WORD HELLO WORD HELLO WORD ^C farsight@ubuntu:~/Desktop$ =============================================================== =============================================================== 服务端的运行效果如下: farsight@ubuntu:~/Desktop$ ./ser 获取ID成功 转换IP-->32位成功 bind function success listen function success 阻塞等待接入 accept function success >>进入父进程 阻塞等待接入 >>进入子进程 hello word hello word hello word hello word hello word accept function success >>进入父进程 阻塞等待接入 >>进入子进程 hello word hello word hello word hello word hello word hello word hello word hello word hello word hello word hello word hello word hello word hello word hello word son pthread over 阻塞等待接入 hello word hello word ==> 结论:与多线程的并发服务器类似,两个客户端接入服务器会进入两个子进程,与平时宇宙一样,你细品!