小项目:多人聊天室

1.服务器

#include<myhead.h>
#define SER_IP "192.168.126.80"
#define SER_PORT 8888
//创建链表结构体
typedef struct Node
{
	char name[20];//用户名
	struct sockaddr_in cin;
	struct Node *next;//指针域
}*node;
//服务器发送系统消息
int system_send(int sfd,node head,const char*buf,size_t length)
{
	node p=head;
	while(p!=NULL)
	{
		sendto(sfd,buf,length,0,(struct sockaddr*)&(p->cin),sizeof(p->cin));
		p=p->next;
	}
	return 0;
}
//上线
node add_node(node head,const char *data,struct sockaddr_in cin)
{
	node p=(node)malloc(sizeof(struct Node));
	p->cin=cin;
	strcpy(p->name,data);
	p->next=head;
	head=p;
	return head;
}
//下线
node del_node(node head,const char *name_point)
{
	node p=head;
	if(strcmp(p->name,name_point)==0)
	{
		head=p->next;
		free(p);
		p=NULL;
		return head;
	}
	while(strcmp(p->name,name_point)!=0)
	{
		p=p->next;
	}
	if(p->next==NULL)
	{
		node q=head;
		while(q->next->next!=NULL)
		{
			q=q->next;
		}
		free(p);
		p=NULL;
		q->next=NULL;
		return head;
	}
	node q=head;
	while(strcmp(q->next->name,name_point)!=0)
	{
		q=q->next;
	}
	q->next=p->next;
	free(p);
	p=NULL;
	return head;
}
int main(int argc, const char *argv[])
{
	//创建套接字
	int sfd=socket(AF_INET,SOCK_DGRAM,0);
	//通信协议族:AT_INET使用IPv4
	//指定通信类型:SOCK_DGRAM支持UDP通信方式
	//参数2已指定通信类型,设为0
	if(sfd==-1)
	{
		perror("socket error");
		return -1;
	}
	//绑定ip地址和端口号
	//填充地址信息结构体
	struct sockaddr_in sin;
	sin.sin_family=AF_INET;//地址族
	sin.sin_port=htons(SER_PORT);//端口号
	sin.sin_addr.s_addr=inet_addr(SER_IP);//ip地址
	//绑定
	if(bind(sfd,(struct sockaddr*)&sin,sizeof(sin))==-1)
		//套接字文件描述符
		//通用地址信息结构体,sockaddr_in的IPv4
		//参数2的大小
	{
		perror("bind error");
		return -1;
	}
	//定义容器接收对端地址信息结构体
	struct sockaddr_in cin;
	socklen_t socklen=sizeof(cin);
	//使用poll函数服务器端
	//定义一个pollfd数组
	struct pollfd pfd[2];
	pfd[0].fd=0;//检测0号文件描述符
	pfd[0].events=POLLIN;//检测0号文件描述符的读操作
	pfd[1].fd=sfd;//检测sfd文件描述符
	pfd[1].events=POLLIN;//检测cfd中的读操作
	int n=2;
	node head=NULL;//链表头
	while(1)
	{
		int res=poll(pfd,n,-1);
		//文件描述符
		//检测的文件描述符个数
		//超时时间,负数永久等待,0非阻塞,大于0超时后解除阻塞
		if(res==-1)
		{
			perror("poll error");
			return -1;
		}
		else if(res==0)
		{
			printf("time out\n");
			return -1;
		}
		if(pfd[0].revents==POLLIN)//0号文件描述符发生事件
		{
			char buf[128]="";
			scanf("%s",buf);
			char sys_buf[128];
			sprintf(sys_buf,"***system****>>>%s",buf);//格式化输出转为字符串
			system_send(sfd,head,sys_buf,sizeof(sys_buf));
			printf("系统发送消息\n");
		}
		if(pfd[1].revents==POLLIN)//cfd文件描述符事件发生
		{
			char buf[200]="";
			recvfrom(pfd[1].fd,buf,sizeof(buf),0,(struct sockaddr*)&cin,&socklen);
			short *type_point=(short *)buf;
			switch(ntohs(*type_point))
			{
			case 1:
				{
					//接收登录消息
					char *data_point =buf+2;
					char buf[300]="";
					sprintf(buf,"******%s已登录******",data_point);
					system_send(sfd,head,buf,sizeof(buf));
					head=add_node(head,data_point,cin);
					printf("%s登录\n",data_point);
					break;
				}
			case 2:
				{
					//收到聊天消息
					char *name_point=buf+2;
					char *data_point=name_point+strlen(name_point)+1;
					char buf[300]="";
					sprintf(buf,"%s>>>%s",name_point,data_point);
					system_send(sfd,head,buf,sizeof(buf));
					printf("%s发送消息\n",name_point);
					break;
				}
			case 3:
				{
					//接收退出消息
					char *name_point=buf+2;
					char *data_point=name_point+strlen(name_point)+1;
					char endbuf[20]="";
					strcpy(endbuf,"quit");
					sendto(sfd,endbuf,sizeof(endbuf),0,(struct sockaddr*)&cin,sizeof(cin));
					del_node(head,name_point);
					char buf[300]="";
					sprintf(buf,"******%s已下线******",name_point);
					system_send(sfd,head,buf,sizeof(buf));
					printf("%s下线\n",name_point);
					break;
				}
			}
		}
	}
	//关闭文件描述符
	close(sfd);
	return 0;
}

2.客户端

#include <myhead.h>
#define SER_PORT 8888
#define SER_IP "192.168.126.80"
 
int login(int sfd,struct sockaddr_in sin,const char *name)
{
	
	char buf[200]="";
	short *type_point = (short*)buf;
	char *data_point = buf+2;
	*type_point=htons(1);
	strcpy(data_point,name);
 
	sendto(sfd,buf,sizeof(buf),0,(struct sockaddr*)&sin,sizeof(sin));
	return 0;
}
int main(int argc, const char *argv[])
{
	//创建套接字
	int sfd=socket(AF_INET,SOCK_DGRAM,0);
	if(sfd==-1)
	{
		perror("socket error:");
		return -1;
	}
	//绑定ip地址和端口号
	struct sockaddr_in sin;
	sin.sin_family=AF_INET;//地址族
	sin.sin_port=htons(SER_PORT);//端口号
	sin.sin_addr.s_addr=inet_addr(SER_IP);//ip地址
	socklen_t socklen;
 
	printf("=======欢迎使用网络聊天室=======\n");
	printf("请输入姓名:");
	char name[20];
	scanf("%s",name);
//调用注册函数 
	login(sfd,sin,name);
	
	pid_t pid;
	pid=fork();
	if(pid>0)
	{
		//父进程,用于发消息
		char buf[128]="";
		short *type_point = (short*)buf;
		char *name_point = buf+2;
		strcpy(name_point,name);
		char *data_point=name_point+strlen(name_point)+1;
		while(1)
		{
			scanf("%s",data_point);
			if(strcmp(data_point,"quit")==0)
			{
				*type_point=htons(3);
				sendto(sfd,buf,sizeof(buf),0,(struct sockaddr*)&sin,sizeof(sin));
				break;
			}
			*type_point=htons(2);
			sendto(sfd,buf,sizeof(buf),0,(struct sockaddr*)&sin,sizeof(sin));
		}
	}
	else if(pid==0)
	{
		//子进程,用于接收消息
		while(1)
		{
			char buf[128];
			recvfrom(sfd,buf,sizeof(buf),0,(struct sockaddr*)&sin,&socklen);
			if(strcmp(buf,"quit")==0)
			{
				break;
			}
			printf("%s\n",buf);
		}
	}
 
	wait(NULL);
	close(sfd);
	return 0;
}

运行结果:

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值