分别通过select、多进程、多线程实现一个并发服务器

select

#include<myhead.h>#define PORT 8888              //端口号
#define IP "192.168.114.109"       //IP地址int main(int argc, const char *argv[])
{//1、创建用于接受连接的套接字int sfd = socket(AF_INET, SOCK_STREAM, 0);if(sfd == -1){perror("socket error");return -1;}printf("socket success\n"); //设置端口号快速重用int reuse = 1;if(setsockopt(sfd, SOL_SOCKET, SO_REUSEADDR, &reuse, sizeof(reuse)) == -1){perror("setsockopt error");return -1;}printf("设置端口快速重用成功\n");//绑定IP地址和端口号//填充要绑定的地址信息结构体struct sockaddr_in sin;sin.sin_family 	= AF_INET;         //表明是ipv4sin.sin_port 	= htons(PORT);        //端口号sin.sin_addr.s_addr = inet_addr(IP);     //IP地址//绑定if(bind(sfd, (struct sockaddr*)&sin, sizeof(sin))==-1){perror("bind error");return -1;}printf("bind success\n");//套接字设置成被动监听状态if(listen(sfd, 128) == -1){perror("listen error");return -1;}printf("listen success\n");//阻塞等待客户端连接请求,如果有新的客户端连接,则创建一个新的用于通信的套接字//定义客户端地址信息结构体struct sockaddr_in cin;             //客户端地址信息结构体cin.sin_family 	= AF_INET;socklen_t socklen = sizeof(cin);          //客户端地址信息的大小定义一个用于检测文件描述符的集合fd_set readfds, tempfds;                          //在栈区定义清空容器中的内容FD_ZERO(&readfds);将要检测的文件描述符放入集合中FD_SET(sfd, &readfds);           //将sfd文件描述符放入FD_SET(0, &readfds);             //将0号文件描述符放入//定义一个容器char buf[128] = "";int res = 0;             //接收select的返回值int newfd = -1;          //存放用于最新连接客户端的套接字int maxfd = sfd;          //定义控制select函数中最大文件描述符struct sockaddr_in saveCin[1024];       //用于存放客户端地址信息结构体while(1){将集合内容复制一份tempfds = readfds;使用select阻塞等待集合中的文件描述符有事件产生res = select(maxfd+1, &tempfds, NULL, NULL, NULL);if(res == -1){perror("select error");return -1;}else if(res == 0){printf("time out\n");return -1;}//遍历所有集合中文件描述符for(int i=0; i<=maxfd; i++){//判断当前i是否在集合中,如果不在,直接判断下一个if(!FD_ISSET(i, &tempfds)){continue;}判断sfd是否还在集合中if( i == sfd){//阻塞接收客户端的链接请求,并且获取客户端的地址信息newfd = accept(sfd, (struct sockaddr*)&cin, &socklen);if(newfd == -1){perror("accept error");return -1;}printf("accept success\n");将newfd放入readfds中FD_SET(newfd , &readfds);//更新maxfdif(newfd > maxfd){maxfd = newfd;}//将最新的客户端套接字放入数组的下标为new的位置saveCin[newfd] = cin;}else if(i == 0 )	//判断是否是终端输入{char buf1[128] = "";bzero(buf, sizeof(buf));//从终端获取数据fgets(buf, sizeof(buf), stdin);       //从终端获取数据buf[strlen(buf)-1]='\0';printf("触发终端输入事件:%s\n", buf);sprintf(buf1, "%s%s", "系统消息:", buf);//将数据发送给所有客户端for(int j=4; j<=maxfd; j++){send(j, buf1,sizeof(buf1), 0);}}else{//收发数据使用newfd完成通信char buf[128] = "";//清空字符串bzero(buf, sizeof(buf));int ret = recv(i, buf, sizeof(buf), 0);   //从套接字中读取客户端发来的消息//判断收到的结果if(ret == 0){printf("客户端已经下线\n");	close(i);             //关闭通信的套接字将当前的文件描述符从集合中删除FD_CLR(i, &readfds);更新maxfdfor(int j=maxfd; j>=0; j--){//判断当前的j是否在集合中,如果在,则为maxfdif(FD_ISSET(j, &readfds)){maxfd = j;continue;           //继续判断下一个}}}else if(ret < 0){perror("recv error");return -1;}printf("[%s:%d]:%s\n", inet_ntoa(saveCin[i].sin_addr), ntohs(saveCin[i].sin_port), buf);//将读取的信息,加上一些字符发送回去strcat(buf, "*_*");send(i, buf, sizeof(buf), 0); }}}//关闭所有套接字close(sfd);               return 0;
}

多进程

#include<myhead.h>#define PORT 8888              //端口号
#define IP "192.168.114.74"       //IP地址//定义函数处理客户端信息
int deal_cli_msg(int newfd, struct sockaddr_in cin)
{//收发数据使用newfd完成通信char buf[128] = "";while(1){//清空字符串bzero(buf, sizeof(buf));//read(newfd, buf, sizeof(buf));        //从套接字中读取客户端发来的消息int res = recv(newfd, buf, sizeof(buf), 0);        //从套接字中读取客户端发来的消息//buf[strlen(buf)-1] = '\0';//判断收到的结果if(res == 0){printf("客户端已经下线\n");break;}else if(res < 0){perror("recv error");return -1;}printf("[%s:%d]:%s\n", inet_ntoa(cin.sin_addr), ntohs(cin.sin_port), buf);//将读取的信息,加上一些字符发送回去strcat(buf, "*_*");//    write(newfd, buf, sizeof(buf));send(newfd, buf, sizeof(buf), 0); }close(newfd);             //关闭通信的套接字return 0;
}//定义信号处理函数
void handler(int signo)
{if(signo == SIGCHLD){while(waitpid(-1, NULL, WNOHANG) > 0);       //非阻塞形式回收僵尸进程}
}int main(int argc, const char *argv[])
{//创建用于接受连接的套接字int sfd = socket(AF_INET, SOCK_STREAM, 0);if(sfd == -1){perror("socket error");return -1;}printf("socket success\n");    //设置端口号快速重用int reuse = 1;if(setsockopt(sfd, SOL_SOCKET, SO_REUSEADDR, &reuse, sizeof(reuse)) == -1){perror("setsockopt error");return -1;}printf("设置端口快速重用成功\n");//绑定IP地址和端口号//填充要绑定的地址信息结构体struct sockaddr_in sin;sin.sin_family     = AF_INET;         //表明是ipv4sin.sin_port     = htons(PORT);        //端口号sin.sin_addr.s_addr = inet_addr(IP);     //IP地址//绑定if(bind(sfd, (struct sockaddr*)&sin, sizeof(sin))==-1){perror("bind error");return -1;}printf("bind success\n");//将套接字设置成被动监听状态if(listen(sfd, 128) == -1){perror("listen error");return -1;}printf("listen success\n");//定义客户端地址信息结构体struct sockaddr_in cin;             //客户端地址信息结构体cin.sin_family     = AF_INET;socklen_t socklen = sizeof(cin);          //客户端地址信息的大小//定义子进程变量pid_t pid;//将SIGCHLD信号绑定到自定义信号处理函数中if(signal(SIGCHLD, handler) == SIG_ERR){perror("signal error");return -1;}while(1){    //阻塞接收客户端的链接请求,并且获取客户端的地址信息int newfd = accept(sfd, (struct sockaddr*)&cin, &socklen);if(newfd == -1){perror("accept error");return -1;}printf("accept success\n");//创建子进程,让子进程完成通信pid = fork();if(pid > 0){//关闭newfdclose(newfd);//回收僵尸进程//wait(NULL);        }else if(pid == 0){       close(sfd);//调用处理客户端函数deal_cli_msg(newfd, cin);//退出子进程exit(EXIT_SUCCESS);}else{perror("fork error");return -1;}}//关闭所有套接字close(sfd);              return 0;
}

多线程

#include<myhead.h>#define PORT 8888              //端口号
#define IP "192.168.114.74"       //IP地址//定义用于向线程体传参的结构体类型
struct msg_info
{int newfd;struct sockaddr_in cin;
};//定义线程体函数
void *deal_cli_msg(void *arg)
{//获取主线程传递的信息int newfd = ((struct msg_info*)arg) -> newfd;struct sockaddr_in cin = ((struct msg_info*)arg) -> cin;//收发数据使用newfd完成通信char buf[128] = "";while(1){//清空字符串bzero(buf, sizeof(buf));//read(newfd, buf, sizeof(buf));        //从套接字中读取客户端发来的消息int res = recv(newfd, buf, sizeof(buf), 0);        //从套接字中读取客户端发来的消息//buf[strlen(buf)-1] = '\0';//判断收到的结果if(res == 0){printf("客户端已经下线\n");break;}else if(res < 0){perror("recv error");return NULL;}printf("[%s:%d]:%s\n", inet_ntoa(cin.sin_addr), ntohs(cin.sin_port), buf);//将读取的信息,加上一些字符发送回去strcat(buf, "*_*");//    write(newfd, buf, sizeof(buf));send(newfd, buf, sizeof(buf), 0); }close(newfd);             //关闭通信的套接字ptread_exit(NULL);               //退出线程}int main(int argc, const char *argv[])
{//创建用于接受连接的套接字int sfd = socket(AF_INET, SOCK_STREAM, 0);if(sfd == -1){perror("socket error");return -1;}printf("socket success sfd = %d\n", sfd);    //4//设置端口号快速重用int reuse = 1;if(setsockopt(sfd, SOL_SOCKET, SO_REUSEADDR, &reuse, sizeof(reuse)) == -1){perror("setsockopt error");return -1;}printf("设置端口快速重用成功\n");//绑定IP地址和端口号//填充要绑定的地址信息结构体struct sockaddr_in sin;sin.sin_family     = AF_INET;         //表明是ipv4sin.sin_port     = htons(PORT);        //端口号sin.sin_addr.s_addr = inet_addr(IP);     //IP地址//绑定if(bind(sfd, (struct sockaddr*)&sin, sizeof(sin))==-1){perror("bind error");return -1;}printf("bind success\n");//将套接字设置成被动监听状态if(listen(sfd, 128) == -1){perror("listen error");return -1;}printf("listen success\n");//阻塞等待客户端连接请求,如果有新的客户端连接,则创建一个新的用于通信的套接字//客户端地址信息结构体struct sockaddr_in cin;             //客户端地址信息结构体cin.sin_family     = AF_INET;socklen_t socklen = sizeof(cin);          //客户端地址信息的大小while(1){//阻塞接收客户端的链接请求,并且获取客户端的地址信息int newfd = accept(sfd, (struct sockaddr*)&cin, &socklen);if(newfd == -1){perror("accept error");return -1;}printf("accept success\n");//定义用于向线程体传参的结构体变量struct msg_info info = {newfd, cin};//创建分支线程用于通信pthread_t tid;if(pthread_create(&tid, NULL, deal_cli_msg, &info) != 0){printf("分支线程创建失败\n");return -1;}//将该线程分离if(pthread_detach(tid) != 0){printf("分离失败\n");return -1;}}//关闭所有套接字close(sfd);               return 0;
}

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/673333.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

【Langchain+Streamlit】旅游聊天机器人

【LangchainStreamlit】打造一个旅游问答AI-CSDN博客 项目线上地址&#xff0c;无需openai秘钥可直接体验&#xff1a;http://101.33.225.241:8502/ github地址&#xff1a;GitHub - jerry1900/langchain_chatbot: langchainstreamlit打造的一个有memory的旅游聊天机器人&…

什么是数据库软删除,什么场景下要用软删除?(go GORM硬删除)

文章目录 什么是数据库软删除&#xff0c;什么场景下要用软删除&#xff1f;go GORM硬删除什么是数据库软删除什么场景下要用软删除 什么是数据库软删除&#xff0c;什么场景下要用软删除&#xff1f; go GORM硬删除 使用的是 GORM&#xff0c;默认启用了软删除功能&#xff…

设计模式(结构型模式)桥接模式

目录 一、简介二、桥接模式2.1、手机品牌接口2.2、手机功能接口2.3、抽象部分2.4、具体抽象部分2.5、使用 三、优点和缺点 一、简介 桥接模式&#xff08;Bridge Pattern&#xff09; 是一种结构型设计模式&#xff0c;用于将抽象部分与它的实现部分分离&#xff0c;使它们可以…

【算法题】96. 不同的二叉搜索树

题目 给你一个整数 n &#xff0c;求恰由 n 个节点组成且节点值从 1 到 n 互不相同的 二叉搜索树 有多少种&#xff1f;返回满足题意的二叉搜索树的种数。 示例 1&#xff1a; 输入&#xff1a;n 3 输出&#xff1a;5 示例 2&#xff1a; 输入&#xff1a;n 1 输出&#x…

js逆向-某东验证码逆向分析

声明 本文仅供学习参考&#xff0c;如有侵权可私信本人删除&#xff0c;请勿用于其他途径&#xff0c;违者后果自负&#xff01; 如果觉得文章对你有所帮助&#xff0c;可以给博主点击关注和收藏哦&#xff01; 插句个人内容&#xff1a;本人最近正在找工作&#xff0c;工作城…

MySQL数据库常用语法回顾及知识点合集(持续更新中……)

前言 本文适合有一定基础的进行快速简单回顾复习。 对于现如今的无论哪一类软件或应用&#xff0c;都几乎无法离开数据库&#xff0c;常见使用的关系性数据库如MySQL、Oracle&#xff0c;非关系性数据库如MongoDB、Redis等。而MySQL数据库则是软件开发中最常用的数据库之一&…

基于SpringBoot的美妆管理系统

文章目录 项目介绍主要功能截图&#xff1a;部分代码展示设计总结项目获取方式 &#x1f345; 作者主页&#xff1a;超级无敌暴龙战士塔塔开 &#x1f345; 简介&#xff1a;Java领域优质创作者&#x1f3c6;、 简历模板、学习资料、面试题库【关注我&#xff0c;都给你】 &…

CS50x 2024 - Lecture 1 - C

本周学习C语言&#xff0c;重点是函数、变量、条件语句和循环。 05:11介绍了编程语言的转换过程&#xff0c;从源代码到机器码&#xff0c;以及编译器的作用。 编译器是将一种语言翻译成另一种语言的程序 09:18使用CS50.dev进行编程&#xff0c;介绍了VS Code和命令行界面的…

LeetCode Python - 1.两数之和

文章目录 题目答案运行结果 题目 给定一个整数数组 nums 和一个整数目标值 target&#xff0c;请你在该数组中找出 和为目标值 target 的那 两个 整数&#xff0c;并返回它们的数组下标。 你可以假设每种输入只会对应一个答案。但是&#xff0c;数组中同一个元素在答案里不能…

数据结构——算法的时间复杂度和空间复杂度

1、算法效率 1.1如何衡量一个算法的好坏&#xff1f; 比如我们最熟悉的斐波那契数列 long long Fib(int N) {if(N < 3)return 1;return Fib(N-1) Fib(N-2); } 上面的斐波那契数列使用递归实现&#xff0c;看起来非常的简洁&#xff0c;那么代码一定是越简洁越好么&…

930. 和相同的二元子数组(多指针滑动窗口)

多指针滑动窗口 滑动窗口&#xff0c;由于题目中数组为二元组数组&#xff0c;对于每一个数组下标 j &#xff0c;当其满足 preSum[j]−preSum[i]goal的条件时&#xff0c;对应 i为一个连续区间&#xff0c;若能够求得 i 的左右边界 left1 与 left2&#xff0c;则此时共有 left…

对接社群团购的风险和坑,其实只有两点

社群团购对接合作的风险和坑&#xff0c;其实只有两点。 让大家更好地了解微信群团购&#xff08;社群团购&#xff09;&#xff0c;正确进入这个领域&#xff0c;借助社群团购进行创业以及货源方通过这个销售渠道进行产品销售。我们将行业的几个关键点进行总结分享&#xff0c…

MongoDB聚合: $skip

$skip聚合阶段用于跳过指定数量的输入文档&#xff0c;并将剩余文档传递到流水线的下一个阶段。 语法 { $skip: <positive 64-bit integer> }使用 $skip需要指定一个正整数来决定跳过的文档数量。从5.0开始&#xff0c;$skip阶段跳过文档的数量限制为一个64位的整数&a…

力扣15-三数之和

三数之和 题目链接 解题思路 1、枚举每个数&#xff0c;表示该数nums[i]已被确定&#xff0c;在排序后的情况下&#xff0c;通过双指针l&#xff0c;r分别从左边l i 1和右边n - 1往中间靠拢&#xff0c;找到nums[i] nums[l] nums[r] 0的所有符合条件的搭配 2、在找符合条…

Python CSV文件读取和写入

本文主要为Python 实现CSV文件读取和写入操作。 CSV文件写入和读取 因为没有现成的csv文件&#xff0c;所以csv的顺序为先写入后读取。 写入 创建csv文件并把数据写入&#xff0c;有两种实现方式&#xff1a;直接插入所有行和插入单行。 示例如下&#xff1a; import csv i…

vim最简单命令学习

安装vim sudo apt install vim在终端随便打开一个文本文件&#xff0c;或者源文件&#xff0c; vim filepath输入该命令后&#xff0c;从终端进入vim编辑器&#xff0c;此时为普通模式(Normal)。 按i键进入编辑模式(Insert)&#xff0c;按Esc键返回普通模式(Normal)。 在编辑…

C语言常见面试题:C语言中如何进行比较运算?

在C语言中&#xff0c;比较运算用于比较两个值的大小关系。比较运算符包括等于&#xff08;&#xff09;、不等于&#xff08;!&#xff09;、大于&#xff08;>&#xff09;、小于&#xff08;<&#xff09;、大于等于&#xff08;>&#xff09;和小于等于&#xff0…

pycharm 配置 conda 新环境

1. conda 创建新环境 本章利用pycharm将conda新建的环境载入进去 关于conda的下载参考上一章博文&#xff1a;深度学习环境配置&#xff1a;Anaconda 安装和 pip 源 首先利用conda 新建虚拟环境 这里按 y 确定 安装好如下&#xff1a;这里两行命令代表怎么激活和关闭新建的虚…

顺序表、链表相关OJ题(2)

创作不易&#xff0c;友友们给个三连吧&#xff01;&#xff01; 一、旋转数组&#xff08;力扣&#xff09; 经典算法OJ题&#xff1a;旋转数组 思路1&#xff1a;每次挪动1位&#xff0c;右旋k次 时间复杂度&#xff1a;o(N^2) 右旋最好情况&#xff1a;k是n的倍数…

Verilog刷题笔记21

题目&#xff1a; A priority encoder is a combinational circuit that, when given an input bit vector, outputs the position of the first 1 bit in the vector. For example, a 8-bit priority encoder given the input 8’b10010000 would output 3’d4, because bit[4…