效果展示

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. hdu 5452

    无意中看到这道题 没读懂英文题面 百度题解寻找题面 看到: #include <iostream> #include <cstdio> #include <algorit ...

  2. Java 【打印俄文的英文字母】

    俄文的的字符可以用 'A' 到 'Я '. public class main { public static void main(String args[]) { char S = 'А', C = ...

  3. [bzoj 4939][Ynoi 2016]掉进兔子洞

    传送门 Description 一个长为 n 的序列 a. 有 m 个询问,每次询问三个区间,把三个区间中同时出现的数一个一个删掉,问最后三个区间剩下的数的个数和,询问独立. 注意这里删掉指的是一个一 ...

  4. codeforces319C

    C. Kalila and Dimna in the Logging Industry time limit per test 2 seconds memory limit per test 256 ...

  5. Java 交换两数的方法

    错误示范 1. 直接交换 public class SwapNumbers { // 直接交换 public static void swap(int a, int b) { int temp = a ...

  6. OpenJudge计算概论-取石子游戏

    OpenJudge计算概论-取石子游戏[函数递归练习] /*====================================================================== ...

  7. OpenJudge计算概论-整数的个数

    /*========================================================== 整数的个数 总时间限制: 1000ms 内存限制: 65536kB 描述 给定 ...

  8. Tosca new project Repository as MS SQL Server

    # 然后对应的服务器就能自己给创建对应的数据库

  9. 放射渐变RadialGradient

    public RadialGradient(float centerX, float centerY, float radius, int[] colors, float[] stops, TileM ...

  10. 字典学习(Dictionary Learning)

    0 - 背景 0.0 - 为什么需要字典学习? 这里引用这个博客的一段话,我觉得可以很好的解释这个问题. 回答这个问题实际上就是要回答“稀疏字典学习 ”中的字典是怎么来的.做一个比喻,句子是人类社会最 ...