c语言实现io多路复用(select),进程,线程并发服务器

io多路复用(select)代码

#include<myhead.h>
#include <sys/select.h>
#define PORT 8888 
#define IP   "192.168.250.100"
int main(int argc, char const *argv[])
{    //创建套接字int sfd = socket(AF_INET, SOCK_STREAM, 0);if(sfd == -1){perror("socket error");return -1;}//端口重用int reuse = 1;if(setsockopt(sfd, SOL_SOCKET, SO_REUSEADDR, &reuse, sizeof(reuse)) == -1){perror("setsockopt error");return -1;}printf("设置端口快速重用成功 _%d_ %s_ %s_\n", __LINE__, __FILE__, __func__);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 _%d_ %s_ %s_\n", __LINE__, __FILE__, __func__);//监听模式if(listen(sfd, 128) == -1){perror("listen error");return -1;}printf("listen success _%d_ %s_ %s_\n", __LINE__, __FILE__, __func__);struct sockaddr_in cin;             //客户端地址信息结构体cin.sin_family     = AF_INET;socklen_t socklen = sizeof(cin);          //客户端地址信息的大小//定义文件描述符集合fd_set readfds, tempfds;//清空readfdsFD_ZERO(&readfds);//将套接字和标准输入放入集合FD_SET(sfd,&readfds);FD_SET(0,&readfds);//定义信息容器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++){if(!FD_ISSET(i, &tempfds)){continue;}if( i == sfd){newfd = accept(sfd, (struct sockaddr*)&cin, &socklen);if(newfd == -1){perror("accept error");return -1;}printf("accept success _%d_ %s_ %s_\n", __LINE__, __FILE__, __func__);//将新的套接字放入select集合           FD_SET(newfd , &readfds);//更新maxfdif(newfd > maxfd){maxfd = newfd;}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;break;}}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);send(i, buf, sizeof(buf), 0); } }}return 0;
}

io多路复用(select)结果图

进程代码

#include<myhead.h>
#define PORT 8888 
#define IP   "192.168.250.100"
//处理客户端请求
int cli_msg(int newfd,struct sockaddr_in cin)
{char buf[128]="";while (1){bzero(buf, sizeof(buf));int res = recv(newfd, buf, sizeof(buf), 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);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, char const *argv[])
{//创建套接字int sfd = socket(AF_INET, SOCK_STREAM, 0);if(sfd == -1){perror("socket error");return -1;}//设置端口重用int reuse = 1;if(setsockopt(sfd, SOL_SOCKET, SO_REUSEADDR, &reuse, sizeof(reuse)) == -1){perror("setsockopt error");return -1;}printf("设置端口快速重用成功 _%d_ %s_ %s_\n", __LINE__, __FILE__, __func__);//设定地址信息结构体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 _%d_ %s_ %s_\n", __LINE__, __FILE__, __func__);//开启监听if(listen(sfd, 128) == -1){perror("listen error");return -1;}printf("listen success _%d_ %s_ %s_\n", __LINE__, __FILE__, __func__);struct sockaddr_in cin;             //客户端地址信息结构体cin.sin_family     = AF_INET;socklen_t socklen = sizeof(cin);          //客户端地址信息的大小pid_t pid;//绑定进程的信号,信号触发就执行handler函数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;}//创建子进程pid = fork();//父进程负责连接if(pid > 0){//父进程不用newfd,回收newfdclose(newfd);}//子进程负责请求响应else if(pid==0){//子进程不用sfd,就回收sfdclose(sfd);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.250.100"
//定义存储客户端地址信息结构体和连接请求套接字的结构体
struct msg_info{int newfd;struct sockaddr_in cin;
};//定义线程体
void *task1(void *arg)
{//将外部值传入int newfd=((struct msg_info*)arg)->newfd;struct sockaddr_in cin=((struct msg_info*)arg)->cin;//定义收发容器char buf[128]="";while (1){//响应客户端请求bzero(buf,sizeof(buf));int res=recv(newfd,buf,sizeof(buf),0);if(res==0){printf("客户端已经下线");break; }else if(res>0){printf("[%s:%d]:%s\n", inet_ntoa(cin.sin_addr), ntohs(cin.sin_port), buf);send(newfd,buf,sizeof(buf),0);}else{perror("recv error:");return NULL;}}//关闭连接套接字close(newfd);//退出线程pthread_exit(NULL);
}
int main(int argc, char const *argv[])
{pthread_t tid;int sfd=socket(AF_INET,SOCK_STREAM,0);int reuse = 1;if(setsockopt(sfd, SOL_SOCKET, SO_REUSEADDR, &reuse, sizeof(reuse)) == -1){perror("setsockopt error");return -1;}printf("设置端口快速重用成功 _%d_ %s_ %s_\n", __LINE__, __FILE__, __func__);//绑定的地址信息结构体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 _%d_ %s_ %s_\n", __LINE__, __FILE__, __func__);//将套接字设置成监听状态if(listen(sfd, 128) == -1){perror("listen error");return -1;}printf("listen success _%d_ %s_ %s_\n", __LINE__, __FILE__, __func__);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 _%d_ %s_ %s_\n", __LINE__, __FILE__, __func__);//定义用于向线程体传参的结构体变量struct msg_info info = {newfd, cin};//线程创建,并向线程体传参的结构体pthread_create(&tid,NULL,task1,&info);//线程分离if(pthread_detach(tid) != 0){printf("分离失败\n");return -1;}}close(sfd);return 0;
}

线程结果图

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

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

相关文章

小米电脑管家-非小米电脑安装教程

​​第一步&#xff1a;去浏览器搜索小米跨终端智联官网 下载小米电脑管家 如果是小米电脑&#xff0c;直接安装就行了 这里主要讲的是不是小米电脑&#xff0c;怎么去安装&#xff1f; 不是小米电脑就需要下载免检测机型插件&#xff0c;不然安装不了的 第二步&#xff1a;…

解决端口被占用问题

写文章原因: 本人在安装alist的时候,在使用5244端口的时候,显示端口被占用,于是想查看一下端口是被什么程序占用了,是否可以杀死占用的程序,还是更换端口. failed to start http: listen tcp 0.0.0.0:5244: bind: Only one usage of each socket address (protocol/network a…

幻兽帕鲁服务器搭建最简单新手教程,10秒钟自动部署,一键开服(腾讯云)

以下教程是基于腾讯云轻量应用服务器搭建的&#xff0c;非常简单&#xff0c;无论搭建幻兽帕鲁还是其他的游戏或者应用&#xff0c;都能以非常快的速度部署好。而且稳定流畅&#xff0c;功能丰富。 下面就来一起看看如何搭建吧。 幻兽帕鲁腾讯云服务器购买与一键部署教程&…

【Qt学习笔记】Qt Creator环境下 信号与槽 详解(自定义信号槽、断连、lambda表达式等)

文章目录 1. 信号槽概念1.1 信号的本质1.2 槽的本质1.3 标准信号槽1.4 信号槽 实例 2. 自定义信号槽2.1 自定义槽函数2.2 自定义信号2.3 带参 信号槽 3. 信号槽的意义 与 作用4. 信号槽断连 &#xff08;了解&#xff09;5. lamda表达式的使用5.1 基本用法5.2 捕获局部变量5.3 …

如何查看端口映射?

端口映射是一种用于实现远程访问的技术。通过将外网端口与内网设备的特定端口关联起来&#xff0c;可以使外部网络用户能够通过互联网访问内部网络中的设备和服务。在网络中使用端口映射可以解决远程连接需求&#xff0c;使用户能够远程访问设备或服务&#xff0c;无论是在同一…

python-分享篇-画樱花

文章目录 画樱花代码效果 画樱花 代码 from turtle import * from random import * from math import *def tree(n,l):pd()#下笔#阴影效果t cos(radians(heading()45))/80.25pencolor(t,t,t)pensize(n/3)forward(l)#画树枝if n>0:b random()*1510 #右分支偏转角度c ran…

Linux操作系统基础(二):Linux操作系统概述

文章目录 Linux操作系统概述 一、Linux起源 二、Linux 的含义 三、Linux发行版 Linux操作系统概述 一、Linux起源 Linux创始人——林纳斯 托瓦兹 Linux 诞生于1991年&#xff0c;作者上大学期间实现的 Linux的特点&#xff1a;开源、免费、拥有最为庞大的源码贡献者 …

MySQL数据库语句总结

一. 数据定义语言 DDL 数据定义语言&#xff0c;用来定义数据库对象的&#xff08;比如&#xff1a;数据库、表、字段等&#xff09; 1. 数据库操作 &#xff08;1&#xff09;查询所有的数据库 —— show databases; &#xff08;2&#xff09;创建数据库 —— create dat…

C语言第二十一弹---指针(五)

✨个人主页&#xff1a; 熬夜学编程的小林 &#x1f497;系列专栏&#xff1a; 【C语言详解】 【数据结构详解】 转移表 1、转移表 总结 1、转移表 函数指针数组的用途&#xff1a;转移表 举例&#xff1a;计算器的⼀般实现&#xff1a; 假设我们需要做一个能够进行加减…

Qt 常用算法及正则表达式

目录 常用算法 正则表达式 常用算法 double c qAbs(a)&#xff0c;函数 qAbs() 返回 double 型数值 a 的绝对值 double max qMax(b,c)&#xff0c;函数 qMax() 返回两个数值中的最大值 int bnqRound(b)&#xff0c;返回一个与浮点数最接近的整数值(四舍五入) int cn q…

TI的电量计驱动在卸载时导致Linux卡死

背景 最近移植TI电量计芯片bq40z50的驱动&#xff0c;移植完毕后&#xff0c;能正常读取电池信息了&#xff0c;但是无意中发现驱动卸载会导致Linux卡死&#xff0c;死前终端闪过大量打印&#xff0c;将putty的缓冲区都耗尽了&#xff0c;必须启用syslog转发并用visual syslog…

Python循环语句——range语句

一、引言 在Python编程中&#xff0c;range函数是一个内置函数&#xff0c;用于生成一个不可变的数字序列。它常被用于循环结构&#xff0c;如for循环&#xff0c;来遍历一系列的数字。尽管其使用非常基础&#xff0c;但range的强大之处在于其提供了灵活性&#xff0c;可以创建…