当前位置: 首页 > news >正文

Linux C 基于tcp和epoll在线聊天室

基于tcp和epoll在线聊天室

  • 说明
  • 服务端代码

说明

  服务端:实现了验证用户是否已经存在(支持最大64用户连接)支持广播用户进入退出聊天室以及用户聊天内容。
  这里只提供里服务端代码,如果想要看客户端代码点击这里。

服务端代码

#include <stdio.h>
#include <stdlib.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <sys/wait.h>
#include <string.h>
#include <fcntl.h>
#include <unistd.h>
#include <errno.h>
#include<sys/types.h>
#include<sys/socket.h>
#include <arpa/inet.h>
#include <time.h>
#include <sys/epoll.h>typedef struct sockaddr  SA;
typedef struct sockaddr_in  SIN;
#define MAXBACKLOG   100int Socket(int domain,int type,int protocol);
int Bind(int sockfd,struct sockaddr * my_addr,int addrlen);
int Listen(int s,int backlog);
int Accept(int s,struct sockaddr * addr,int * addrlen);
int is_exist(char * username);
void broadcast(char *r,char *n);char Userlist[64][20] = {0};
int Userfdlist[64] = {0};//./app 192.168.5.166  8888
int main(int argc,char *argv[])
{	int opt = 1;//建立监听套接字int socketfd = Socket(AF_INET,SOCK_STREAM,0);//需要进行重用地址及其端口号setsockopt(socketfd,SOL_SOCKET,SO_REUSEADDR,&opt,sizeof(opt));//绑定信息编写服务器信息SIN   serverinfo;serverinfo.sin_family =AF_INET;serverinfo.sin_port   =htons(atoi(argv[2])); serverinfo.sin_addr.s_addr=  inet_addr(argv[1]);int addrlen = sizeof(SIN);Bind(socketfd,(SA*)&serverinfo,addrlen);//监听Listen(socketfd,MAXBACKLOG);//epoll创建根节点int epollfd = epoll_create(1024);//添加socketfd文件描述符至内核 红黑树struct epoll_event event;event.events = EPOLLIN;			//事件成员event.data.fd = socketfd;		//数据epoll_ctl(epollfd,EPOLL_CTL_ADD,socketfd, &event);//读写while(1){struct epoll_event events[10];int count = epoll_wait(epollfd,events,10,-1);for(int i = 0; i< count;i++){if(events[i].events == EPOLLIN){if(events[i].data.fd == socketfd){//wait client connectSIN clientinfo;struct epoll_event event;int  clientaddrlen =sizeof(SA);int newfd = Accept(socketfd,(SA*)&clientinfo,&clientaddrlen);printf("客户端地址:%s 端口号:%d\n",inet_ntoa(clientinfo.sin_addr),ntohs(clientinfo.sin_port));//read usernamechar namebuff[20];read(newfd,namebuff,sizeof(namebuff));if(is_exist(namebuff)){write(newfd,"已存在",sizeof("已存在"));close(newfd);}else{//put newfd into Red-Black Treeevent.events = EPOLLIN;			//事件成员event.data.fd = newfd;			//数据epoll_ctl(epollfd,EPOLL_CTL_ADD,newfd, &event);write(newfd,"登录成功",sizeof("登录成功"));	//save userfd & usernamefor(int j=0;j<64;j++)if(strlen(Userlist[j])==0){Userfdlist[j]=event.data.fd;strcpy(Userlist[j],namebuff);break;}	char r[50];sprintf(r,"%s %s",namebuff,"进入聊天室");printf("%s\n",r);broadcast(r,namebuff);}}else{//readchar readbuff[512] = {0};int len = read(events[i].data.fd,readbuff,sizeof(readbuff));//get name and poschar namebuff[20] = {0};int key = 0;for(int i=0;i<10;i++)if(strstr(readbuff,Userlist[i])){strcpy(namebuff,Userlist[i]);key=i;break;}if(len > 0 && strlen(readbuff)!=0){printf("%s\n",readbuff);broadcast(readbuff,namebuff);if(strstr(readbuff,"退出")){strcpy(Userlist[key],"\0");Userfdlist[key] = 0;epoll_ctl(epollfd,EPOLL_CTL_DEL,events[i].data.fd,NULL);close(events[i].data.fd);}}else if(len <= 0){epoll_ctl(epollfd,EPOLL_CTL_DEL,events[i].data.fd,NULL);close(events[i].data.fd);}}}}}//关闭close(socketfd);return 0;
}
int is_exist(char * username)
{for(int i = 0 ; i < 10; i++)if(strcmp(username,Userlist[i]) == 0)return 1;return 0;
}
void broadcast(char *r,char *n)
{for(int i=0 ; i<64 ;i++)//if it is a user and not himselfif(strcmp(Userlist[i],n)!=0 && strlen(Userlist[i])!=0)write(Userfdlist[i],r,strlen(r));
}
int Socket(int domain,int type,int protocol)
{int socketFd = socket(domain,type,protocol);if(socketFd == -1){perror("socket");exit(1);}return socketFd;
}
int Bind(int sockfd,struct sockaddr * my_addr,int addrlen)
{int val = bind(sockfd,my_addr,addrlen);if(val){perror("bind");exit(1);}return 0;
}
int Listen(int s,int backlog)
{int val = listen(s,backlog);if(val == -1){perror("listen");exit(1);}return val;
}
int Accept(int s,struct sockaddr * addr,int * addrlen)
{int NEWfd = accept(s,addr,addrlen);if(NEWfd == -1){perror("listen");exit(1);}return NEWfd;
}
http://www.lryc.cn/news/242596.html

相关文章:

  • 为什么要隐藏id地址?使用IP代理技术可以实现吗?
  • 前端(HTML + CSS + JS)
  • 12 要素 12 Factor
  • 十大排序之冒泡排序与快速排序(详解)
  • 【SpringBoot篇】阿里云OSS—存储文件的利器
  • Leetcode—58.最后一个单词的长度【简单】
  • Apach Ozone部署
  • 【nlp】3.2 Transformer论文复现:1. 输入部分(文本嵌入层和位置编码器)
  • 自动化部署 / 扩容openGauss —— Ansible for openGauss
  • Go 实现网络代理
  • Redis报错:JedisConnectionException: Could not get a resource from the pool
  • 【广州华锐互动】Web3D云展编辑器能为展览行业带来哪些便利?
  • Vue项目实战之一----实现分类弹框效果
  • Vue解析器
  • Spring Cloud 版本升级遇坑记:OpenFeignClient与Gateway的恩怨情仇
  • 面试:Docker相关问题
  • 移动端浏览器 jquery 获取 pdf blob文件流 预览pdf
  • Redis并发问题解决方案
  • 读取两个文件夹里不同名的文件,处理映射不对应的文件
  • SpringCloud原理-OpenFeign篇(四、请求原理)
  • 什么是工业物联网(IOT)?这样的IOT平台你需要吗?——青创智通
  • MTK Pump Express 快速充电原理分析
  • leetcode刷题记录——1991. 找到数组的中间位置
  • 跨域攻击分析和防御(上)
  • GEE:梯度提升树(Gradient Boosting Tree)分类教程(样本制作、特征添加、训练、精度、参数优化、贡献度、统计面积)
  • ubuntu22.04 arrch64版在线安装redis
  • 篮桥云课-摆玩具
  • 【python】python进阶知识点
  • LeetCode算法题解(动态规划)|LeetCode322. 零钱兑换、LeetCode279. 完全平方数
  • Python Web开发基础知识篇