整体思路与框架
1.由于经历了一次重构,让我重新认识到服务器整体框架搭建的困难,在一番折腾过后了解到epoll的一个常规模型
epfd = epoll_create(MAXEVENTS); //生成epoll文件描述符
ev.data.fd = sockfd;
ev.events = EPOLLIN | EPOLLET | EPOLLRDHUP | EPOLLERR; //设置事件属性
epoll_ctl(epfd,EPOLL_CTL_ADD,sockfd,&ev); //因为开始create也需要一个sockfd存到红黑树中
connects++;
for(;;){
npfd = epoll_wait(epfd,events,MAXEVENTS,-1); //等待响应
for(int i = 0;i < npfd;i++){
connects++;
if(events[i].data.fd == sockfd){
if(connects > MAXEVENTS){
my_err("达到最大连接数...",__LINE__);
continue;
}
connfd = accept(events[i].data.fd,(struct sockaddr*)&cliaddr,&clen);
printf("客户端[IP:%s],[port: %d]已链接...\n",
inet_ntop(AF_INET,&cliaddr.sin_addr.s_addr,ip,sizeof(ip)),
ntohs(cliaddr.sin_port));
if(connfd <= 0){
my_err("accpet",__LINE__);
continue;
}
ev.data.fd = connfd;
ev.events = EPOLLIN | EPOLLET | EPOLLRDHUP | EPOLLERR;
epoll_ctl(epfd,EPOLL_CTL_ADD,connfd,&ev); //新增套接字
}
/* 用户非正常挂断或程序出错 */
else if((events[i].events & EPOLLIN) && (events[i].events & EPOLLRDHUP) || (events[i].events & EPOLLIN) && (events[i].events & EPOLLERR)){
epoll_ctl(epfd,EPOLL_CTL_DEL,events[i].data.fd,0); //删去套接字
close(events[i].data.fd);
connects--;
}
/* 用户正常发来消息请求 */
else if(events[i].events & EPOLLIN){
//...工作
}
}
2.对于客户端我开两个独立的线程来分别执行发数据和接收数据,这样一般不会阻塞,也对线程的知识进行了复习
int main(){
int connfd;
pthread_t tid1, tid2;
struct sockaddr_in servaddr;
if((connfd = socket(AF_INET, SOCK_STREAM,0))<0){
//初始化socket套接字
my_err("socket",__LINE__);
}
bzero(&servaddr,sizeof(struct sockaddr_in));
servaddr.sin_family = AF_INET; //ipv4协议
servaddr.sin_port = htons(PORT); //填入端口号
inet_pton(AF_INET,"127.0.0.1",(void*)&servaddr.sin_addr.s_addr); //转为网络地址格式
printf("正在与服务器建立连接...\n");
if((connect(connfd,(struct sockaddr*)&servaddr,sizeof(servaddr))) < 0){
//与服务器链接
my_err("connect",__LINE__);
}else
printf("与服务器链接成功!!!\n");
pthread_create(&ptd1,NULL,send_mission,(void*)&connfd); //发送消息的线程
pthread_create(&ptd2,NULL,recv_mission,(void*)&connfd); //接收消息的线程
return 0;
数据库的准备
1.个人信息表:
id:帐号; name:昵称; passwd:密码; state:在线状态 fd:对方的文件描述符
2.好友信息表:
your_id:你的帐号; friend_id: 好友的帐号; relation: 好友关系;
3.好友聊天记录表:
your_id:你的id; recv_id: 收消息的人的id; massages: 发的消息; y_look: 自己是否可见; recv_look: 对方是否可见
4.群信息表:
group_id:群id; group_name:群名; group_mem_id:群成员id; group_mem_nikename:群成员昵称; group_state: 群成员的阶级
演示功能
- 加好友:
当输入对方的id后就可以发送好友请求了
对面就会收到
- 查看好友请求:
会有提示是谁发的好友请求
- 私聊:
客户端选择私聊后输入对方的id就可以私聊了
如果非法输入或者帐号不存在则会有如下提示:
- 查看消息记录:
- 群聊:
当其他人没打开群聊框时,会提示受到消息
当打开群聊框就能看到他们发的消息
当查看消息时
- 发文件:
对方接收文件
- 退出:
客户端退出 :
服务器显示如下: