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;
}

  • 3
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
### 回答1: 为了使用Qt框架实现局域网聊天室,我们可以使用UDP协议进行通信。UDP是一种面向无连接的传输协议,适用于传输不需要高可靠性和有序到达的数据。 首先,我们需要创建一个UDP的Socket,并绑定到一个合适的端口。接下来,我们可以使用Qt提供的信号与槽机制来处理接收到的消息。 为了实现聊天室功能,我们需要至少两个应用实例,一个用作服务器,另一个用作客户端。当客户端启动时,它将向服务器发送一个加入聊天室的请求。 当服务器接收到一个加入请求时,它可以将发送者的IP地址和端口存储在一个列表中,以便之后可以将消息广播给所有的聊天室成员。 当一个客户端发送一条消息时,它将将消息发送给服务器,服务器收到消息后,将消息广播给所有已连接的客户端。客户端接收到广播后,可以将消息显示在聊天窗口中。 需要注意的是,UDP是无连接的协议,因此在实现聊天室时,需要处理丢包和乱序的问题。可以使用一些技术,如序列号、心跳检测等来解决这些问题。 此外,为了提高用户体验,我们还可以在聊天室实现一些额外的功能,如私聊、文件传输等。 总之,通过使用Qt和UDP协议,我们可以很容易地实现一个简单的局域网聊天室。使用UDP协议可以简化通信过程,并提供轻量级的通信方式。不过也要注意到UDP的不可靠性,需要在实现中考虑丢包和乱序问题。 ### 回答2: Qt是一个跨平台的C++应用程序开发框架,可以用于开发各种类型的应用程序,包括局域网聊天室。首先要实现局域网聊天室,需要使用UDP协议进行通信,因为UDP是无连接的、不可靠的传输协议,适合于实时性要求较高的应用。 在Qt中,可以使用QUdpSocket类来实现UDP通信。首先,需要创建一个QUdpSocket对象,并绑定到本地IP和端口上。接下来,可以通过该对象的bind函数将socket绑定到指定的本地IP和端口上。然后,可以使用该对象的readDatagram函数接收其他主机发送过来的消息,并使用writeDatagram函数发送消息给其他主机。 在局域网聊天室中,需要实现多个主机之间的消息传递。可以使用多线程来处理消息接收和发送的操作,以免阻塞主线程。可以创建一个接收线程,通过QUdpSocket来接收其他主机发送的消息,并将接收到的消息发送给主线程进行处理。同时,可以创建一个发送线程,用于向其他主机发送消息。 在主线程中,可以使用Qt的信号和槽机制来处理接收到的消息。当接收线程接收到消息后,可以通过信号将消息传递给主线程,并在主线程中的槽函数中进行处理,例如显示在用户界面上。当用户在界面上输入消息后,可以通过发送线程将消息发送给其他主机。 总结起来,使用Qt的QUdpSocket类可以方便地实现局域网聊天室。通过创建多线程,利用信号和槽机制处理接收和发送的消息,可以实现实时的消息传递。使用UDP协议可以满足聊天室的实时性要求。

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值