10.22作业

项目需求:

  1. 如果有用户登录,其他用户可以收到这个人的登录信息

  2. 如果有人发送信息,其他用户可以收到这个人的群聊信息

  3. 如果有人下线,其他用户可以收到这个人的下线信息

  4. 服务器可以发送系统信息

 服务器代码

#include <stdio.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <pthread.h>
#include <string.h>
#include <math.h>
#include <stdlib.h>
#include <netinet/in.h>
#include <netinet/ip.h>
#include <arpa/inet.h>
#define ERR_MSG(msg) {printf("line=%d\n",__LINE__);perror("msg");}
#define IP "0.0.0.0"
#define PORT 8888
typedef struct node
{
	struct sockaddr_in  client_information;
	struct node * pro;
	struct node * next;
}*client,doublelink;
//创建结构体申请函数
client list_create()
{
	client p=(client)malloc(sizeof(doublelink));
	if (p==NULL)
	{
		printf("空间申请失败\n");
		return NULL;
	}
	p->next=NULL;
	p->pro=NULL;
	return p;
}
//新人头插法,将数据插入双向链表中                后进行,避免被遍历到
void new_list_insert(client head_p,client new_meber)    //新人的数据结构体     头结点
{
	new_meber->next=head_p->next;
	new_meber->pro=head_p;
	head_p->next->pro=new_meber;
	head_p->next=new_meber;
	return;
}
//新人上线通知
//名字字符串地址,头结点地址      先进行,不然容易遍历到自己
void new_join(char *p1,client p2,int sfd)
{
	struct sockaddr_in addr;
	ssize_t res;
	if (p2->next==p2)
	{
		return ;
	}
	client p3=p2->next;
	char frr[128];
	sprintf(frr,"%s%s%s%s","****",p1,"***","*online****");
	while(p3!=p2)
	{
		res=sendto(sfd,frr,sizeof(frr),0,(struct sockaddr*)&(p3->client_information),sizeof(addr));
		if (res<0)
		{
			ERR_MSG("sendto");
			return ;
		}
		p3=p3->next;
	}

}
struct ifo              //传参结构体
{
	int fd;
	client p;

};
void *recv_func(void *pp)   // sfd   头结点p
{
	struct ifo *p1=(struct ifo*)pp;
	int sfd=p1->fd;
	char arr_recv[256]="";
	ssize_t arr_len=sizeof(arr_recv);
	struct sockaddr_in recv_client;
	socklen_t len=sizeof(recv_client);
	while(1)
	{
		bzero(arr_recv,arr_len);
		ssize_t size_recv=recvfrom(sfd,(void *)arr_recv,arr_len,0,(struct sockaddr*)&recv_client,&len);
		if (size_recv<0)
		{
			ERR_MSG("recvfrom");
			return NULL;
		}
		if (arr_recv[0]=='N')
		{
			//新人上线通知
			new_join(arr_recv+1,p1->p,sfd);
			//新人加入链表
			client new_meber=list_create();
			new_meber->client_information.sin_family=recv_client.sin_family;
			new_meber->client_information.sin_port=recv_client.sin_port;
			new_meber->client_information.sin_addr=recv_client.sin_addr;
			new_list_insert(p1->p,new_meber); 
		}
		else if (arr_recv[0]=='F')
		{
			client p3=p1->p->next;
			while(p3!=p1->p)
			{
				if(p3->client_information.sin_port==recv_client.sin_port)  //判断是不是自己
				{
					p3=p3->next;
					continue;
				}
				sendto(sfd,(void *)(arr_recv+1),strlen(arr_recv)-1,0,(struct sockaddr*)&(p3->client_information),len);
				p3=p3->next;
			}
		}
		else if(arr_recv[0]=='E')
		{
			client p4;
			client p3=p1->p->next;
			while(p3!=p1->p)
			{
				if(p3->client_information.sin_port==recv_client.sin_port)  //判断是不是自己
				{
					p4=p3;
					p3->pro->next=p3->next;
					p3->next->pro=p3->pro;
					p3=p3->next;
					continue;
				}
				sendto(sfd,(void *)(arr_recv+1),strlen(arr_recv)-1,0,(struct sockaddr*)&(p3->client_information),len);
				p3=p3->next;
			}
			free(p4);
			p4=NULL;
		}

	}
}
void *send_func(void *pp)
{ 
	struct ifo *p1=(struct ifo*)pp;
	struct sockaddr_in len11;
	char buf[256]="";
	char arr[256]="";
	while(1)
	{
		bzero(buf,sizeof(buf));
		bzero(arr,sizeof(arr));
		fgets(buf,sizeof(buf),stdin);
		buf[strlen(buf)-1]=0;
		sprintf(arr,"%s%s%s","***system***",buf,"***system***");
		client p2=p1->p->next;
		while(p2!=(p1->p))
		{
			sendto(p1->fd,arr,sizeof(arr),0,(struct sockaddr*)&(p2->client_information),sizeof(len11));
			p2=p2->next;
		}
	}
}
int main(int argc, const char *argv[])
{
	struct ifo message;
	client head_p=list_create();
	if (head_p==NULL)
	{
		printf("头结点创建失败\n");
	}
	head_p->next=head_p;
	head_p->pro=head_p;
	message.p=head_p;      //将头结点放入结构体
	int sfd=socket(AF_INET,SOCK_DGRAM,0);
	if (sfd<0)
	{
		ERR_MSG("socket");
		return -1;
	}
	message.fd=sfd;    //将文件描述符放入结构体
	//创建服务器IP结构体
	struct sockaddr_in server_information;
	server_information.sin_family=AF_INET;
	server_information.sin_port=htons(PORT);
	server_information.sin_addr.s_addr=inet_addr(IP);
	//绑定服务器端口与IP
	if (bind(sfd,(struct sockaddr*)&server_information,sizeof(server_information))<0)
	{
		ERR_MSG("bind");
		return -1;
	}
	//创建第一个线程
	pthread_t pthread_1;
	if (pthread_create(&pthread_1,NULL,send_func,(void*)&message)<0)
	{
		ERR_MSG("pthread_create");
		return -1;
	}
	//创建第二个线程
	pthread_t pthread_2;
	if (pthread_create(&pthread_2,NULL,recv_func,(void*)&message)<0)
	{
		ERR_MSG("pthread_create");
		return -1;
	}
	//阻塞等待指定线程退出
	pthread_join(pthread_1,NULL);
	pthread_join(pthread_2,NULL);
	return 0;
}

客户端代码

#include <stdio.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <netinet/ip.h>
#include <string.h>
#include <pthread.h>
#include <math.h>
#include <arpa/inet.h>
#define ERR_MSG(msg) {printf("%d\n",__LINE__);perror("msg");};
struct inf
{
	int fd;
	struct sockaddr_in  server_IP_PORT;
	char c_name[128];
};
void *send_func(void *pp)
{
	struct inf *p=(struct inf*)pp;
	int sfd_1=p->fd;
	struct sockaddr_in server_inf_1=p->server_IP_PORT;
	char arr[128]="";
	char brr[256]="";
	while(1)
	{
		bzero(arr,sizeof(arr));
		bzero(brr,sizeof(brr));
		fgets(arr,sizeof(arr),stdin);
		arr[strlen(arr)-1]=0;
		if(strcmp(arr,"quit")==0)     //判断是否退出
		{
			sprintf(brr,"%s%s%s%s","E",p->c_name,"****","offline");  //拼接
			sendto(sfd_1,brr,sizeof(brr),0,(struct sockaddr*)&server_inf_1,sizeof(server_inf_1));
			return NULL;
		}
		sprintf(brr,"%s%s%c%s","F",p->c_name,':',arr);    //拼接
		sendto(sfd_1,brr,sizeof(brr),0,(struct sockaddr*)&server_inf_1,sizeof(server_inf_1));
	}

}
void *recv_func(void *pp)
{
	struct inf *p=(struct inf*)pp;
	int sfd_2=p->fd;
	struct sockaddr_in server_inf_2=p->server_IP_PORT;
	socklen_t addrlen=sizeof(server_inf_2);
	char crr[128]="";
	while(1)
	{
		bzero(crr,sizeof(crr));
		recvfrom(sfd_2,crr,sizeof(crr),0,(struct sockaddr*)&server_inf_2,&addrlen);
		printf("%s\n",crr);
	}
}
int main(int argc, const char *argv[])
{
	struct inf c_need;
	int sfd=socket(AF_INET,SOCK_DGRAM,0);
	if (sfd<0)
	{
		ERR_MSG("socket");
		return -1;
	}
	c_need.fd=sfd;              //穿参
	char name[128]="";
	char crr[128]="";
	printf("请输入姓名>>>>>>>");
	fgets(name,sizeof(name),stdin);
	name[strlen(name)-1]=0;
	strcpy(c_need.c_name,name);    //穿参
	sprintf(crr,"%s%s","N",name);
	struct sockaddr_in server_inf; 
	server_inf.sin_family=AF_INET;
	server_inf.sin_port=htons(8888);
	server_inf.sin_addr.s_addr=inet_addr("0.0.0.0");
	c_need.server_IP_PORT=server_inf;
	if (sendto(sfd,crr,strlen(name)+1,0,(struct sockaddr*)&server_inf,sizeof(server_inf))<0)
	{
		ERR_MSG("sendto");
		return -1;
	}
	//创建线程
	pthread_t pt_1;
	if (pthread_create(&pt_1,NULL,send_func,(void *)&c_need)<0)
	{
		ERR_MSG("pthread_create");
		return -1;
	}
	//创建线程2
	pthread_t pt_2;
	if (pthread_create(&pt_2,NULL,recv_func,(void *)&c_need)<0)
	{
		ERR_MSG("pthread_create");
		return -1;
	}
	pthread_join(pt_1,NULL);
	return 0;
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值