一.服务器代码
#include "hv/hloop.h"
#include "hv/hsocket.h"
#include "hv/hbase.h"
#include "list.h"
struct chatroom_s {
hloop_t* loop;//事件循环结构体指针
hio_t* listenio;//监听io结构体
int roomid;//房间号
struct list_head conns;//链表存储房间中的连接
};
struct chatroom_s chatroom;
struct connection_s {
hio_t* connio;// 连接io结构体指针
char addr[SOCKADDR_STRLEN];// 套接字地址
struct list_node node;// 链表结点
};
void boardcast_talk(struct chatroom_s *room, char *msg, int msglen, hio_t* talk_io)
{
struct list_node* node;
struct connection_s* cur;
list_for_each (node, &room->conns) {
cur = list_entry(node, struct connection_s, node);
if(cur->connio != talk_io)
hio_write(cur->connio, msg, msglen);
}
}
void boardcast(struct chatroom_s *room, char *msg, int msglen)
{
struct list_node* node;
struct connection_s* cur;
list_for_each (node, &room->conns) {
cur = list_entry(node, struct connection_s, node);
hio_write(cur->connio, msg, msglen);
}
}
void on_recv(hio_t *io, void *buf, int readbytes)
{
char localaddrstr[SOCKADDR_STRLEN] = {0};
char peeraddrstr[SOCKADDR_STRLEN] = {0};
printf("[%s] <=> [%s]\n",
SOCKADDR_STR(hio_localaddr(io), localaddrstr),
SOCKADDR_STR(hio_peeraddr(io), peeraddrstr));
printf("< %.*s", readbytes, (char*)buf);
//广播成员说的话
char msg[256] = {0};
int msglen = 0;
struct connection_s* conn = (struct connection_s*)hevent_userdata(io);
msglen = snprintf(msg, sizeof(msg), "成员[%s]:%.*s", conn->addr, readbytes, (char*)buf);
boardcast_talk(&chatroom, msg, msglen, conn->connio);
}
void leave(struct chatroom_s* room, struct connection_s* conn) {
// 从链表里删除
list_del(&conn->node);
// 广播有成员离开聊天室
char msg[256] = {0};
int msglen = snprintf(msg, sizeof(msg), "成员[%s]离开房间[%d]\r\n", conn->addr, room->roomid);
boardcast(room, msg, msglen);
}
static void on_close(hio_t* io) {
printf("关闭描述符%d,错误=%d\n", hio_fd(io), hio_error(io));
struct connection_s* conn = (struct connection_s*)hevent_userdata(io);
if (conn) {
hevent_set_userdata(io, NULL);
// 断连离开聊天室
leave(&chatroom, conn);
HV_FREE(conn);
}
}
void on_accept(hio_t *io)
{
//获取服务器和客户端IP地址
char localaddrstr[SOCKADDR_STRLEN] = {0};
char peeraddrstr[SOCKADDR_STRLEN] = {0};
printf("建立连接(连接描述符:%d):%s=====>%s\r\n\r\n",hio_fd(io) , SOCKADDR_STR(hio_localaddr(io), localaddrstr), SOCKADDR_STR(hio_peeraddr(io), peeraddrstr));
hio_setcb_close(io, on_close);
hio_setcb_read(io, on_recv);
hio_read(io);
struct connection_s *conn = NULL;
HV_ALLOC_SIZEOF(conn);
conn->connio = io;
strcpy(conn->addr, peeraddrstr);
hevent_set_userdata(io, conn);
list_add(&conn->node, &chatroom.conns);
//向新来的成员发送当前聊天室成员列表
char msg[256] = {0};
int msglen = 0;
struct list_node* node;
struct connection_s* cur;
msglen = snprintf(msg, sizeof(msg), "房间[%06d] 成员列表:\r\n", chatroom.roomid);
hio_write(io, msg, msglen);
list_for_each (node, &chatroom.conns) {
cur = list_entry(node, struct connection_s, node);
msglen = snprintf(msg, sizeof(msg), "%s\r\n", cur->addr);
hio_write(io, msg, msglen);
}
hio_write(io, "\r\n", 2);
//向全体成员广播新成员加入
msglen = snprintf(msg, sizeof(msg), "新成员加入房间[%06d]:%s\r\n\r\n",chatroom.roomid, conn->addr);
boardcast(&chatroom, msg, msglen);
}
int main(int argc, char **argv)
{
if(argc <2)
{
printf("Please input the port");
return -1;
}
int port = atoi(argv[1]);
//创建按事件循环
hloop_t* loop = hloop_new(0);
//创建TCP服务器,设置accept回调函数
hio_t* listenio = hloop_create_tcp_server(loop, "0.0.0.0", port, on_accept);//监听所有IP地址,端口号为8080
chatroom.loop = loop;
chatroom.listenio = listenio;
chatroom.roomid = 1;
list_init(&chatroom.conns);
//循环事件体
hloop_run(loop);
//释放事件体
hloop_free(&loop);
return 0;
}
二.客户端代码
#include "hv/hloop.h"
#include "hv/hsocket.h"
#include "hv/hbase.h"
#include "hv/htime.h"
#include "list.h"
#include <string.h>
typedef struct client_s{
hio_t *io;
} client_t;
client_t client;
void on_recv(hio_t *io, void *buf, int readbytes)
{
printf("%.*s\n", readbytes, (char*)buf);
}
static void on_close(hio_t* io) {
}
void on_connect(hio_t *io)
{
hio_setcb_close(io, on_close);
hio_setcb_read(io, on_recv);
hio_read(io);
client.io = io;
}
void on_cin(hio_t *io, void *str, int readbytes)
{
// 发送输入的字符串
hio_write(client.io, str, readbytes);
fflush(stdin);
fflush(stdout);
}
int main(int argc, char **argv)
{
if(argc <2)
{
printf("Please input the port");
return -1;
}
int port = atoi(argv[1]);
//创建按事件循环
hloop_t* loop = hloop_new(0);
//创建读取终端输入的描述符输入事件
hio_t* io = hio_get(loop, 0);
hio_read(io);
hio_setcb_read(io, on_cin);
//创建TCP服务器,设置accept回调函数
hio_t* listenio = hloop_create_tcp_client(loop, "127.0.0.1", port, on_connect);//监听所有IP地址,端口号为8080
//循环事件体
hloop_run(loop);
//释放事件体
hloop_free(&loop);
return 0;
}
三.运行结果截图