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));
}
}
}

最新文章

  1. Android消息传递之基于RxJava实现一个EventBus - RxBus
  2. jquery的checkbox 全选和全不选
  3. Pycharm注册码(2016.2)
  4. JavaScript(七)——视频插入
  5. Laravel 安装多国语言包后,phpstorm 还是报错
  6. 电影成生活O2O必争之地,破局之战就此拉开
  7. JSP生成条形码
  8. php定时执行脚本
  9. Android 画图类View与SurfaceView之学习
  10. 天坑 之 Eclipse J2EE Preview 运行正确项目一直显示http 404
  11. Solr搜索技术
  12. Android -传统蓝牙通信聊天
  13. 蓝牙Legacy Pairing流程概述
  14. for...in的改进版for...of
  15. python_数据类型
  16. MySQL日志功能详解
  17. HTML、CSS、JS 样式 (未整理)
  18. 学习Java的方法
  19. 爬虫Scrapy框架
  20. HTTP的response code 1xx,2xx,3xx,4xx,5xx分别代表什么

热门文章

  1. tab区域折叠
  2. jvm性能监控(3)-jdk自带工具 jps jstack jmap
  3. python安装numpy
  4. 怎么区分PV、IV、UV以及网站统计名词解释(pv、曝光、点击)
  5. Saying goodbye to Flash in Chrome一代人的回忆FLASH
  6. 从0构建webpack开发环境(三) 开发环境以及 webpack-dev-server 的使用
  7. 手写call、apply、bind
  8. .ef core 多对对关系的关联方法
  9. Solr的学习使用之(二)schema.xml等配置文件的解析
  10. weblogic启动脚本01