网络聊天室

服务器端: 

#include<myhead.h>
//存放消息的结构体
typedef struct Msgtpy
{
	char type;
	char name[40];
	char msgtext[1024];
}message_t;
//存放各个客户端信息的结构体
typedef struct Node
{
	struct sockaddr_in cin;
	struct Node *next;
}*linklist;
//单链表节点创建
linklist Create()
{
	linklist s=(linklist)malloc(sizeof(struct Node));
	if(NULL==s)
	{
		return NULL;
	}
	s->next=NULL;
	return s;
}
//单链表头插,加入新的客户端
linklist insert_head(linklist head,struct sockaddr_in cin)
{
	//创建新节点s
	linklist s=Create();
	if(NULL==s)
	{
		return NULL;
	}
	s->cin=cin;
	//判断链表是否为空
	if(NULL==head)
	{
		head=s;
	}
	else
	{
		s->next=head;
		head=s;
	}
	return head;
}
struct sockaddr_in cin;
linklist free_cli(linklist head)
{
    //只有一个客户端时
	if(head->next==NULL)
	{
		free(head);
		head=NULL;
		return head;
	}
	//有两个及以上客户端时
	linklist p=head;
	while(p->next)
	{
		if(memcmp(&(p->next->cin),&cin,sizeof(cin))==0)
		{
			linklist del=p->next;
			p->next=del->next;
			free(del);
			del=NULL;
			break;
		}
		else
		{
			p=p->next;
		}
		return head;
	}
}
int main(int argc, const char *argv[])
{
	//创建用于通信的套接字文件描述符
	int sfd=socket(AF_INET,SOCK_STREAM,0);
	if(sfd==-1)
	{
		perror("socket error\n");
		return -1;
	}

	//端口快速重用
	int reuse = -1;
	if(setsockopt(sfd,SOL_SOCKET,SO_REUSEADDR,&reuse,sizeof(reuse))==-1)
	{
		perror("setsockopt error\n");
		return -1;
	}

	//填充地址信息结构体、绑定
	struct sockaddr_in sin;
	sin.sin_family=AF_INET;
	sin.sin_port=htons(8888);
	sin.sin_addr.s_addr=inet_addr("192.168.242.132");
	if(bind(sfd,(struct sockaddr*)&sin,sizeof(sin))==-1)
	{
		perror("bind error\n");
		return -1;
	}
	//定义容器接受对端地址信息结构体
	struct sockaddr_in cin;
	socklen_t socklen = sizeof(cin);

	linklist head=NULL;//客户端链表

	//创建文件描述符容器
	fd_set readfds,tempfds;
	//清空容器
	FD_ZERO(&readfds);
	FD_SET(0,&readfds);
	FD_SET(sfd,&readfds);

	int maxfd=sfd;
	char lbuf[1024];
	char cbuf[1024];
	char qbuf[1024]; 
	message_t msg;
	while(1)
	{
		tempfds=readfds;//将要检测的容器临时复制一份

		int res=select(maxfd+1,&readfds,NULL,NULL,NULL);//阻塞等待集合中的事件发生
		if(res==-1)
		{
			perror("select error\n");
			return -1;
		}
		else if(res==0)
		{
			printf("time out\n");//超时
			return -1;
		}
		//sfd触发事件
		if(FD_ISSET(sfd,&tempfds))
		{  
			recvfrom(sfd,&msg,sizeof(msg),0,(struct sockaddr *)&cin,socklen);//接收客户端消息
			switch(msg.type)
			{
			case('L')://登录消息
				{
					head=insert_head(head,cin);
					linklist p=head;
					bzero(lbuf,sizeof(lbuf));
					printf("%s[%s:%d]登录服务器\n",msg.name,inet_ntoa(p->cin.sin_addr),ntohs(p->cin.sin_port));
					p=p->next;
					do
					{
						snprintf(lbuf,sizeof(lbuf),"%s[%s:%d]加入聊天室\n",msg.name,inet_ntoa(p->cin.sin_addr),ntohs(p->cin.sin_port));
						sendto(sfd,&lbuf,sizeof(lbuf),0,(struct sockaddr*)&(p->cin),sizeof(p->cin));
						p=p->next;
					}while(p->next);

				};break;
				case ('C')://服务器转发消息 
				{
					linklist p=head;
					p=p->next;
					bzero(cbuf,sizeof(cbuf));
					do
					{
						snprintf(cbuf,sizeof(cbuf),"%s[%s:%d]:%s\n",msg.name,inet_ntoa(p->cin.sin_addr),ntohs(p->cin.sin_port),msg.msgtext);
						sendto(sfd,cbuf,sizeof(cbuf),0,(struct sockaddr *)&(p->cin),sizeof(p->cin));
					}while(p->next);	
				};break;
				case ('Q')://客户端退出
				{
					linklist p=head;
					p=p->next;
					bzero(qbuf,sizeof(qbuf));
					do
					{
						snprintf(qbuf,sizeof(qbuf),"%s[%s:%d]退出了聊天室\n",msg.name,inet_ntoa(p->cin.sin_addr),ntohs(p->cin.sin_port));
					}while(p->next);
					head=free_cli(head);	
				};break;
				default:
				{
					printf("type error\n");
					return -1;
				}

			}
		}
		char buf[128];
		char wbuf[128];
		if(FD_ISSET(0,&tempfds))
		{
			bzero(buf,sizeof(buf));
			fgets(buf,sizeof(buf),stdin);
			buf[strlen(buf)-1]=0;
			snprintf(wbuf,sizeof(wbuf),"*****system*****\n%s",buf);
			linklist p=head;
			while(p)
			{
				sendto(sfd,wbuf,sizeof(wbuf),0,(struct sockaddr *)&(p->cin),sizeof(p->cin));
				p=p->next;
			}		
		}

	}

	return 0;
}

客户端:

#include<myhead.h>
typedef struct Msgtpy
{
	char type;
	char name[40];
	char msgtext[1024];
}message_t;
int main(int argc, const char *argv[])
{
	message_t msg;
	int cfd=socket(AF_INET,SOCK_STREAM,0);
	if(cfd==-1)
	{
		perror("socket error\n");
		return -1;
	}
	//服务器地址信息
	struct sockaddr_in sin;
	sin.sin_family=AF_INET;
	sin.sin_port=htons(8888);
	sin.sin_addr.s_addr=inet_addr("192.168.242.132");
	//客户端登录
	printf("请输入姓名:");
	fgets(msg.name,sizeof(msg.name),stdin);
	msg.name[strlen(msg.name)-1]=0;
	msg.type='L';

	if(sendto(cfd,&msg,sizeof(msg),0,(struct sockaddr *)&sin,sizeof(sin))==-1)
	{
		perror("sendto error\n");
		return -1;
	}
	else
	{
		printf("成功加入了聊天室\n");
	}

	//创建文件描述符容器
	fd_set readfds,tempfds;
	//清空容器
	FD_ZERO(&readfds);
	FD_SET(0,&readfds);
	FD_SET(cfd,&readfds);
	int maxfd=cfd;
	while(1)
	{

		tempfds=readfds;//将要检测的容器临时复制一份

		int res=select(maxfd+1,&readfds,NULL,NULL,NULL);//阻塞等待集合中的事件发生
		if(res==-1)
		{
			perror("select error\n");
			return -1;
		}
		else if(res==0)
		{
			printf("time out\n");//超时
			return -1;
		}
		if(FD_ISSET(0,&tempfds))
		{
			memset(msg.msgtext,0,sizeof(msg.msgtext));
			read(0,msg.msgtext,sizeof(msg.msgtext));
			msg.msgtext[strlen(msg.msgtext)-1]=0;

			if(strcmp(msg.msgtext,"quit")==0)
			{
				msg.type='Q';
				sendto(cfd,&msg,sizeof(msg),0,(struct sockaddr*)&sin,sizeof(sin));
				printf("本客户端下线\n");
				close(cfd);
				return 0;
			}
			else
			{
				msg.type='C';
				sendto(cfd,&msg,sizeof(msg),0,(struct sockaddr*)&sin,sizeof(sin));
				
			} 
		}
		if(FD_ISSET(cfd,&tempfds))
		{
			char buf[128];
			recvfrom(cfd,buf,sizeof(buf),0,NULL,NULL);
			printf("%s",buf);
			fflush(stdout);
		}
	}
	return 0;
}

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值