一步一步创建聊天程序2利用epoll来创建简单的聊天室
如图,这个是看视频时,最后的作业,除了客户端未使用select实现外,其它的要求都有简单实现。
服务端代码如下:
#include <stdio.h>#include
<string.h>#include
<sys/types.h>#include
<sys/socket.h>#include
<errno.h>#include
<sys/epoll.h>#include
<netinet/in.h>#include
<unistd.h>#include
<netinet/tcp.h>#define MAX_LISTEN 10
#define EPOLL_SIZE 100
struct message
{
int target_id;
char buf[100];
};
struct user_password
{
char username[100];
char password[100];
};
//设置保活参数 keepalive_time保活时间,keepalive_intvl保活间隔,keepalive_probes保活探测数。
int set_keepalive(int sockfd,int keepalive_time, int keepalive_intvl, int keepalive_probes)
{
int optval;
socklen_t optlen= sizeof(optval);
optval=1;
if(-1==setsockopt(sockfd,SOL_SOCKET, SO_KEEPALIVE, &optval, optlen))
{
perror("setsockopt failture.
");
return -1;
}
optval=keepalive_probes;
if(-1==setsockopt(sockfd,SOL_TCP,TCP_KEEPCNT, &optval,optlen))
{
perror("setsockopt failture.
");
return -1;
}
optval=keepalive_intvl;
if(-1==setsockopt(sockfd,SOL_TCP,TCP_KEEPINTVL, &optval,optlen))
{
perror("setsockopt failture.
");
return -1;
}
optval=keepalive_time;
if(-1==setsockopt(sockfd,SOL_TCP,TCP_KEEPIDLE, &optval, optlen))
{
perror("setsockopt failture
");
return -1;
}
return0;
}
void set_user_password(struct user_password users[100])
{
int fd=fopen("./password.txt","r");
if(fd==NULL)
{
perror("open password failed
");
return;
}
char buf[100];
int count=0;
int i=0;
while(feof(fd)==0)
{
fscanf(fd,"%s",buf);
if(count%2==0)
{
strcpy(users[i].username,buf);
count++;
}
else
{
strcpy(users[i++].password,buf);
count++;
}
}
fclose(fd);
}
int main(int argc,char * argv[])
{
//读取设定的用户名和密码
struct user_password users[100];
set_user_password(users);
for(int i=0;i<2;i++)
{
printf("user: %s, password: %s
",users[i].username,users[i].password);
}
struct sockaddr_in server_ip,customer_ip;
int err,sd;
sd=socket(AF_INET,SOCK_STREAM,0);
if(sd==-1)
{
perror("socket failed
");
close(sd);
return -1;
}
server_ip.sin_family=AF_INET;
server_ip.sin_port=htons(5678);
server_ip.sin_addr.s_addr=htonl(INADDR_ANY);
memset(server_ip.sin_zero,0,8);
err=bind(sd,(struct sockaddr *)(&server_ip),sizeof(struct sockaddr));
if(err==-1)
{
perror("bind failed
");
close(sd);
return -1;
}
err=listen(sd,MAX_LISTEN);
if(err==-1)
{
perror("listen failed
");
close(sd);
return -1;
}
int epfd=epoll_create(EPOLL_SIZE);
if(epfd<0)
{
perror("epoll create failed
");
return -1;
}
printf("epoll created, epollfd=%d
",epfd);
struct epoll_event events[EPOLL_SIZE];
struct epoll_event event;
event.data.fd=sd;
event.events=EPOLLIN;
err=epoll_ctl(epfd,EPOLL_CTL_ADD,sd,&event);
if(err==-1)
{
perror("epoll add failed
");
return -1;
}
while(1)
{
int epoll_events_count=epoll_wait(epfd,events,EPOLL_SIZE,-1);
if(epoll_events_count<0)
{
perror("epoll wait failed
");
break;
}
printf("epoll_events_count= %d
",epoll_events_count);
for(int i=0;i<epoll_events_count;i++)
{
int sockfd=events[i].data.fd;
if(sockfd==sd)
{
int length=sizeof(struct sockaddr);
int client_fd=accept(sockfd,(struct sockaddr *)(&customer_ip),&length);
//用户名和密码检验
int flag=0;
char buf[100]="please input username and password ";
struct user_password login_user;
send(client_fd,buf,100,0);
recv(client_fd,&login_user,sizeof(struct user_password),0);
memset(buf,0,100);
for(int i=0;i<100;i++)
{
if((strcmp(users[i].username,login_user.username)==0)&&(strcmp(users[i].password,login_user.password)==0))
{
flag=1;
break;
}
}
if(flag)
{
err=set_keepalive(sockfd,120,20,3);
if(err!=0)
{
perror("set keep alive failed.
");
continue;
}
printf("USER %d online
",client_fd);
event.data.fd=client_fd;
event.events=EPOLLIN;
err=epoll_ctl(epfd,EPOLL_CTL_ADD,client_fd,&event);
if(err==-1)
{
perror("epoll add failed
");
return -1;
}
}
else
{
memset(buf,0,100);
strcpy(buf,"login failed
");
send(client_fd,buf,100,0);
}
}
else
{
struct message recv_message;
int bytes=recv(sockfd,&recv_message,sizeof(struct message),0);
if(bytes<0)
{
perror("recv failed
");
return -1;
}
elseif(bytes==0)
{
err=epoll_ctl(epfd,EPOLL_CTL_DEL,sockfd,events);
if(err==-1)
{
perror("epoll del failed
");
return -1;
}
printf("USER %d offline
",sockfd);
close(sockfd);
}
else
{
printf("recv message from cliend %d, buf: %s
",sockfd,recv_message.buf);
if(recv_message.target_id!=-1)//请求向客户端发送信息
{
err=send(recv_message.target_id,recv_message.buf,100,0);
if(err==-1)
{
perror("send failed
");
}
}
elseif(strcmp(recv_message.buf,"quit")==0)//用户输入quit,客户端推出。
{
printf("USER %d offline
",sockfd);
send(sockfd,recv_message.buf,100,0);
close(sockfd);
}
else
{
char cmd[100];
strcat(cmd,recv_message.buf);
strcat(cmd," >> test.txt");
int fd=fopen("./test.txt","w");
if(fd==NULL)
{
perror("clear file failed
");
continue;
}
close(fd);
printf("exec cmd: %s
",cmd);
system(cmd);
memset(cmd,0,100);
//将结果回送客户端
fd=fopen("./test.txt","r");
if(fd==NULL)
{
perror("open file failed
");
continue;
}
char buf[100];
while(feof(fd)==0)
{
int fread_ret=fread(buf,sizeof(char),sizeof(buf),fd);
send(sockfd,buf,100,0);
memset(buf,0,128);
}
fclose(fd);
}
}
}
}
}
return0;
}
客户端代码还是之前的版本,没有使用select实现:
#include <stdio.h>#include
<pthread.h>#include
<string.h>#include
<sys/types.h>#include
<sys/socket.h>#include
<netinet/in.h>struct message
{
int target_id;
char buf[100];
};
struct user_password
{
char username[100];
char password[100];
};
int sd;
struct message send_message;
void * read_message(void * argv)
{
while(1)
{
//读服务器发来的消息
char revBuf[100];
read(sd,revBuf,100);
printf("recevice from server: %s",revBuf);
}
}
void * write_message(void * argv)
{
while(1)
{
printf("input message:
");
memset(send_message.buf,0,128);
send_message.target_id=-1;
scanf("%d %s",&send_message.target_id,send_message.buf);
write(sd,&send_message,sizeof(send_message));
sleep(3);
}
}
int main()
{
struct sockaddr_in server_ip,customer_ip;
int err;
sd=socket(AF_INET,SOCK_STREAM,0);
if(sd==-1)
{
printf("socket failed
");
close(sd);
return -1;
}
//server_ip初始化
server_ip.sin_family=AF_INET;
server_ip.sin_port=htons(5678);
server_ip.sin_addr.s_addr=htonl(INADDR_ANY);
//err=inet_aton("115.157.201.179",&server_ip.sin_addr.s_addr);
memset(server_ip.sin_zero,0,8);
err=connect(sd,(struct sockaddr *)(&server_ip),sizeof(server_ip));
if(err==-1)
{
printf("connect failed
");
close(sd);
return -1;
}
pid_t pid=fork();
if(pid==0)
{
while(1)
{
//读服务器发来的消息
//printf("read message:
");
char revBuf[100];
recv(sd,revBuf,100,0);
//read(sd,revBuf,100);
if(strcmp(revBuf,"quit")==0)
{
return0;
}
printf("recevice from server: %s
",revBuf);
}
}
int flag=0;
while(1)
{
printf("input message:
");
if(flag++==0)
{
struct user_password login_user;
scanf("%s %s",login_user.username,login_user.password);
err=send(sd,&login_user,sizeof(struct user_password),0);
if(err==-1)
{
printf("send failed
");
}
continue;
}
memset(send_message.buf,0,128);
send_message.target_id=-1;
scanf("%d %s",&send_message.target_id,send_message.buf);
//if(send_message.target_id!=-1&&(strcmp(send_message.buf,"")!=0))
//{
//err=send(sd,send_message.buf,100,0);
err=send(sd,&send_message,sizeof(send_message),0);
if(err==-1)
{
printf("send failed
");
}
//write(sd,&send_message,sizeof(send_message));
//}
if(strcmp(send_message.buf,"quit")==0)
{
printf("USER offline
");
close(sd);
return0;
}
send_message.target_id=-1;
memset(send_message.buf,0,sizeof(send_message.buf));
sleep(3);
}
close(sd);
return0;
}
以上是 一步一步创建聊天程序2利用epoll来创建简单的聊天室 的全部内容, 来源链接: utcz.com/z/511374.html