1024多人激情在线聊天室---select函数的使用
效果展示
step1.服务器启动!端口号3006

step2.1号客户端启动!jack加入了群聊

step3.2号客户端启动!kelly加入了群聊

step4.3号客户端启动!zwj加入了群聊

step5.开始聊天吧!zwj发出问候

step6.Kelly尴尬回应,并询问jack情况

step7.jack回到

具体代码实现(客户端)
在客户端,存在“收到消息”和“发送消息”这两个事件。其中“收到消息”是随机发生的。“收到消息”取决于其他客户端什么时候发送消息,而“发送消息”取决于用户什么时候键入数据。正是因为“收到消息”这个事件随机发生的,因此不能让程序被采集键盘数据所阻塞掉,这样会使得某个一直不发送消息的用户,无法及时收到其他用户的对话。因此需要使用select函数,对文件描述符监听。哪一个就就绪,就先处理哪一个事件。下面是客户端的核心代码段。
if(severfd > ){
printf("connction estabilshed\n");
FD_ZERO(&read_set);
FD_SET(,&read_set);
FD_SET(severfd,&read_set);
while(){
ready_set = read_set;
Select(severfd+,&ready_set,NULL,NULL,NULL);
if(FD_ISSET(,&ready_set)){
read(, sbuf, sizeof(sbuf));//send data to server
mergeMessage(name,sbuf,Message);
write(severfd,Message,StrLen(Message));
}
if(FD_ISSET(severfd,&ready_set)){
read(severfd, rbuf, sizeof(rbuf));
printf("%s",rbuf);
}
}
}else{
printf("fail to estabilsh connction\n");
}
第3行的ready_set和read_set是 fd_set类型结构体变量,在进入循环之前,已经为read_set做好了初始化。第5行将标准输入0,放置于fd_set中,第6行将从服务器返回的serverfd置于fd_set。在第10行使用select函数,监听0号和serverfd文件描述符,此时进程被挂起。0和serverfd谁先就绪,就会唤醒进程,继续处理下面两个if语句。如果是0号先就绪,那么从标准输入中读取数据,并将输入数据和nickname封装成Messgae,写至serverfd去。如果是serverfd先就绪,那么就从serverfd中读出数据,并打印至控制台显示。客户端代码较容易,逻辑简单,接下来讲述服务器端代码如何实现。
具体代码实现(服务器端)
在编写服务器代码时,也存在“接受新客户端的链接”和“推送消息”这两个事件。这两个事件都是随机发生的。“接受新客户端的链接”取决于客户端什么时候发起请求链接,向其他客户端“推送消息”取决于是否有新的消息被发送至服务器段。因此既不能让“推送消息”事件阻塞服务器,也不能让“接受新客户端的链接”事件阻塞服务器,而应是,哪一个事件先就绪,就先处理哪一个事件。否则的话,服务器要么就一直等待处理链接请求,要么就一直等待推送消息。服务器与客户端代码还有不同的一点是,服务器应该记录下所有客户发送的消息和客户端信息,然后才能将该客户发送的消息推送至其他客户端。因此服务器,应该设置一个数据结构,用于存储和记录所有客户端的信息。
服务器数据结构
服务器段用到的数据结构,该数据结构用于记录所有访问服务器的客户链接请求。其中nready和maxi用于减少遍历循环时的次数,每一次有客户端链接到服务器,就更新maxi的值,因为文件描述符在linux系统下,是从3开始递增(其中0,1,2为标准输入输出,2为标准错误输出)。clientfd是一个int数组用于记录所有客户端的文件描述符。clientfbuf是一个指针数组,每一个指针都指向客户端专属的缓冲器。服务器用此结构,记录每一个客户端的输入数据。
typedef struct {
fd_set read_set;
fd_set ready_set;
int nready;
int maxi;
int clientfd[FD_SETSIZE];
char* clientbuf[FD_SETSIZE];
} pool;
服务器核心代码
服务器在第4行使用select函数,将使得服务器被挂起,一旦当发生了请求链接事件,服务器将处理该链接,并将该请求添加至pool中,用于推送消息。
while () {
pool.ready_set = pool.read_set;
printf("waiting \n");
pool.nready = Select(pool.maxfd+, &pool.ready_set, NULL, NULL, NULL);
if (FD_ISSET(listenfd, &pool.ready_set)) {
connfd = Accept(listenfd, (SA *)&clientaddr, &clientlen);
add_client(connfd, &pool);
}
push_message(&pool);
}
下面是添加客户端的代码,每当有一个客户端成功和服务器成功建立起链接,就把该客户端的文件描述符存入结构中,并为其初始化buf。在第12行,把该文件描述符,加入到服务器的fd_set中,让服务器的select函数监听该客户端。
void add_client(int connfd, pool *p)
{
int i;
p->nready--;
for (i = ; i < FD_SETSIZE; i++)
if (p->clientfd[i] < ) { p->clientfd[i] = connfd; initBuf(&p->clientbuf[i]); FD_SET(connfd, &p->read_set); if (i > p->maxi)
p->maxi = i;
break;
}
}
下面是推送消息的代码,循环遍历pool,并从中取出文件描述符,和它对应的buf。然后并读出它所发送的数据,并在第16行将消息转发至除它以外所有的其他客户端。
void push_messgae(pool *p)
{
int i, connfd, n, j, cfd;
char *buf; for (i = ; (i <= p->maxi) && (p->nready > ); i++) {
connfd = p->clientfd[i];
buf = p-> clientbuf[i]; if ((connfd > ) && (FD_ISSET(connfd, &p->ready_set))) {
p->nready--;
if ((n = read(connfd, buf, sizeof(buf))) != ) {
printf("i am in,maxi = %d \n",p->maxi);
for(j=;j <= p->maxi;j++){
cfd = p->clientfd[j];
if(cfd == connfd) continue;
printf("transfering to %d\n",cfd);
write(cfd , buf, n);
}
}
else {
Close(connfd);
FD_CLR(connfd, &p->read_set);
p->clientfd[i] = -;
}
}
}
}
1024多人激情在线聊天室---select函数的使用的更多相关文章
- 基于JQuery+JSP的无数据库无刷新多人在线聊天室
JQuery是一款非常强大的javascript插件,本文就针对Ajax前台和JSP后台来实现一个无刷新的多人在线聊天室,该实现的数据全部存储在服务端内存里,没有用到数据库,本文会提供所有源程序,需要 ...
- Asp.NET MVC 使用 SignalR 实现推送功能二(Hubs 在线聊天室 获取保存用户信息)
简单介绍 关于SignalR的简单实用 请参考 Asp.NET MVC 使用 SignalR 实现推送功能一(Hubs 在线聊天室) 在上一篇中,我们只是介绍了简单的消息推送,今天我们来修改一下,实现 ...
- 三、jQuery--jQuery基础--jQuery基础课程--第12章 jQuery在线聊天室
在线聊天室案例 一.功能简介: 1.用户需要登录后才能进入聊天室交流 2.已无刷新的方式,动态展示交流后的内容和在线人员的基本信息 3.登录后的用户可以提交文字和表情图标 技术重点:利用ajax的无刷 ...
- AngularJS+Node.js+socket.io 开发在线聊天室
所有文章搬运自我的个人主页:sheilasun.me 不得不说,上手AngularJS比我想象得难多了,把官网提供的PhoneCat例子看完,又跑到慕课网把大漠穷秋的AngularJS实战系列看了一遍 ...
- SignalR实现在线聊天室功能
一.在线聊天室 1.新建解决方案 SignalROnlineChatDemo 2.新建MVC项目 SignalROnlineChatDemo.Web (无身份验证) 3.安装SignalR PM> ...
- 基于Server-Sent Event的简单在线聊天室
Web即时通信 所谓Web即时通信,就是说我们可以通过一种机制在网页上立即通知用户一件事情的发生,是不需要用户刷新网页的.Web即时通信的用途有很多,比如实时聊天,即时推送等.如当我们在登陆浏览知乎时 ...
- 在线聊天室的实现(1)--websocket协议和javascript版的api
前言: 大家刚学socket编程的时候, 往往以聊天室作为学习DEMO, 实现简单且上手容易. 该Demo被不同语言实现和演绎, 网上相关资料亦不胜枚举. 以至于很多技术书籍在讲解网络相关的编程时, ...
- 基于Server-Sent Event的简单聊天室 Web 2.0时代,即时通信已经成为必不可少的网站功能,那实现Web即时通信的机制有哪些呢?在这门项目课中我们将一一介绍。最后我们将会实现一个基于Server-Sent Event和Flask简单的在线聊天室。
基于Server-Sent Event的简单聊天室 Web 2.0时代,即时通信已经成为必不可少的网站功能,那实现Web即时通信的机制有哪些呢?在这门项目课中我们将一一介绍.最后我们将会实现一个基于S ...
- 百度前端面试题-类似slack的在线聊天室
别人国庆出去玩,我在家写代码的感觉也是很不错哒. 首先介绍一下技术架构吧! 使用了js框架:FFF,zepto,jquery,md5.min.js 前端框架:Bootstrap 后端:野狗,部分PHP ...
随机推荐
- Linux操作系统常用命令合集——第六篇-压缩和归档操作(16个命令)
1.gzip [命令作用] 压缩和解压缩文件 gzip/guzip/zcat zcat:不显式展开的前提下查看文本文件内容 zdiff/zgrep/zless/zmore [命令语法] gzip ...
- luogu 4587
假设当前已经组合好了 $[1, x]$ ,设 $ans = x + 1$ :显然初始时 $x = 0, ans = 1$ 我们另 $y = \sum_{i = l} ^ {r} (w_i <= ...
- OpenFOAM中的热传导?【翻译】
翻译自:CFD-online 帖子地址:http://www.cfd-online.com/Forums/openfoam/70758-conductive-heat-transfer-openfoa ...
- PaintCode 教程:矢量图轻松转换成CoreGraphics代码
本文译自Ranwenderlich的这篇:http://www.raywenderlich.com/100281/paintcode-for-designers-getting-started Pai ...
- faster-rcnn CUDA8.0编译错误
之前编译Faster-RCNN的时候用的都是CUDA7.5,最近换了机器,变成了CUDA8.0,果然编译出现错误了…… 参考下面这篇博客解决了问题: http://blog.csdn.net/kexi ...
- js回车键事件
js回车键事件 一.总结 一句话总结: $("#focus").keypress(function(event){if(event.which === 13) { /*点击回车要执 ...
- IDEA导航光标回退和前进快捷键失效
工作中突然发现IDEA里的Ctrl+Alt+Left/Right失效了,即导航光标的回退和前进,影响看代码的效率. 用Windows Hotkey Explorer查看,发现是被igfxHK.exe进 ...
- 将bat文件注册成为系统服务
第一章 注册系统服务准备 1.1 注册系统服务前准备 1.1.1 涉及第三方软件 Bat_To_Exe_Converter.exe (将*.bat文件转化为可执行*.exe文件) insts ...
- js根据数据条数与每页多少条数据计算页数,js前端计算页数
/** *根据数据条数与每页多少条数据计算页数 * totalnum 数据条数 * limit 每页多少条 */ function pageCount (totalnum,limit){ ...
- 手把手教你MyEclipseUML建模(下)
手把手教你MyEclipseUML建模(下) 点击访问:手把手教你MyEclipseUML建模(上) 1.用UML 2建模 MyEclipse提供了以下UML 2特性: UML 2图:类.组件.部署. ...