#include <myhead.h>
#define IP "192.168.2.66"
#define PORT 8888
#define ERR_MSG(msg) do{\
printf("\t%d\t%s\t",__LINE__,__func__);\
perror("msg");\
}while(0);
typedef struct node //存储客户信息的链表
{
struct sockaddr_in skar;
struct node *NEXT;
}*linklist;
struct msg //客户端发送的协议
{
char type;
char name[128];
char txt[128];
};
struct apple
{
int newfd;
struct sockaddr_in cin;
linklist L;
struct msg buf6;
};//要给子线程处理函数传的参
linklist create()
{
linklist L =(linklist)malloc(sizeof(struct node));
if(L==NULL)
{
printf("创建节点失败\n");
return NULL;
}
L->NEXT = NULL;
return L;
}
int flag = 0;
int stag = 0;
struct msg GG={'F',"FWQ"};
//捕获到ctrl+z信号后,系统发公告,这是线程中阻塞的条件
void handler(int signo)
{
stag = 1;
}
void *orange(void *arg); //登录
void *pear(void *arg);
int banana(struct msg buf2,linklist L,int sfd); //向所有客户端发送信息
int main(int argc, const char *argv[])
{
//设置捕获信号以及handler函数
if(signal(SIGTSTP,handler) == SIG_ERR)
{
ERR_MSG("signal");
return -1;
}
int sfd = socket(AF_INET,SOCK_DGRAM,0);
if(sfd<0)
{
ERR_MSG("socket");
return -1;
}
struct sockaddr_in sin;
sin.sin_family = AF_INET;
sin.sin_port = htons(PORT);
sin.sin_addr.s_addr = inet_addr(IP);
if(bind(sfd,(struct sockaddr*)&sin,sizeof(sin))<0)
{
ERR_MSG("bind");
return -1;
}
linklist L =create();
L->skar = sin; //链表头部存服务器自身的地址信息
printf("服务器连接成功%d\n",__LINE__);
struct msg buf;
struct sockaddr_in cin;
socklen_t len = sizeof(buf);
pthread_t pt,pt2;
struct apple apple1={sfd,cin,L,buf};
if(pthread_create(&pt,NULL,pear,&apple1)!=0)
{
ERR_MSG("pthread_create");
}
while(1)
{
bzero(&buf,sizeof(buf));
if(recvfrom(sfd,&buf,len,0,(struct sockaddr*)&cin,&len)<0)
{
ERR_MSG("recvfrom");
return -1;
}
printf("%s\n",buf.txt);
apple1.cin = cin;
apple1.buf6 =buf;
if(pthread_create(&pt2,NULL,orange,&apple1)!=0)
{
ERR_MSG("pthread_create");
}
if(flag == 1)
{
break;
}
pthread_detach(pt2);
pthread_detach(pt);
}
close(sfd);
return 0;
}
void *orange(void * arg) //实现登录、群聊、下线功能
{
struct apple *apple1 = (struct apple *)arg;
struct msg buf = apple1->buf6;
printf("%s\n",buf.txt);
linklist L = apple1->L;
int sfd = apple1->newfd;
struct sockaddr_in cin = apple1->cin;
if(buf.type=='L')
{
while(L->NEXT)
{
if(memcmp((const void *)&(L->NEXT->skar),(const void *)&cin,sizeof(cin))==0)
{
strcpy(GG.txt,"已经登录,请勿重复登录");
if(sendto(sfd,&GG,sizeof(GG),0,(struct sockaddr*)&cin,sizeof(cin))<0)
{
ERR_MSG("sendto");
return NULL;
}
return NULL;
}
L=L->NEXT;
}
linklist p = create();
L->NEXT = p;
p->skar=cin;
strcpy(buf.txt,"登录");
banana(buf,L,sfd);
}else if(buf.type=='C')
{
banana(buf,L,sfd);
}else if(buf.type=='Q')
{
while(L->NEXT)
{
if(memcmp((const void *)&(L->NEXT->skar),(const void *)&cin,sizeof(cin))==0)
{
linklist q = L->NEXT;
L->NEXT=q->NEXT;
free(q);
strcpy(buf.txt,"已退出登录");
banana(buf,L,sfd);
return NULL;
}
}
strcpy(buf.txt,"请先登录");
if(sendto(sfd,&buf,sizeof(buf),0,(struct sockaddr*)&cin,sizeof(cin))<0)
{
ERR_MSG("sendto");
return NULL;
}
}
pthread_exit(NULL);
}
void *pear(void *arg) //子线程功能
{
int sfd = ((struct apple*)arg)->newfd;
linklist L = ((struct apple*)arg)->L;
char c;
while(1)
{
while(stag ==1)
{
printf("请输入你想发布的公告:");
scanf("%s",GG.txt);
getchar();
banana(GG,L,sfd);
printf("是否继续发送(y or n or b)或者结束该聊天室:");
c=getchar();
if(c=='n')
{
stag=0; //
}else if(c == 'b'){
stag = 0;
flag = 1;
break;
}
getchar();
}
}
pthread_exit(NULL);
}
int banana(struct msg buf2,linklist L,int sfd) //向所有人发消息
{
while(L->NEXT)
{
if(sendto(sfd,&buf2,sizeof(buf2),0,(struct sockaddr*)&(L->NEXT->skar),sizeof(L->NEXT->skar))<0)
{
ERR_MSG("sendto");
return -1;
}
L=L->NEXT;
}
return 0;
}
6.11聊天室
最新推荐文章于 2024-07-24 18:23:35 发布