用select实现多客户端连接
server.c
把accept也看成是一个read类型的函数, 于是我们可以把sockfd也放入到select中
maxi标记当前客户端连接数组的最大下标
select返回值为当前已经准备就绪的fd总数
#include <unistd.h>
#include <netdb.h>
#include <errno.h>
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <signal.h>
#include <sys/wait.h>
#include <sys/select.h>
#include <sys/socket.h>
#include <arpa/inet.h>
#include <netinet/in.h>
#define MAX(a,b) a>b?a:b;
void err_quit(const char *s){
perror(s);
exit(1);
}
ssize_t readn(int fd,void *buff,size_t count){
char *buffp;
ssize_t nread;
size_t nleft;
buffp=(char *)buff;
nleft=count;
while(nleft > 0){
if((nread = read(fd,buffp,nleft)) < 0){
if(errno == EINTR)
continue;
else
return -1;
}else if(nread == 0)
break;
nleft -= nread;
buffp += nread;
}
return count-nleft;
}
ssize_t writen(int fd,const void *buff,size_t n){
size_t nleft;
ssize_t nwritten;
const char *ptr;
ptr=buff;
nleft=n;
while(nleft > 0){
if((nwritten=write(fd,ptr,nleft)) < 0){
if(nwritten < 0 && errno == EINTR)
continue;
else
return -1;
}else if(nwritten == 0)
break;
nleft -= nwritten;
ptr += nwritten;
}
return n-nleft;
}
ssize_t recv_peek(int fd,void *buf,size_t len){
ssize_t ret;
while(1){
ret=recv(fd,buf,len,MSG_PEEK);
if(ret == -1 && errno == EINTR)
continue;
return ret;
}
}
ssize_t readline(int fd,void *buf,size_t maxline){
ssize_t ret;
size_t nread;
size_t nleft;
char *bufp;
bufp=buf;
nleft=maxline;
while(1){
ret=recv_peek(fd,buf,nleft);
if(ret < 0)
return ret;
else if(ret == 0)
return ret;
nread=ret;
int i;
for(i=0;i<nread;i++){
if(bufp[i] == '\n'){
ret=readn(fd,bufp,i+1);
if(ret != i+1)
err_quit("readn");
return ret;
}
}
if(nread > nleft)
err_quit("readn");
nleft -= nread;
ret=readn(fd,bufp,nread);
if(ret != nread)
err_quit("readn");
bufp += nread;
}
return -1;
}
int main(int argc,char *argv[]){
int i,maxi,maxfd,tmpfd,sockfd,connfd;
socklen_t len;
struct sockaddr_in addr,client;
fd_set rset,allset;
int nready,clientfd[FD_SETSIZE];
ssize_t n;
char buf[1024];
if((sockfd=socket(PF_INET,SOCK_STREAM,0)) < 0)
err_quit("sockfd");
bzero(&addr,sizeof(addr));
addr.sin_family=AF_INET;
addr.sin_addr.s_addr=htonl(INADDR_ANY);
addr.sin_port=htons(5566);
int on=1;
if(setsockopt(sockfd,SOL_SOCKET,SO_REUSEADDR,&on,sizeof(on)) <0)
err_quit("setsockopt");
if(bind(sockfd,(struct sockaddr *)&addr,sizeof(addr))<0)
err_quit("bind");
if(listen(sockfd,10)<0)
err_quit("listen");
maxfd=sockfd;
maxi=-1;
for(i=0;i<FD_SETSIZE;i++)
clientfd[i]=-1;
FD_ZERO(&allset);
FD_SET(sockfd,&allset);
while(1){
rset=allset;
nready=select(maxfd+1,&rset,NULL,NULL,NULL);
if(nready == -1){
if(errno == EINTR)
continue;
else
err_quit("select");
}
if(FD_ISSET(sockfd,&rset)){
len=sizeof(client);
connfd=accept(sockfd,(struct sockaddr *)&client,&len);
if(connfd < 0)
err_quit("accept");
for(i=0;i<FD_SETSIZE;i++){
if(clientfd[i] < 0){
clientfd[i]=connfd;
break;
}
}
if(i == FD_SETSIZE)
err_quit("too many clients");
FD_SET(connfd,&allset);
if(connfd > maxfd)
maxfd=connfd;
if(i>maxi)
maxi=i;
if(--nready <= 0)
continue;
}
for(i=0;i<=maxi;i++){
if((tmpfd=clientfd[i]) < 0)
continue;
if(FD_ISSET(tmpfd,&rset)){
bzero(buf,sizeof(buf));
if((n=readline(tmpfd,buf,sizeof(buf))) == 0){
close(tmpfd);
FD_CLR(tmpfd,&allset);
clientfd[i]=-1;
}
write(STDOUT_FILENO,buf,n);
writen(tmpfd,buf,n);
if(--nready <= 0)
break;
}
}
}
}
client.c
fileno函数的作用把FILE *型转换电脑int fd型
此实例用了shutdown方法
#include <unistd.h>
#include <signal.h>
#include <errno.h>
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <sys/socket.h>
#include <sys/types.h>
#include <arpa/inet.h>
#include <netinet/in.h>
#define MAX(a,b) a>b?a:b;
void err_quit(const char *s){
perror(s);
exit(1);
}
ssize_t readn(int fd,void *buff,size_t count){
size_t nleft;
ssize_t nread;
char *ptr;
nleft=count;
ptr=(char *)buff;
while(nleft > 0){
if((nread=read(fd,ptr,nleft)) < 0){
if(errno == EINTR)
continue;
else
return -1;
}else if(nread == 0)
break;
ptr += nread;
nleft -= nread;
}
return count - nleft;
}
ssize_t writen(int fd,const void *buff,size_t n){
size_t nleft;
ssize_t nwritten;
const char *ptr;
nleft=n;
while(n > 0){
if((nwritten=write(fd,buff,nleft)) < 0){
if(errno == EINTR)
continue;
else
return -1;
}else if(nwritten == 0)
break;
nleft -= nwritten;
ptr += nwritten;
}
return n-nleft;
}
/* if have any data then return */
ssize_t recv_peek(int fd,void *buf,size_t len){
ssize_t ret;
while(1){
ret=recv(fd,buf,len,MSG_PEEK);
if(ret == -1 && errno == EINTR)
continue;
return ret;
}
}
ssize_t readline(int fd,void *buf,size_t maxline){
ssize_t ret;
size_t nread;
size_t nleft;
char *bufp;
bufp=buf;
nleft=maxline;
while(1){
ret=recv_peek(fd,buf,nleft);
if(ret < 0)
return ret;
else if(ret == 0)
return ret;
nread=ret;
int i;
for(i=0;i<nread;i++){
if(bufp[i] == '\n'){
ret=readn(fd,bufp,i+1);
if(ret != i+1)
err_quit("readn");
return ret;
}
}
if(nread > nleft)
err_quit("nread");
nleft -= nread;
ret=readn(fd,bufp,nread);
if(ret != nread)
err_quit("readn");
bufp += nread;
}
return -1;
}
int main(int argc,char *argv[]){
int sockfd,maxfd;
int nready;
struct sockaddr_in servaddr;
fd_set fileset;
char buf[1024];
int stdineof;
if((sockfd=socket(PF_INET,SOCK_STREAM,0)) < 0)
err_quit("socket");
bzero(&servaddr,sizeof(servaddr));
servaddr.sin_family=AF_INET;
servaddr.sin_addr.s_addr=inet_addr("127.0.0.1");
servaddr.sin_port=htons(5566);
if(connect(sockfd,(struct sockaddr *)&servaddr,sizeof(servaddr)) <0)
err_quit("connect");
bzero(buf,sizeof(buf));
FD_ZERO(&fileset);
stdineof=0;
while(1){
if(stdineof == 0)
FD_SET(fileno(stdin),&fileset);
FD_SET(sockfd,&fileset);
maxfd=MAX(fileno(stdin),sockfd);
nready=select(maxfd+1,&fileset,NULL,NULL,NULL);
if(nready == -1){
if(errno == EINTR)
continue;
else
err_quit("select");
}
if(FD_ISSET(fileno(stdin),&fileset)){
if(fgets(buf,sizeof(buf),stdin) == NULL){
stdineof=1;
shutdown(sockfd,SHUT_WR);
FD_CLR(fileno(stdin),&fileset);
continue;
}else{
writen(sockfd,buf,strlen(buf));
bzero(buf,sizeof(buf));
}
}
if(FD_ISSET(sockfd,&fileset)){
int ret=readline(sockfd,buf,sizeof(buf));
if(ret == -1)
err_quit("read");
if(ret == 0){
if(stdineof == 1)
exit(0);
else
err_quit("readline");
}
fputs(buf,stdout);
bzero(buf,sizeof(buf));
}
}
}
用select实现多客户端连接的更多相关文章
- 配置ORACLE 客户端连接到数据库
--================================= -- 配置ORACLE 客户端连接到数据库 --================================= Oracle ...
- Oracle RAC 客户端连接负载均衡(Load Balance)
实现负载均衡(Load Balance)是Oracle RAC最重要的特性之一,主要是把负载平均分配到集群中的各个节点,以提高系统的整体吞吐能力.通常情况下有两种方式来实现负载均衡,一个是基于客户端连 ...
- [20171106]配置客户端连接注意.txt
[20171106]配置客户端连接注意.txt --//在配置客户端连接时一般建议使用Net Manager工具,windows下调用执行Net Manager.--//linux下执行 netmgr ...
- 一个I/O线程可以并发处理N个客户端连接和读写操作 I/O复用模型 基于Buf操作NIO可以读取任意位置的数据 Channel中读取数据到Buffer中或将数据 Buffer 中写入到 Channel 事件驱动消息通知观察者模式
Tomcat那些事儿 https://mp.weixin.qq.com/s?__biz=MzI3MTEwODc5Ng==&mid=2650860016&idx=2&sn=549 ...
- redis客户端连接到服务器的步骤
和大多数客户端连接到服务器一样,redis-cli连接到服务器也主要分为两个阶段,请求连接阶段和数据传送阶段.具体来讲redis-cli做的事情有: 1.以socket方式建立连接: 2,选择相应的数 ...
- Netty源码分析 (六)----- 客户端连接接入accept过程
通读本文,你会了解到1.netty如何接受新的请求2.netty如何给新请求分配reactor线程3.netty如何给每个新连接增加ChannelHandler netty中的reactor线程 ne ...
- MySql 8.0.11 客户端连接失败:2059 - Authentication plugin 'caching_sha2_password' cannot be loaded: ....
近期,换了新笔记本,重新安装了MySql数据库和客户端工具Navicat Premium 12.我是从官网上下载的MySql数据库,版本为8.0.11,链接:https://dev.mysql.com ...
- netty(二)---客户端连接
概述 先了解一下 netty 大概框架图 ,可以看到客户端的创建和服务端最大的区别 - 服务端传入两个 EventLoopGroup,客户端传入一个 EventLoopGroup - channel ...
- 设置MySQL客户端连接使用的字符集
设置MySQL客户端连接使用的字符集 时间:2014-03-05 来源:服务器之家 投稿:root 考虑什么是一个"连接":它是连接服务器时所作的事情.客户端发送SQL ...
随机推荐
- 利用Spring实现Hello World
因为最近要做Java Web方面的开发,所以,就像使用Spring来实现一个以前学其他程序时首先做的一个示例"Hello World!"练练手,之前用很多中语言实现过hello w ...
- 第一天学习如何使用markdown写日志,一起来看看成果吧!
目录 一级标题 二级标题 一级标题 二级标题 ==黄色== one two three one two three 性别 年龄 男 150 H~2~o hello markdown hello mar ...
- C#设计模式:组合模式(Composite Pattern)
一,C#设计模式:组合模式(Composite Pattern) using System; using System.Collections.Generic; using System.Linq; ...
- springcloud费话之Eureka服务访问(restTemplate)
目录: springcloud费话之Eureka基础 springcloud费话之Eureka集群 springcloud费话之Eureka服务访问(restTemplate) springcloud ...
- 日期格式化:SimpleDateFormat【线程不安全】、FastDateFormat和Joda-Time【后两个都是线程安全】
SimpleDateFormat是线程不安全的,不能多个线程公用.而FastDateFormat和Joda-Time都是线程安全的,可以放心使用. SimpleDateFormat是JDK提供的,不需 ...
- openstack--all-in-one部署
安装过程 本次宿主机(即安装OpenStack的机器)的操作系统是CentOS 7.5.安装的OpenStack是目前最新的rocky版本,官方文档建议机器至少有16 GB的内存,处理器硬件虚拟化扩展 ...
- IBM和DoE推出世界上最快的超级计算机
IBM和美国能源部的橡树岭国家实验室今天发布了该部门最新的超级计算机Summit.IBM声称峰会目前是世界上“最强大,最聪明的科学超级计算机”,其峰值性能每秒高达20万亿次.当新的榜单在本月晚些时候发 ...
- Win7 ODBC驱动 Excel (转)
“控制面板-管理工具-数据源(ODBC)”,打开“ODBC数据源管理器”窗口,然后“添加”,打开“创建新数据源”的窗口,最后选择Microsoft Access Driver(*.mdb)选项,往后等 ...
- C#基础提升系列——C#异步编程
C#异步编程 关于异步的概述,这里引用MSDN的一段文字: 异步编程是一项关键技术,使得能够简单处理多个核心上的阻塞 I/O 和并发操作. 如果需要 I/O 绑定(例如从网络请求数据或访问数据库),则 ...
- Java反射学习-5 - 反射复制对象
通过反射方式复制对象: package cn.tx.reflect; import java.lang.reflect.Constructor; import java.lang.reflect.Fi ...