效果展示

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函数的使用的更多相关文章

  1. 基于JQuery+JSP的无数据库无刷新多人在线聊天室

    JQuery是一款非常强大的javascript插件,本文就针对Ajax前台和JSP后台来实现一个无刷新的多人在线聊天室,该实现的数据全部存储在服务端内存里,没有用到数据库,本文会提供所有源程序,需要 ...

  2. Asp.NET MVC 使用 SignalR 实现推送功能二(Hubs 在线聊天室 获取保存用户信息)

    简单介绍 关于SignalR的简单实用 请参考 Asp.NET MVC 使用 SignalR 实现推送功能一(Hubs 在线聊天室) 在上一篇中,我们只是介绍了简单的消息推送,今天我们来修改一下,实现 ...

  3. 三、jQuery--jQuery基础--jQuery基础课程--第12章 jQuery在线聊天室

    在线聊天室案例 一.功能简介: 1.用户需要登录后才能进入聊天室交流 2.已无刷新的方式,动态展示交流后的内容和在线人员的基本信息 3.登录后的用户可以提交文字和表情图标 技术重点:利用ajax的无刷 ...

  4. AngularJS+Node.js+socket.io 开发在线聊天室

    所有文章搬运自我的个人主页:sheilasun.me 不得不说,上手AngularJS比我想象得难多了,把官网提供的PhoneCat例子看完,又跑到慕课网把大漠穷秋的AngularJS实战系列看了一遍 ...

  5. SignalR实现在线聊天室功能

    一.在线聊天室 1.新建解决方案 SignalROnlineChatDemo 2.新建MVC项目 SignalROnlineChatDemo.Web (无身份验证) 3.安装SignalR PM> ...

  6. 基于Server-Sent Event的简单在线聊天室

    Web即时通信 所谓Web即时通信,就是说我们可以通过一种机制在网页上立即通知用户一件事情的发生,是不需要用户刷新网页的.Web即时通信的用途有很多,比如实时聊天,即时推送等.如当我们在登陆浏览知乎时 ...

  7. 在线聊天室的实现(1)--websocket协议和javascript版的api

    前言: 大家刚学socket编程的时候, 往往以聊天室作为学习DEMO, 实现简单且上手容易. 该Demo被不同语言实现和演绎, 网上相关资料亦不胜枚举. 以至于很多技术书籍在讲解网络相关的编程时, ...

  8. 基于Server-Sent Event的简单聊天室 Web 2.0时代,即时通信已经成为必不可少的网站功能,那实现Web即时通信的机制有哪些呢?在这门项目课中我们将一一介绍。最后我们将会实现一个基于Server-Sent Event和Flask简单的在线聊天室。

    基于Server-Sent Event的简单聊天室 Web 2.0时代,即时通信已经成为必不可少的网站功能,那实现Web即时通信的机制有哪些呢?在这门项目课中我们将一一介绍.最后我们将会实现一个基于S ...

  9. 百度前端面试题-类似slack的在线聊天室

    别人国庆出去玩,我在家写代码的感觉也是很不错哒. 首先介绍一下技术架构吧! 使用了js框架:FFF,zepto,jquery,md5.min.js 前端框架:Bootstrap 后端:野狗,部分PHP ...

随机推荐

  1. decodeURI 与 decodeURIComponent 区别

    1. 关于URL.encodeURI 及 encodeURIComponent: URI: Uniform Resource Identifiers,通用资源标识符 Global 对象的 encode ...

  2. css3 perspective与translateZ变换

    css3中的坐标系,rotateX就是绕着x轴旋转,rotateY就是绕着Y轴旋转,rotateZ就是绕着z轴旋转(也就是xy平面的旋转). perspective属性用来设置视点,在css3的模型中 ...

  3. 由Java正则表达式的灾难性回溯引发的高CPU异常:java.util.regex.Pattern$Loop.match

    问题与分析 某天领导report了一个问题:线上的CPU自从上一个版本迭代后就一直处于居高不下的状况,领导看着这段时间的曲线图判断是有两条线程在不停的死循环. 接到任务后去查看了AWS的CloudWa ...

  4. 将制定目录家到系统PATH环境变量中

    1.打开系统文件sudo vim/etc/profile,请输入root密码 2.在appendpath '/usr/local/sbin' appendpath '/usr/local/bin' a ...

  5. ibm 汇编

    https://www.ibm.com/developerworks/cn/linux/l-assembly/index.html https://72k.us/file/4031001-328073 ...

  6. MAC常用快捷键 基本常用的都整理在这里了

    写在前面Mac系统中有几个比较特殊的功能键,和Win系统的区别也主要在这里比如在Win系统中我们常用的Ctrl键,在Mac系统中对应的不是长得比较像的Cnotrol,而是Command键,貌似也是Ma ...

  7. Flutter移动电商实战 --(49)详细页_Stack制作底部工具栏

    一直悬浮在最下面的 Stack层叠组件.里面用Row 可以横向布局 开始 stack如果想定位就要用position去定位. 修改return返回值的这个地方 大R刷新查看效果,可以看到固定的在左下角 ...

  8. 阶段5 3.微服务项目【学成在线】_day18 用户授权_04-方法授权-方法授权实现

    2.3 方法授权实现 2.3.1资源服务添加授权控制 1.要想在资源服务使用方法授权,首先在资源服务配置授权控制 1)添加spring-cloud-starter-oauth2依赖. 2)拷贝授权配置 ...

  9. Qt使用boost库

    1.在官网下载boost库 boost_1_70_0.zip 2.将你的Qt的工具目录(有gcc.exe)设置环境变量.(比如F:\Qt592\Tools\mingw530_32\bin) 3.在命令 ...

  10. Django之model详解

    Django中的页面管理后台 Djano中自带admin后台管理模块,可以通过web页面去管理,有点想php-admin,使用步骤: 在项目中models.py 中创建数据库表 class useri ...