6.11聊天室

#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;
}

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值