基于UDP的聊天群

文章描述了一个使用UDP协议的服务器程序,通过链表管理连接的客户端,支持登录、聊天和退出功能。客户端通过发送消息类型指示操作,如登录名、聊天内容或退出请求。

服务器(未完成)

#include <my_head.h>
#define SER_PORT 8888
#define SER_IP "192.168.96.132"

typedef struct Msg
{
	char type;   //消息类型
	char name[20];  //用户ID
	char text[128];  //消息内容
}msg_t;
//链表节点
typedef struct node
{
	struct sockaddr_in cin; //数据域:客户的网络地址信息结构体
	struct node_t *next;  //指针域:下一个节点的地址

}*list;

//创建头结点
list create_node()
{
	list p=(list)malloc(sizeof(struct node));
	if(NULL==p)
		return NULL;
	p->next=NULL;
	return p;
}


int main(int argc, const char *argv[])
{
	//创建报式套接字
	int sfd=socket(AF_INET,SOCK_DGRAM,0);
	//创建头结点
	list p=NULL;
	if(sfd==-1)
	{
		perror("socket error");
		return -1;
	}
	//将端口号快速重用
	int reuse=-1;
	if(setsockopt(sfd,SOL_SOCKET,SO_REUSERADDR,&reuse,sizeof(reuse))==-1)
	{
		perror("setsockopt error");
		return -1;
	}
	//绑定服务器地址信息
	struct sockaddr_in sin;
	sin.sin_family = AF_INET;
	sin.sin_port   = htons(SER_PORT);
	sin.sin_addr.s_addr = inet_addr(SER_IP);
	if(bind(sfd,(struct sockaddr *)&sin,sizeof(sin))==-1)
	{
		perror("bind error");
		return -1;
	}
	printf("bind success\n");


	int res=0;
	//定义客户端信息变量
	struct sockaddr_in cin;
	socklen_t socklen = sizeof(cin);
	list p=create_node();//定义p为头结点
	msg_t msg;


	while(1)
	{
		//收到客户端来信
		res=recvfrom(sfd,&msg,sizeof(msg),(struct sockaddr *)&cin,&socklen);
		if(res==-1)
		{
			perror("recvfrom error");
			return -1;
		}
		if(msg.type=='L')
		{
			//登录
			login(sfd,msg,p,cin,socklen);
		}
		if(msg.type=="S")	sendto

		{
			//聊天
			chat(sfd,msg,p,cin);
		}
		if(msg.type=="Q")
		{
			//退出
		}
		else


	}
	//关闭套接字
	close(sfd);

	return 0;
}

void login(int sfd,msg_t msg,list p,struct sockaddr_in cin,socklen_t socklen)
{
	//客户端登录及创建一个新的节点
	list new=(list)malloc(sizeof(struct node));
	while(p->next!=NULL)
	{
		//向所有的客户端发送某某客户端上线的消息
		p=p->next;
		if(sendto(sfd,&msg,sizeof(msg),0,(struct sockaddr *)&cin,socklen)==-1)
		{
			perror("sendto error");
			return -1;
		}
		printf("%s已上线",msg->name);
	}
	//将新用户信息保存 尾插到链表中
	new->cin=cin;
	new->next=NULL;
	p->next=new;
	return;
}

void chat(int sfd,msg_t msg,list p,struct sockaddr_in cin)
{
	//把收到客户端的消息转发给其他所有在线客户端
	while(p->next!=NULL)
	{
		p=p->next;
		sendto(sfd,&msg,sizeof(msg),0,(struct sockaddr *)&(p->cin),sizeof(p->cin));
	}
}

void quit(int sfd,msg_t msg,list p,struct sockaddr_in cin)
{
	//先删除下线客户端对应节点,在将下线消息发给在线客户端
	while(p->next!=NULL)
	{
		//找到下线客户端的前一个节点



		p=p->next;
		sendto(sfd,&msg,sizeof(msg),0,(struct sockaddr *)&cin,sizeof(cin));

	}
}

客户端

#include <my_head.h>

#define SER_IP "192.168.96.132"
#define SER_PORT 8888

typedef struct Msg
{
	char type;
	char name[20];
	char text[128];

}msg_t;
int main(int argc, const char *argv[])
{
	int rfd=socket(AF_INET,SOCK_DGRAM,0);
	if(rfd==-1)
	{
		perror("socket error");
		return -1;
	}
	//填充服务器地址信息结构体
	struct sockaddr_in sin;
	sin.sin_family=  AF_INET;
	sin.sin_port  =  htons(SER_PORT);
	sin.sin_addr.s_addr = inet_addr(SER_IP);

	struct sockaddr_in cin;
	socklen_t socklen_cin=sizeof(cin);

	msg_t msg;
	msg.type='L';

	printf("请输入用户名\n");
	scanf("%s",msg.name);
	msg.name[strlen(msg.name)-1]='\0';
	//给客户端发送用户名
	if(sendto(rfd,&msg,sizeof(msg),0,(struct sockaddr *)&sin,sizeof(sin))==-1)
	{
		perror("sendto error");
		return -1;
	}
	pid_t pid=fork();
	if(pid==0)
	{
		//子进程发消息
		while(1)
		{
			scanf("%s",msg.text);
			getchar();
			if(strcmp(msg.text,"quit")==0)
			{
				msg.type=='Q';
				sendto(rfd,&msg,sizeof(msg),0,(struct sockaddr *)&sin,sizeof(sin));
				wait(NULL);
				exit(EXIT_SUCCESS);
			}
			else
			{
				msg.type='S';
				sendto(rfd,&msg,sizeof(msg),0,(struct sockaddr *)&sin,sizeof(sin));
			}
		}
		kill();   //终止子进程运行
		wait(NULL);

	}
	else if(pid>0)
	{
		//父进程接收服务端消息
		while(1)
		{
			int res=recvfrom(rfd,&msg,sizeof(msg),0,NULL,NULL);
			if(res==-1)
			{
				perror("recvfrom error");
				return -1;
			}
			printf("%s:%s\n",msg.name,msg.text);
		}
		wait(NULL);
	}
	else
	{
		perror("fork error");
		return -1;
	}
	close(cfd);

	return 0;
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值