基于epoll的聊天室程序

epoll相对于poll和select这两个多路复用的I/O模型更加的高效。epoll的函数很简单,麻烦的地方在于水平触发和边沿触发。

用张图来说明下

ET(边沿)只是在状态反转时触发,比如从不可读到可读。而LT(水平)就是如果可读,就会一直触发。所以在使用ET的时候要做一些额外的处理,比如可读的,一直把缓冲区读完,进入不可读状态,下次来数据才会触发。

下面贴出代码,只是一个简单的练习的例子
socketheads.h

C++

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

#ifndef SOCKETHEADS_H

#define SOCKETHEADS_H

#include <sys/types.h>

#include <sys/socket.h>

#include <stdio.h>

#include <stdlib.h>

#include <errno.h>

#include <string.h>

#include <unistd.h>

#include <netinet/in.h>

#include <fcntl.h>

#include <netinet/in.h>

#include <arpa/inet.h>

#endif //SOCKETHEADS_H

zepoll.h

C++

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

25

26

27

28

29

30

31

32

33

34

35

36

37

38

39

40

41

42

43

44

#ifndef EPOLL_H

#define EPOLL_H

#include <sys/epoll.h>

#include <unistd.h>

/**

* @brief The Epoll class 对epoll的封装

*/

class Epoll

{

public:

/**

*

*/

enum EPOLL_OP {ADD = EPOLL_CTL_ADD, MOD = EPOLL_CTL_MOD, DEL = EPOLL_CTL_DEL};

/**

* 最大的连接数和最大的回传事件数

*/

Epoll(int _max = 30, int maxevents = 20);

~Epoll();

int create();

int add(int fd, epoll_event *event);

int mod(int fd, epoll_event *event);

int del(int fd, epoll_event *event);

void setTimeout(int timeout);

void setMaxEvents(int maxevents);

int wait();

const epoll_event* events() const;

const epoll_event& operator[](int index)

{

return backEvents[index];

}

private:

bool isValid() const;

int max;

int epoll_fd;

int epoll_timeout;

int epoll_maxevents;

epoll_event *backEvents;

};

#endif //EPOLL_H

zepoll.cpp

C++

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

25

26

27

28

29

30

31

32

33

34

35

36

37

38

39

40

41

42

43

44

45

46

47

48

49

50

51

52

53

54

55

56

57

58

59

60

61

62

63

64

65

66

67

68

69

70

71

72

73

74

75

76

77

78

79

80

81

82

83

84

85

86

87

88

#include "zepoll.h"

Epoll::Epoll(int _max, int maxevents):max(_max),

epoll_fd(-1),

epoll_timeout(0),

epoll_maxevents(maxevents),

backEvents(0)

{

}

Epoll::~Epoll()

{

if (isValid()) {

close(epoll_fd);

}

delete[] backEvents;

}

inline

bool Epoll::isValid() const

{

return epoll_fd > 0;

}

inline

void Epoll::setTimeout(int timeout)

{

epoll_timeout = timeout;

}

inline

void Epoll::setMaxEvents(int maxevents)

{

epoll_maxevents = maxevents;

}

inline

const epoll_event* Epoll::events() const

{

return backEvents;

}

int Epoll::create()

{

epoll_fd = ::epoll_create(max);

if (isValid()) {

backEvents = new epoll_event[epoll_maxevents];

}

return epoll_fd;

}

int Epoll::add(int fd, epoll_event *event)

{

if (isValid()) {

return ::epoll_ctl(epoll_fd, ADD, fd, event);

}

return -1;

}

int Epoll::mod(int fd, epoll_event *event)

{

if (isValid()) {

return ::epoll_ctl(epoll_fd, MOD, fd, event);

}

return -1;

}

int Epoll::del(int fd, epoll_event *event)

{

if (isValid()) {

return ::epoll_ctl(epoll_fd, DEL, fd, event);

}

return -1;

}

int Epoll::wait()

{

if (isValid()) {

return ::epoll_wait(epoll_fd, backEvents, epoll_maxevents, epoll_timeout);

}

return -1;

}

task.h

C++

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

25

26

27

28

29

30

31

32

33

34

35

36

37

38

39

/********************************************************************

* author 周翔

* e-mail [email protected]

* blog http://blog.csdn.net/zhx6044

**********************************************************************/

#ifndef TASK_H

#define TASK_H

#include <string>

#include <socketheads.h>

/**

* @brief The Task class 任务类

*/

class Task

{

public:

typedef enum {CONNECT = 0, DISCONNECT, TALKING} TASKFLAG;

Task(const std::string &message, TASKFLAG flag = TALKING);

const std::string& getMessage() const;

TASKFLAG getFlag() const;

void setIP(in_addr _ip);

int getS_fd() const;

void setS_fd(int _fd);

std::string getData() const;

private:

std::string m_message;

TASKFLAG m_flag;

in_addr ip;

int s_fd;

};

#endif // TASK_H

task.cpp

C++

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

25

26

27

28

29

30

31

32

33

34

35

36

37

38

39

40

41

42

43

44

45

46

47

48

49

50

51

52

53

54

/********************************************************************

* author 周翔

* e-mail [email protected]

* blog http://blog.csdn.net/zhx6044

**********************************************************************/

#include "task.h"

Task::Task(const std::string &message, TASKFLAG flag):

m_message(message),

m_flag(flag)

{

}

const std::string& Task::getMessage() const

{

return m_message;

}

Task::TASKFLAG Task::getFlag() const

{

return m_flag;

}

void Task::setIP(in_addr _ip)

{

ip = _ip;

}

int Task::getS_fd() const

{

return s_fd;

}

void Task::setS_fd(int _fd)

{

s_fd = _fd;

}

std::string Task::getData() const

{

std::string re;

if (m_flag == CONNECT) {

re = ::inet_ntoa(ip) + std::string("----->") + "CONNECT!    " + m_message;

} else {

if (m_flag == DISCONNECT) {

re = ::inet_ntoa(ip) + std::string("----->") + "DISCONNECT   " + m_message;;

} else {

re = ::inet_ntoa(ip) + std::string("----->Talk:") + m_message;

}

}

return re;

}

epoll_server.h

C++

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

25

26

27

28

29

30

31

32

33

34

35

36

37

38

39

40

41

42

43

44

45

46

47

48

#ifndef EPOLL_SERVER_H

#define EPOLL_SERVER_H

#include <map>

#include <list>

#include "zepoll.h"

#include "socketheads.h"

#include "task.h"

typedef std::pair<int, in_addr> FDtoIP;

/**

* @brief The Epoll_server class 服务器

*/

class Epoll_server

{

public:

Epoll_server(int port);

~Epoll_server();

int bind();

int listen();

void poweroff();

bool states() const;

private:

enum  {BLOCKLOG = 5};

bool isValid() const;

int acceptSocketEpoll();

int readSocketEpoll(const epoll_event &ev);

int writeSocketEpoll(const epoll_event &ev);

void doTask(const Task &t);

int _port;

int server_socket_fd;

Epoll *_epoll;

sockaddr_in server_addr;

sockaddr_in client_addr;

epoll_event m_event;

bool on;

static int setNonblocking(int socket_fd);

std::list<FDtoIP> fd_IP;

};

#endif //EPOLL_SERVER_H

epoll_server.cpp

C++

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

25

26

27

28

29

30

31

32

33

34

35

36

37

38

39

40

41

42

43

44

45

46

47

48

49

50

51

52

53

54

55

56

57

58

59

60

61

62

63

64

65

66

67

68

69

70

71

72

73

74

75

76

77

78

79

80

81

82

83

84

85

86

87

88

89

90

91

92

93

94

95

96

97

98

99

100

101

102

103

104

105

106

107

108

109

110

111

112

113

114

115

116

117

118

119

120

121

122

123

124

125

126

127

128

129

130

131

132

133

134

135

136

137

138

139

140

141

142

143

144

145

146

147

148

149

150

151

152

153

154

155

156

157

158

159

160

161

162

163

164

165

166

167

168

169

170

171

172

173

174

175

176

177

178

179

180

181

182

183

184

185

186

187

188

189

190

191

192

193

194

195

196

197

198

199

200

201

202

203

204

205

206

207

208

209

210

211

212

213

214

215

216

217

218

219

220

221

222

223

224

225

226

227

228

229

230

231

232

233

234

235

236

237

238

239

240

241

242

243

244

245

246

247

248

249

250

251

252

253

254

255

256

257

258

259

260

261

262

263

264

265

266

267

268

269

270

271

272

273

274

275

276

277

278

279

280

281

282

283

284

285

#include "epoll_server.h"

#include <iostream>

//static char welcom[] = "welcom to my epoll_server";

//static char sorry[] = "Sorry! This is a simple demo,so not any function!";

//static char buf[BUFSIZ];

Epoll_server::Epoll_server(int port):_port(port),

server_socket_fd(-1),

_epoll(0),

on(true)

{

}

Epoll_server::~Epoll_server()

{

if (isValid()) {

::close(server_socket_fd);

}

delete _epoll;

}

inline

bool Epoll_server::isValid() const

{

return server_socket_fd > 0;

}

inline

void Epoll_server::poweroff()

{

on = false;

}

inline

bool Epoll_server::states() const

{

return on;

}

int Epoll_server::setNonblocking(int socket_fd)

{

int opts;

opts = fcntl(socket_fd, F_GETFL);

if (opts < 0) {

return -1;

} else

{

opts = opts | O_NONBLOCK;

if (fcntl(socket_fd, F_SETFL, opts) < 0) {

return -1;

}

}

return 0;

}

void Epoll_server::doTask(const Task &t)

{

std::list<FDtoIP>::iterator ite = fd_IP.begin();

std::list<FDtoIP>::iterator ite1 = fd_IP.end();

for (;ite != fd_IP.end();++ite) {

if ((*ite).first != t.getS_fd()) {

memset(&m_event, ‘\0‘, sizeof(m_event));

m_event.events = EPOLLOUT | EPOLLET;

Task *c = new Task(t);

c->setS_fd((*ite).first);

m_event.data.ptr = static_cast<void*>(c);

_epoll->mod((*ite).first, &m_event);

} else {

ite1 = ite;

}

}

if (t.getFlag() == Task::DISCONNECT) {

if (ite1 != fd_IP.end()) {

fd_IP.erase(ite1);

}

}

}

/**

* @brief Epoll_server::acceptSocketEpoll 有用户接入

* @return

*/

int Epoll_server::acceptSocketEpoll()

{

socklen_t len = sizeof(struct sockaddr_in);

int connect_fd;

while ((connect_fd = ::accept(server_socket_fd,

(struct sockaddr*)(&client_addr), &len)) > 0) {

if (setNonblocking(connect_fd) < 0) {

::close(connect_fd);

continue;

}

m_event.data.fd = connect_fd;

m_event.events = EPOLLIN | EPOLLET;

if (_epoll->add(connect_fd, &m_event) < 0) {

::close(connect_fd);

continue;

} else {

fd_IP.push_back(FDtoIP(connect_fd, client_addr.sin_addr));

Task t("come in", Task::CONNECT);

t.setIP(client_addr.sin_addr);

t.setS_fd(connect_fd);

doTask(t);

}

}

if (connect_fd == -1 && errno != EAGAIN && errno != ECONNABORTED

&& errno != EPROTO && errno !=EINTR) {

return -1;

}

return 0;

}

int Epoll_server::readSocketEpoll(const epoll_event &ev)

{

int n = 0;

int nread = 0;

char buf[BUFSIZ]={‘\0‘};

while ((nread = ::read(ev.data.fd, buf + n, BUFSIZ-1)) > 0) {

n += nread;

}

if (nread == -1 && errno != EAGAIN) {

return -1;

}

std::list<FDtoIP>::iterator ite = fd_IP.begin();

for (;ite != fd_IP.end();++ite) {

if ((*ite).first == ev.data.fd) {

break;

}

}

if (nread == 0) {

strcpy(buf, " disconet  left ");

Task t(buf,Task::DISCONNECT);

t.setIP(client_addr.sin_addr);

t.setS_fd((*ite).first);

doTask(t);

} else {

Task t(buf,Task::TALKING);

t.setIP(client_addr.sin_addr);

t.setS_fd((*ite).first);

doTask(t);

}

//    Task *t = new Task(buf,Task::DISCONNECT);

//    t->setIP((*ite).second);

//    t->setS_fd((*ite).first);

// m_event.data.fd = ev.data.fd;

// m_event.events = ev.events;

return 0;//_epoll->mod(m_event.data.fd, &m_event);

}

int Epoll_server::writeSocketEpoll(const epoll_event &ev)

{

Task *t = static_cast<Task*>(ev.data.ptr);

const char* buf = t->getData().data();

int nwrite = 0, data_size = strlen(buf);

int fd = t->getS_fd();

int n = data_size;

delete t;

while (n > 0) {

nwrite = ::write(fd, buf + data_size - n, n);

if (nwrite < 0) {

if (nwrite == -1 && errno != EAGAIN) {

return -1;

}

break;

}

n -= nwrite;

}

memset(&m_event, ‘\0‘, sizeof(m_event));

// m_event.events &= ~EPOLLOUT;

m_event.events = EPOLLIN | EPOLLET;

m_event.data.fd = fd;

if (_epoll->mod(fd, &m_event) < 0) {

::close(m_event.data.fd);

return -1;

}

return 0;

}

/**

* @brief Epoll_server::bind

* @return

*/

int Epoll_server::bind()

{

server_socket_fd = socket(AF_INET, SOCK_STREAM, 0);

if (server_socket_fd < 0) {

return -1;

}

setNonblocking(server_socket_fd);

_epoll = new Epoll();

if (_epoll->create() < 0) {

return -1;

}

memset(&m_event, ‘\0‘, sizeof(m_event));

m_event.data.fd = server_socket_fd;

m_event.events = EPOLLIN | EPOLLET;

_epoll->add(server_socket_fd, &m_event);

memset(&server_addr, 0 ,sizeof(server_addr));

server_addr.sin_family = AF_INET;

server_addr.sin_addr.s_addr = htonl(INADDR_ANY);

server_addr.sin_port = htons(_port);

return ::bind(server_socket_fd, (struct sockaddr*)(&server_addr), sizeof(struct sockaddr));

}

int Epoll_server::listen()

{

if (isValid()) {

if (::listen(server_socket_fd, BLOCKLOG) < 0) {

return -1;

} else {

int num;

while (on) {

num = _epoll->wait();

for (int i = 0;i < num;++i) {

/**

* 接受连接的连接,把她加入到epoll中

*/

if ((*_epoll)[i].data.fd == server_socket_fd) {

if (acceptSocketEpoll() < 0) {

break;

}

continue;

}

/**

* EPOLLIN event

*/

if ((*_epoll)[i].events & EPOLLIN) {

if (readSocketEpoll((*_epoll)[i]) < 0) {

break;

}

continue;

}

/**

* EPOLLOUT event

*/

if ((*_epoll)[i].events & EPOLLOUT) {

if (writeSocketEpoll((*_epoll)[i]) < 0) {

break;

}

}

}

}

}

}

return -1;

}

main.cpp

C++

1

2

3

4

5

6

7

8

9

10

11

12

#include "epoll_server.h"

#include <iostream>

int main(int /*argc*/, char const **/*argv[]*/)

{

std::cout << "server" << std::endl;

Epoll_server s(18090);

if (s.bind() < 0) {

return -1;

}

return s.listen();

}

客户端用qt简单的写了一个

客户端服务端代码:epoll_chatroom.zip

http://love.junzimu.com/archives/2660

时间: 2024-08-03 01:35:03

基于epoll的聊天室程序的相关文章

Java网络编程 - 基于UDP协议 实现简单的聊天室程序

最近比较闲,一直在抽空回顾一些Java方面的技术应用. 今天没什么事做,基于UDP协议,写了一个非常简单的聊天室程序. 现在的工作,很少用到socket,也算是对Java网络编程方面的一个简单回忆. 先看一下效果: 实现的效果可以说是非常非常简单,但还是可以简单的看到一个实现原理. "聊天室001"的用户,小红和小绿相互聊了两句,"聊天室002"的小黑无人理会,在一旁寂寞着. 看一下代码实现: 1.首先是消息服务器的实现,功能很简单: 将客户端的信息(进入了哪一个聊

15.基于UDP协议的聊天室程序

使用UDP协议完成一个聊天室程序的小项目,大部分代码都有注释,一看就能看到的. 实现的功能:               (1)查看/显示已经登陆的用户信息               (2)向已登陆的用户发送消息               (3)输出错误消息,给予提示               (4)退出 共有三个文件: chat_public.h #ifndef _CHAT_PUB_H_ #define _CHAT_PUB_H_ //chat_public.h #include <lis

基于java网络聊天室---前言

很久之前做的一个东西,现在拿出来整理一下放在自己的博客中! 一. 设计目的 随着人互联网的发展,人和人之间的沟通方式也越来越便捷和多样化,在线聊天工具已经成为人们生活中够通不可缺少的部分,在学习完 java网络编程课程,如果能开发一款属于自己的聊天工具,和好友进行私密对话,则是一件令人兴奋的事.同时,安全可靠的TCP这两种 通信协议,是非常重要的内容,值得研究. 二. 设计内容 本聊天室程序基于C/S模式,聊天室共分为服务器端和客户端两部分,服务器端程序主要负责侦听客户端发来的消息,客户端需登陆

ASP.NET 使用application和session对象写的简单聊天室程序

ASP.Net中有两个重要的对象,一个是application对象,一个是session对象. Application:记录应用程序参数的对象,该对象用于共享应用程序级信息. Session:记录浏览器端的变量对象,用来存储跨网页程序程序的变量或者对象. 说实话,写了快一年的asp.net,application对象还真没怎么用过.看了看书,根据这两个对象的特性写了一个简单的聊天室程序.真的是非常的简陋. 我的思路是,有两个页面Default页和ChatRoom页,页面布局如图: Default

I/O复用——聊天室程序

本文主要是为熟悉Linux下网络编程,而实现一个简单的网络聊天室程序.  以Poll实现I/O复用技术来同时处理网络连接和用户输入,实现多个用户同时在线群聊. 其中客户端实现两个功能:一:从标准输入读入用户数据,并将用户数据发送到服务器:二:接收服务器发送的数据,并在标准输出打印. 服务端功能为:接收客户端数据,并将客户数据发送到登录到该服务端的所有客户端(除数据发送的客户端外). 服务端程序 chat_server: #define _GNU_SOURCE 1 #include<sys/typ

java socket控制台版本聊天室程序源码下载

原文:java socket控制台版本聊天室程序源码下载 代码下载地址:http://www.zuidaima.com/share/1550463257578496.htm java socket控制台版本聊天室程序源码下载,学习的时候写的,适合学习java基础 java网络编程基础用 标签: java socket 控制台 聊天室 源码话题: 网络编程 java socket控制台版本聊天室程序源码下载,布布扣,bubuko.com

Erlang 聊天室程序

Erlang 聊天室程序( 一) Erlang 聊天室程序(二) 客户端的退出 Erlang 聊天室程序(三) 数据交换格式---json的decode Erlang 聊天室程序(四) 数据交换格式---json的encode Erlang 聊天室程序(五) 设置客户端信息 Erlang 聊天室程序(七) 获取在线用户 Erlang 聊天室程序(八) 主题房间---supervisor 的使用 Erlang 聊天室程序(九) 主题房间2 ---房间信息管理 Erlang 聊天室程序(十) 主题房

基于java的聊天室/群发控制台程序

java聊天室 1.概述 基于tcp协议的,由一个服务器和多个客户端组成,一个客户端发送消息,其他所有客户端都能接收到消息.在服务器端设置一个线程监听客户端发来的请求(消息),并且向所有的客户端响应.每个客户端也有一个线程用来接收服务器端的请求. 2.代码如下 public class Client { public static void main(String[] args) throws IOException { //创建套接字 Socket socket = new Socket("l

构建有多个房间的聊天室程序

1. 程序概览 用户可以在一个简单的表单中输入消息,相互聊天.消息输入后会发送给同一个聊天室内的其他所有用户. 进入聊天室后,程序会自动给用户分配一个昵称,但他们可以用聊天命令修改自己的昵称,如图2-2所示.聊天命令以斜杠(/)开头. 同样,用户也可以输入命令创建新的聊天室(或加入已有的聊天室) ,如图2-3所示.在加入或创建聊天室时,新聊天室的名称会出现在聊天程序顶端的水平条上,也会出现在聊天消息区域右侧的可用房间列表中. 在用户换到新房间后,系统会确认这一变化,如图2-4所示. 2. 程序需