#include "server.h"
vector<bool> server::sock_arr(10000,false);
unordered_map<string,int> server::name_sock_map;//名字和套接字描述符
unordered_map<string,string> server::from_to_map;//记录用户xx要向用户yy发送信息
unordered_map<int,set<int> > server::group_map;//记录群号和套接字描述符集合
pthread_mutex_t server::name_sock_mutx;//互斥锁,锁住需要修改name_sock_map的临界区
pthread_mutex_t server::group_mutx;//互斥锁,锁住需要修改group_map的临界区
pthread_mutex_t server::from_mutex;//自旋锁,锁住修改from_to_map的临界区
server::server(int port,string ip):server_port(port),server_ip(ip){
pthread_mutex_init(&name_sock_mutx, NULL); //创建互斥锁
pthread_mutex_init(&group_mutx, NULL); //创建互斥锁
pthread_mutex_init(&from_mutex, NULL); //创建互斥锁
}
server::~server(){
for(int i=0;i<sock_arr.size();i++){
if(sock_arr[i])
close(i);
}
close(server_sockfd);
}
//将参数的文件描述符设为非阻塞
void server::setnonblocking(int sock)
{
int opts;
opts=fcntl(sock,F_GETFL);
if(opts<0)
{
perror("fcntl(sock,GETFL)");
exit(1);
}
opts = opts|O_NONBLOCK;
if(fcntl(sock,F_SETFL,opts)<0)
{
perror("fcntl(sock,SETFL,opts)");
exit(1);
}
}
void server::run(){
//listen的backlog大小
int LISTENQ=200;
int i, maxi, listenfd, connfd, sockfd,epfd,nfds;
ssize_t n;
//char line[MAXLINE];
socklen_t clilen;
//声明epoll_event结构体的变量,ev用于注册事件,数组用于回传要处理的事件
struct epoll_event ev,events[10000];
//生成用于处理accept的epoll专用的文件描述符
epfd=epoll_create(10000);
struct sockaddr_in clientaddr;
struct sockaddr_in serveraddr;
listenfd = socket(PF_INET, SOCK_STREAM, 0);
//把socket设置为非阻塞方式
setnonblocking(listenfd);
//设置与要处理的事件相关的文件描述符
ev.data.fd=listenfd;
//设置要处理的事件类型
ev.events=EPOLLIN|EPOLLET;
//注册epoll事件
epoll_ctl(epfd,EPOLL_CTL_ADD,listenfd,&ev);
//设置serveraddr
bzero(&serveraddr, sizeof(serveraddr));
serveraddr.sin_family = AF_INET;
serveraddr.sin_addr.s_addr = inet_addr("127.0.0.1");//此处设为服务器的ip
serveraddr.sin_port=htons(8023);
bind(listenfd,(sockaddr *)&serveraddr, sizeof(serveraddr));
listen(listenfd, LISTENQ);
clilen=sizeof(clientaddr);
maxi = 0;
/* 定义一个10线程的线程池 */
boost::asio::thread_pool tp(10);
while(1){
cout<<"--------------------------"<<endl;
cout<<"epoll_wait阻塞中"<<endl;
//等待epoll事件的发生
nfds=epoll_wait(epfd,events,10000,-1);//最后一个参数是timeout,0:立即返回,-1:一直阻塞直到有事件,x:等待x毫秒
cout<<"epoll_wait返回,有事件发生"<<endl;
//处理所发生的所有事件
for(i=0;i<nfds;++i)
{
//有新客户端连接服务器
if(events[i].data.fd==listenfd)
{
connfd = accept(listenfd,(sockaddr *)&clientaddr, &clilen);
if(connfd<0){
perror("connfd<0");
exit(1);
}
else{
cout<<"用户"<<inet_ntoa(clientaddr.sin_addr)<<"正在连接\n";
}
//设置用于读操作的文件描述符
ev.data.fd=connfd;
//设置用于注册的读操作事件,采用ET边缘触发,为防止多个线程处理同一socket而使用EPOLLONESHOT
ev.events=EPOLLIN|EPOLLET|EPOLLONESHOT;
//边缘触发要将套接字设为非阻塞
setnonblocking(connfd);
//注册ev
epoll_ctl(epfd,EPOLL_CTL_ADD,connfd,&ev);
}
//接收到读事件
else if(events[i].events&EPOLLIN)
{
sockfd = events[i].data.fd;
events[i].data.fd=-1;
cout<<"接收到读事件"<<endl;
string recv_str;
boost::asio::post(boost::bind(RecvMsg,epfd,sockfd)); //加入任务队列,处理事件
}
}
}
close(listenfd);
}
//注意,前面不用加static!
void server::RecvMsg(int epollfd,int conn){
tuple<bool,string,string,int,int> info;//元组类型,四个成员分别为if_login、login_name、target_name、target_conn
/*
bool if_login;//记录当前服务对象是否成功登录
string login_name;//记录当前服务对象的名字
string target_name;//记录目标对象的名字
int target_conn;//目标对象的套接字描述符
int group_num;//记录所处群号
*/
get<0>(info)=false;
get<3>(info)=-1;
string recv_str;
while(1){
char buf[10];
memset(buf, 0, sizeof(buf));
int ret = recv(conn, buf, sizeof(buf), 0);
if(ret < 0){
cout<<"recv返回值小于0"<<endl;
//对于非阻塞IO,下面的事件成立标识数据已经全部读取完毕
if((errno == EAGAIN) || (errno == EWOULDBLOCK)){
printf("数据读取完毕\n");
cout<<"接收到的完整内容为:"<<recv_str<<endl;
cout<<"开始处理事件"<<endl;
break;
}
cout<<"errno:"<<errno<<endl;
return;
}
else if(ret == 0){
cout<<"recv返回值为0"<<endl;
return;
}
else{
printf("接收到内容如下: %s\n",buf);
string tmp(buf);
recv_str+=tmp;
}
}
string str=recv_str;
HandleRequest(epollfd,conn,str,info);
}
void server::HandleRequest(int epollfd,int conn,string str,tuple<bool,string,string,int,int> &info){
char buffer[1000];
string name,pass;
//把参数提出来,方便操作
bool if_login=get<0>(info);//记录当前服务对象是否成功登录
string login_name=get<1>(info);//记录当前服务对象的名字
string target_name=get<2>(info);//记录目标对象的名字
int target_conn=get<3>(info);//目标对象的套接字描述符
int group_num=get<4>(info);//记录所处群号
//连接MYSQL数据库
MYSQL *con=mysql_init(NULL);
mysql_real_connect(con,"127.0.0.1","root","","ChatProject",0,NULL,CLIENT_MULTI_STATEMENTS);
//连接redis数据库
redisContext *redis_target = redisConnect("127.0.0.1",6379);
if(redis_target->err){
redisFree(redis_target);
cout<<"连接redis失败"<<endl;
}
//先接收cookie看看redis是否保存该用户的登录状态
if(str.find("cookie:")!=str.npos){
cout<<"cookie方法\n";
string cookie=str.substr(7);
// 查询该cookie是否存在:hget cookie name
string redis_str="hget "+cookie+" name";
redisReply *r = (redisReply*)redisCommand(redis_target,redis_str.c_str());
string send_res;
//存在
if(r->str){
cout<<"查询redis结果:"<<r->str<<endl;
send_res=r->str;
}
//不存在
else
send_res="NULL";
send(conn,send_res.c_str(),send_res.length()+1,0);
}
//注册
else if(str.find("name:")!=str.npos){
cout<<"注册方法\n";
int p1=str.find("name:"),p2=str.find("pass:");
name=str.substr(p1+5,p2-5);
pass=str.substr(p2+5,str.length()-p2-4);
st
没有合适的资源?快使用搜索试试~ 我知道了~
资源详情
资源评论
资源推荐
收起资源包目录
聊天室代码.zip (8个子文件)
code12
server.h 1KB
client.h 383B
client.cpp 7KB
makefile 527B
test_client.cpp 84B
global.h 574B
server.cpp 15KB
test_server.cpp 85B
共 8 条
- 1
三Ⅶ
- 粉丝: 3
- 资源: 1
上传资源 快速赚钱
- 我的内容管理 展开
- 我的资源 快来上传第一个资源
- 我的收益 登录查看自己的收益
- 我的积分 登录查看自己的积分
- 我的C币 登录后查看C币余额
- 我的收藏
- 我的下载
- 下载帮助
安全验证
文档复制为VIP权益,开通VIP直接复制
信息提交成功
评论0