linux 下用c语言编写的聊天室程序服务器和客户端.docx
《linux 下用c语言编写的聊天室程序服务器和客户端.docx》由会员分享,可在线阅读,更多相关《linux 下用c语言编写的聊天室程序服务器和客户端.docx(19页珍藏版)》请在冰豆网上搜索。
linux下用c语言编写的聊天室程序服务器和客户端
/*
*server.c
*
*Createdon:
2012-6-15
*Author:
root
*/
#include
#include
#include
#include
#include
#include
#include
#include
#include
#definePORT7999
#defineMAX_NUM3//client连接最大个数
#defineMAX_CLIENT15
#defineMAX_SIZE1024
pthread_rwlock_tidx_lock,wait_lock;
//client信息
typedefstruct_client{
intsockfd;
charname[20];
pthread_tpid;
intflg;
}c_client;
c_clientclient[MAX_CLIENT];//定义client;
//等待的client
struct_client_{
intsockfd;
charname[20];
pthread_tpid;
struct_client_*next;
};
typedefstruct_client_c_client_c;
c_client_c*head=NULL;
c_client_c*temp_c1=NULL,*temp_c2=NULL;//等待的
//初始化client信息
voidinit_client(){
inti=0;
for(i=0;iclient[i].sockfd=-1;
memset(client[i].name,0,20);
client[i].pid=-1;
client[i].flg=-1;
}
}
//查找结构体数组中sockfd为-1的下标值
intfind_fd(c_client*client){
inti=0;
while(i//printf("====%d\n",client[i].sockfd);
if(client[i].sockfd==-1)
returni;
i++;
}
return-1;
}
//判断登录格式
intlogform(char*buf){
char*p=strstr(buf,"LOGIN\r\n");
intn=strlen(buf);
char*q=p+n-4;
if(p!
=NULL&&p+7!
=q&&strcmp(q,"\r\n\r\n")==0)
return1;
else
return0;
}
intcmpname(char*buf,c_client*p_client){
inti=0;
char*p=strtok(buf+7,"\r\n\r\n");
while(client[i].sockfd!
=-1&&client[i].sockfd!
=p_client->sockfd&&i
if(strcmp(client[i].name,p)==0)
return0;
i++;
}
return1;
}
//SHOW
voidshowuser(c_client*p_client){
inti=0;
charbuf[1024]={0};
strcpy(buf,"200\r\n");
for(i=0;iif(client[i].sockfd!
=-1){
sprintf(buf+strlen(buf),"%s\r\n",client[i].name);
}
}
sprintf(buf+strlen(buf),"\r\n");
send(p_client->sockfd,buf,strlen(buf),0);
}
//ALL
voidsendto_all(c_client*p_client,char*buf){
inti=0;
charsendbuf[1024]={0};
sprintf(sendbuf,"AFROM\r\n%s\r\n%s",p_client->name,buf+5);
for(i=0;iif(client[i].sockfd!
=-1&&client[i].flg!
=-1)
if(send(client[i].sockfd,sendbuf,strlen(sendbuf),0)<=0){
printf("senderrrrrr\n");
exit
(1);
}
}
}
intfindname(char*name){
inti=0;
for(i=0;iif(client[i].sockfd!
=-1&&strcmp(client[i].name,name)==0)
returnclient[i].sockfd;
}
return0;
}
//TO
voidsendto_one(c_client*p_client,char*buf){
inti=0;
charsendbuf[1024]={0};
charname[20]={0};
char*p=strtok(buf+4,"\r\n");//TO\r\n:
4个字符后取出\r\n前的名字
strcpy(name,p);
intsock=findname(name);
if(!
sock){
sprintf(sendbuf,"ERROR2\r\n%s用户不存在\r\n\r\n",name);
send(p_client->sockfd,sendbuf,strlen(sendbuf),0);
}else{
sprintf(sendbuf,"FROM\r\n%s\r\n%s",p_client->name,buf+4+strlen(
name)+2);
if(send(sock,sendbuf,strlen(sendbuf),0)<=0){
printf("senderrrrrr\n");
exit
(1);
}
}
}
voidpthread_fun(void*cclient);
//quit
voidquit(c_client*p_client){
inti=0;
intidx;
charbuf[1024]={0};
c_client_c*temp;
printf("--%s退出聊天室\n",p_client->name);
close(p_client->sockfd);
p_client->sockfd=-1;
p_client->pid=-1;
p_client->flg=-1;
sprintf(buf,"NOTICE1\r\n%s退出聊天室\r\n\r\n",p_client->name);
memset(p_client->name,0,20);
for(i=0;iif(client[i].sockfd!
=-1&&client[i].flg!
=-1)
send(client[i].sockfd,buf,strlen(buf),0);
}
if(head!
=NULL&&head->next!
=NULL){
memset(buf,0,1024);
pthread_rwlock_rdlock(&idx_lock);
idx=find_fd(client);
pthread_rwlock_unlock(&idx_lock);
client[idx].sockfd=head->next->sockfd;
pthread_rwlock_wrlock(&wait_lock);
temp=head->next;
head->next=head->next->next;
free(temp);
pthread_rwlock_unlock(&wait_lock);
sprintf(buf,"NOTICE\r\n您已被唤醒,请继续操作\r\n\r\n");
send(client[idx].sockfd,buf,strlen(buf),0);
if(pthread_create(&client[idx].pid,NULL,(void*)pthread_fun,(void*)&client[idx])!
=0){
perror("pthread_create");
exit
(1);
}
pthread_detach(client[idx].pid);
}
}
voidpthread_fun(void*cclient){
c_client*p_client=(c_client*)cclient;
charbuf[MAX_SIZE]={0};
charsendbuf[1024]={0};
inti,n;
char*p;
sprintf(sendbuf,"%s","NOTICE\r\n通讯通道开启\r\n\r\n");
if(send(p_client->sockfd,sendbuf,strlen(sendbuf),0)<=0){
printf("senderr\n");
}
memset(sendbuf,0,1024);
while
(1){
memset(buf,0,MAX_SIZE);
n=recv(p_client->sockfd,buf,sizeof(buf)-1,MSG_NOSIGNAL);
if(n<=0){
close(p_client->sockfd);
p_client->sockfd=-1;
break;
}
if(logform(buf)){
if(cmpname(buf,p_client)==0){
send(p_client->sockfd,"ERROR\r\n用户名重复\r\n\r\n",26,0);
continue;
}else{
p_client->flg=1;
p=strtok(buf+7,"\r\n\r\n");
strcpy(p_client->name,p);
sprintf(sendbuf,"100\r\n%s\r\n\r\n",p_client->name);
send(p_client->sockfd,sendbuf,sizeof(sendbuf),0);
printf("%s进入聊天室\n",p_client->name);
for(i=0;iif(client[i].sockfd!
=-1&&client[i].sockfd
!
=p_client->sockfd&&client[i].flg!
=-1)
send(client[i].sockfd,sendbuf,sizeof(sendbuf),0);
}
memset(sendbuf,0,1024);
while
(1){
memset(buf,0,MAX_SIZE);
if((n=recv(p_client->sockfd,buf,MAX_SIZE,0))<=0){
perror("recverr");
break;
}
//printf("recv=%s\n",buf);
if((p=strstr(buf,"\r\n\r\n"))!
=NULL&&*(p+4)
=='\0'){
if(!
strncmp(buf,"SHOW\r\n\r\n",8)){
showuser(p_client);//客户端执行show后,发送给客户端已连接的用户
continue;
}
if(!
strncmp(buf,"ALL\r\n",5)){
sendto_all(p_client,buf);
continue;
}
if(!
strncmp(buf,"TO\r\n",4)){
sendto_one(p_client,buf);
continue;
}
if(!
strncmp(buf,"QUIT\r\n\r\n",8))
quit(p_client);
//break;
pthread_exit(NULL);
}else{
send(p_client->sockfd,"ERROR\r\n信息不符合协议要求\r\n\r\n",
38,0);
}
}
}
}else{
send(p_client->sockfd,"ERROR\r\n未登录,请您登录再进行其他操作\r\n\r\n",56,0);
}
}
pthread_exit(NULL);
}
intmain(){
intser_sockfd,clt_sockfd;
structsockaddr_inaddr;
intidx;
charbuf[1024]={0};
//pthread_rwlock_tidx_lock,wait_lock;
pthread_rwlock_init(&idx_lock,NULL);
pthread_rwlock_init(&wait_lock,NULL);
init_client();
//创建服务器sockfd
if((ser_sockfd=socket(AF_INET,SOCK_STREAM,0))==-1){
perror("socket");
exit
(1);
}
//设置服务器网络地址
bzero(&addr,sizeof(addr));
addr.sin_family=AF_INET;
addr.sin_port=htons(PORT);
addr.sin_addr.s_addr=htonl(INADDR_ANY);
//设置端口可重用
intopt=1;
setsockopt(ser_sockfd,SOL_SOCKET,SO_REUSEADDR,&opt,sizeof(opt));
//将套接字绑定到服务器的网络地址上
if(bind(ser_sockfd,(structsockaddr*)&addr,sizeof(addr))==-1){
perror("bind");
exit
(1);
}
printf("bindsuccess\n");
//监听连接请求--监听队列长度为10
if(listen(ser_sockfd,10)==-1){
perror("listen");
exit
(1);
}
printf("listensuccess\n");
while
(1){
if((clt_sockfd=accept(ser_sockfd,NULL,NULL))==-1){
perror("accept");
exit
(1);
}
pthread_rwlock_rdlock(&idx_lock);
idx=find_fd(client);
//printf("idx=%d\n",idx);
pthread_rwlock_unlock(&idx_lock);
if(idx!
=-1){//连接末满
client[idx].sockfd=clt_sockfd;
if(pthread_create(&client[idx].pid,NULL,(void*)pthread_fun,
(void*)&client[idx])!
=0){
perror("pthread_create");
exit
(1);
}
pthread_detach(client[idx].pid);
}else{//连接已满,等待
temp_c1=(c_client_c*)malloc(sizeof(c_client_c));
temp_c1->sockfd=clt_sockfd;
temp_c1->next=NULL;
pthread_rwlock_wrlock(&wait_lock);
if(head==NULL){
head=(c_client_c*)malloc(sizeof(c_client_c));
head->next=temp_c1;
}else{
for(temp_c2=head;temp_c2->next!
=NULL;temp_c2=temp_c2->next);
temp_c2->next=temp_c1;
}
pthread_rwlock_unlock(&wait_lock);
memset(buf,0,1024);
sprintf(buf,"NOTICE\r\n服务器已满,请等候\r\n\r\n");//客户端接受则等待
if(send(temp_c1->sockfd,buf,strlen(buf),0)<=0){
printf("sendrerr\n");
}
}
}
}
/*
*client.c
*
*Createdon:
2012-6-18
*Author:
root
*/
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#defineMAX_SIZE1024
#definePORT7999
staticintFLAGE=-1;
charname[20]={0};
voidfun_show(intsockfd){
charsendbuf[256]={0};
sprintf(sendbuf,"SHOW\r\n\r\n");
if(send(sockfd,sendbuf,strlen(sendbuf),0)<=0){
printf("senderr\n");
close(sockfd);
exit
(1);
}
}
voidfun_all(intsockfd){
charsendbuf[MAX_SIZE]={0};
sprintf(sendbuf,"ALL\r\n",5);
printf("输入发送的内容:
\n");
scanf("%s",sendbuf+5);
sprintf(sendbuf+strlen(sendbuf),"\r\n\r\n");
if(send(sockfd,sendbuf,strlen(sendbuf),0)<=0){
printf("senderr\n");
close(sockfd);
exit
(1);
}
}
voidfun_one(intsockfd){
charsendbuf[MAX_SIZE]={0};
charname3[20]={0};
printf("输入聊天对象:
");
scanf("%s",name3);
sprintf(sendbuf,"TO\r\n%s\r\n",name3);
printf("输入聊天内容:
\n");
scanf("%s",sendbuf+strlen(sendbuf));
sprintf(sendbuf+strlen(sendbuf),"\r\n\r\n");
if(send(sockfd,sendbuf,strlen(sendbuf),0)<=0){
printf("senderr\n");
close(sockfd);
exit
(1);
}
}
voidfun_quit(intsockfd){
charsendbuf[256]="QUIT\r\n\r\n";
if(send(sockfd,sendbuf,strlen(sendbuf),0)<=0){
printf("senderr\n");
close(sockfd);
exit
(1);
}
}
void*pthread_fun(int*sock){
intsockfd