UDP聊天室

服务器

#include<myhead.h>
 
struct sockaddr_in serveraddr,caddr;
enum type_t//枚举
{
	Login,
	Chat,
	Quit,
};
typedef struct MSG
{
	char type;//L C Q
	char name[32];//
	char text[128];//
}msg_t;
 
typedef struct NODE//链表
{
	struct sockaddr_in caddr;
	struct NODE *next;
}node_t;
 
node_t *create_node(void)//建头节点
{
	node_t *p=(node_t *)malloc(sizeof(node_t));
	if(p==NULL)
	{
		perror("malloc err");
		return NULL;
	}
	p->next=NULL;
	return p;
 
}
void do_login(int ,msg_t ,node_t *,struct sockaddr_in);//登录的函数
void do_chat(int ,msg_t ,node_t *,struct sockaddr_in);//群聊的函数
void do_quit(int ,msg_t ,node_t *,struct sockaddr_in);//退出函数
int main(int argc, char const *argv[])
{
	if(argc !=3)
	{
		printf("Usage:./a.out <port>\n");
		return -1;
	}
	//创建UDP套接字
	int sockfd = socket(AF_INET,SOCK_DGRAM,0);
	if(sockfd<0)
	{
		perror("socket err");
		exit(-1);
	}
	//填充服务器网络信息结构体
	serveraddr.sin_family=AF_INET;
	serveraddr.sin_port=htons(atoi(argv[2]));
 
	serveraddr.sin_addr.s_addr=inet_addr(argv[1]);
	socklen_t len = sizeof(caddr);
	//定义保存客户端网络信息的结构体
	//绑定套接字和服务器网络信息的结构体
	bind(sockfd,(struct sockaddr *)&serveraddr,sizeof(serveraddr));
	printf("bind ok!\n");
	msg_t msg;
	node_t *p=create_node();
	while(1)
	{
		if(recvfrom(sockfd,&msg,sizeof(msg),0,(struct sockaddr *)&caddr,&len)<0)
		{
			perror("recvfrom err");
			return -1;
		}
		if(msg.type==Login)
		{
			strcpy(msg.text,"已上线");
			printf("ip:%s pord:%d name:%s\n",inet_ntoa(caddr.sin_addr),ntohs(caddr.sin_port),msg.name);
			printf("状态:%s\n",msg.text);
			do_login(sockfd,msg,p,caddr);
		}
		else if(msg.type==Chat)
		{
			do_chat(sockfd,msg,p,caddr);    
		}
		else if(msg.type==Quit)
		{
			strcpy(msg.text,"已下线");
			printf("ip:%s pord:%d name:%s\n",inet_ntoa(caddr.sin_addr),ntohs(caddr.sin_port),msg.name);
			printf("状态:%s\n",msg.text);
			do_quit(sockfd,msg,p,caddr);        
		}
	}
	close(sockfd);
	return 0;
}
//登录的函数
//功能:
//1》将新登录的用户转发给所有已经登录的用户(遍历链表发送谁登录的消息)
//2》创建新节点来保存新登录用户的信息,链接到链表尾就可已
void do_login(int sockfd,msg_t msg,node_t *p,struct sockaddr_in caddr)
{
 
	sprintf(msg.text,"%s 已上线",msg.name);
	while(p->next != NULL)
	{
		p= p->next;
		sendto(sockfd,&msg,sizeof(msg),0,(struct sockaddr *)&(p->caddr),sizeof(p->caddr));
		//printf("%s\n",msg.text);
	}
	node_t *new=(node_t *)malloc(sizeof(node_t));
	//初始化
	new->caddr=caddr;
	new->next=NULL;
	//链接到链表尾
	p->next=new;
	return;
}
//群聊的函数
//功能:将客户端发来的聊天内容转发给所有已登录的用户,除了发送聊天内容的用户已外
void do_chat(int sockfd,msg_t msg,node_t *p,struct sockaddr_in caddr)
{
	//遍历链表
	while(p->next != NULL)
	{
		p=p->next;
 
		if(memcmp(&(p->caddr),&caddr,sizeof(caddr)) != 0)
		{
			sendto(sockfd,&msg,sizeof(msg),0,(struct sockaddr *)&(p->caddr),sizeof(p->caddr));
		}
	}
	return;
}
//退出函数
//功能:
//1》将谁退出的消息转发给i所有用户
//2》将链表中保存这个推出的用户信息的节点删除
void do_quit(int sockfd,msg_t msg,node_t *p,struct sockaddr_in caddr)
{
	sprintf(msg.text,"%s 已下线",msg.name);
	while(p->next != NULL)
	{
		if((memcmp(&(p->next->caddr),&caddr,sizeof(caddr)))==0)
		{ 
			node_t *dele=NULL;
			dele = p->next;
			p->next=dele->next;
			free(dele);
			dele=NULL;
		}
		else
		{
			p=p->next;
			sendto(sockfd,&msg,sizeof(msg),0,(struct sockaddr *)&(p->caddr),sizeof(p->caddr));
		}  
	}
	return;
}

客户端

#include <myhead.h>
 
enum type_t
{
    Login,
    Chat,
    Quit,
};
typedef struct 
{
    char type;//L C Q
    char name[32];//
    char text[128];//
}msg_t;
 
int main(int argc, char const *argv[])
{
     if(argc !=3)
    {
        printf("Usage ./a.out <ip> <port>\n");
        return -1;
    }
   
    int sockfd = socket(AF_INET,SOCK_DGRAM,0);
    if(sockfd<0)
    {
        perror("socket err");
        exit(-1);
    }
    struct sockaddr_in serveraddr;
    serveraddr.sin_family=AF_INET;
    serveraddr.sin_port=htons(atoi(argv[2]));
    serveraddr.sin_addr.s_addr=inet_addr(argv[1]);
    socklen_t len = sizeof(serveraddr);
    msg_t msg;
    //先执行登录操作 
    printf("请登录:\n");
    msg.type=Login;
    printf("请输入用户名:");
    fgets(msg.name,32,stdin);
    if(msg.name[strlen(msg.name)-1]=='\n')
       msg.name[strlen(msg.name)-1]='\0';
    //发送登录消息
    if(sendto(sockfd,&msg,sizeof(msg),0,(struct sockaddr *)&serveraddr,len)<0)
       {
         perror("sendto err");
         exit(-1);
       }
    pid_t pid=fork();
     if(pid<0)
    {
        perror("fork err");
        exit(-1);
    }
    else if(pid==0)
    {
        while(1)
        {
            if(recvfrom(sockfd,&msg,sizeof(msg),0,NULL,NULL)<0)
            {
                perror("recvfrom err");
                return -1;
            }
            printf("[%s]:%s\n",msg.name,msg.text);
        } 
    }    
    else 
    {
        while(1)
        {
            fgets(msg.text,sizeof(msg.text),stdin);
            if(msg.text[strlen(msg.text)-1]=='\n')
               msg.text[strlen(msg.text)-1]='\0';
            if(strcmp(msg.text,"quit")==0)
            {
                msg.type=Quit; 
                sendto(sockfd,&msg,sizeof(msg),0,(struct sockaddr *)&serveraddr,len);
                kill(pid,SIGKILL);
                wait(NULL);
                exit(-1);
            }else
        {
            msg.type=Chat;
        }
        //发送消息
        sendto(sockfd,&msg,sizeof(msg),0,(struct sockaddr *)&serveraddr,len);
        }
    }
    close(sockfd);
    return 0;
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值