简单的聊天室(UDP)

简单的聊天室(UDP)
UDP编程步骤
1--创建数据报套接字 socket() : SOCK_DGRAM.
2--绑定地址信息.  bind() .  struct sockaddr_in.
3--recvfrom() 与 sendto()   适用于udp协议
4--关闭套接字close().
使用的f发送接收函数
ssize_t recvfrom(int socket, void *buffer, size_t length,
          int flags, struct sockaddr *address,
          socklen_t *address_len);
{
	socket:          套接字;
	buffer: 存放接受数据空间首地址.
	length:          接受数据的字节大小
	flags:           设置数据接受的模式.通常为0 缺省模式.
	address: 存放客户端的地址信息. 
					  如果不需要了解客户端信息则为NULL 
	address_len: 客户端的地址信息长度(传递的是地址)
}
ssize_t sendto(int socket, const void *message, size_t length,
          int flags, const struct sockaddr *dest_addr,
          socklen_t dest_len);
服务器
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <errno.h>

#include <sys/types.h>
#include <sys/socket.h>
#include <arpa/inet.h>
#include <netinet/in.h>
#include <signal.h>
#define N 32
#define M 256

#define L 0x1//登录
#define C 0x2//聊天
#define Q 0x3//退出
typedef struct{
	int type;//消息类型
	char name[N];
	char text[M];//消息正文
}MSG;
#define LEN sizeof(MSG)

typedef struct node{   //网络信息节点
	struct sockaddr_in addr;
	struct node *next;
}linknode,*linklist;

#define err_log(log)\
	do{\
	perror(log);\
	exit(1);\
	}while(0)

typedef struct sockaddr_in SA;
linklist create_list(void);
void do_login(int sockfd,struct sockaddr_in clientaddr,linklist H,MSG *msg);
void do_chat(int sockfd,struct sockaddr_in clientaddr,linklist H,MSG *msg);
void do_quit(int sockfd,struct sockaddr_in clientaddr,linklist H,MSG *msg);
int main(int argc, const char *argv[])
{
	
	int sockfd;
	struct sockaddr_in serveraddr,clientaddr;
	socklen_t len=sizeof(SA);
	bzero(&serveraddr,len);
	MSG msg;
	pid_t pid;
	linklist H;

	if((sockfd=socket(AF_INET,SOCK_DGRAM,0))<0)//创建数据报套接字
	{
		err_log("fail to socket:");
	}
    //指定的网络信息
	serveraddr.sin_family=AF_INET;
	serveraddr.sin_port=htons(6666);
	serveraddr.sin_addr.s_addr=inet_addr("0.0.0.0");
    if(bind(sockfd,(SA*)&serveraddr,len)<0)
	{
		err_log("fail to bind:");
	}

	pid=fork();
	if(pid<0)
	{
		err_log("fail to fork:");
	}
	else if(pid==0)//发送系统信息
	{
		   bzero(&msg,LEN);
		   strcpy(msg.name,"server");
		   msg.type=C;
		   while(1)
		   {
			   fgets(msg.text,M,stdin);
			   msg.text[strlen(msg.text)-1]='\0';
			   sendto(sockfd,&msg,LEN,0,(SA*)&serveraddr,len);
		   }
	}
	else //群发信息
	{
			while(1)
			{
				H=create_list();
				while(1)
				{
					recvfrom(sockfd,&msg,LEN,0,(SA*)&clientaddr,&len);
					switch(msg.type)
					{
						case L:
							do_login(sockfd,clientaddr,H,&msg);
							break;
						case C:
							do_chat(sockfd,clientaddr,H,&msg);
							break;
						case Q:
							do_quit(sockfd,clientaddr,H,&msg);
							break;
						default:
							puts("error!");
							break;
					}
				}
			}
	}



	return 0;
}
linklist create_list(void)//创建链表
{
	linklist H;
	if((H=(linklist)malloc(sizeof(linknode)))==NULL)
	{
		perror("fail to malloc:");
		return NULL;
	}
	H->next=NULL;
	return H;
}
void do_login(int sockfd,struct sockaddr_in clientaddr,linklist H,MSG *msg)//登录处理
{
	linklist p=H->next;
	linklist q;
	sprintf(msg->text,"%s login.....",msg->name);
	socklen_t len=sizeof(SA);
	 while(p)//群发登录信息
	 {
			sendto(sockfd,msg,LEN,0,(SA*)&p->addr,len);//发送
			p=p->next;
	 }
	 if((q=(linklist)malloc(sizeof(linknode)))==NULL)
	 {
		perror("fail to malloc:");
		return;
	 }
	q->addr=clientaddr;
	 //头插
	q->next=H->next;
	H->next=q;

	puts(msg->text);
}
void do_chat(int sockfd,struct sockaddr_in clientaddr,linklist H,MSG *msg)//聊天处理
{
	linklist p=H->next;
	char buf[M]={0};
	sprintf(buf,"%s said:%s",msg->name,msg->text);
	strcpy(msg->text,buf);
	socklen_t len=sizeof(SA);
	while(p)
	{
		if(memcmp(&clientaddr,&p->addr,sizeof(clientaddr))!=0)//不给自己发
		{
				sendto(sockfd,msg,LEN,0,(SA*)&p->addr,len);
		}
		p=p->next;
	}
	puts(msg->text);
}
void do_quit(int sockfd,struct sockaddr_in clientaddr,linklist H,MSG *msg)//退出处理
{
	linklist p=H;
	linklist q;
	sprintf(msg->text,"%s offline..........",msg->name);
	socklen_t len=sizeof(SA);
	while(p->next)
	{
		 if(memcmp(&clientaddr,&p->next->addr,sizeof(clientaddr))==0)//删除节点操作
		 {
				q=p->next;
				p->next=q->next;
				free(q);
				q=NULL;
		 }
		 else
		 {
			 sendto(sockfd,msg,LEN,0,(SA*)&p->next->addr,len);
			 p=p->next;
		 }
	}
	puts(msg->text);
}
客户端
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <errno.h>

#include <sys/types.h>
#include <sys/socket.h>
#include <arpa/inet.h>
#include <netinet/in.h>
#include <signal.h>
#define N 32
#define M 256

#define L 0x1//登录
#define C 0x2//聊天
#define Q 0x3//退出
typedef struct{
	int type;//消息类型
	char name[N];
	char text[M];//消息正文
}MSG;
#define LEN sizeof(MSG)
#define err_log(log)\
	do{\
	perror(log);\
	exit(1);\
	}while(0)
typedef struct sockaddr SA;
int main(int argc, const char *argv[])
{
	
	int sockfd;
	struct sockaddr_in serveraddr;
	socklen_t len=sizeof(SA);
	bzero(&serveraddr,len);
	MSG msg;
	pid_t pid;
	if(argc!=3)
	{
		fprintf(stderr,"user:%s ip port",argv[0]);
		return -1;
    }

	if((sockfd=socket(AF_INET,SOCK_DGRAM,0))<0)//创建数据报套接字
	{
		err_log("fail to socket:");
	}
    //指定服务器的网络信息
	serveraddr.sin_family=AF_INET;
	serveraddr.sin_port=htons(atoi(argv[2]));
	serveraddr.sin_addr.s_addr=inet_addr(argv[1]);

	puts("====================client login=================");
	msg.type=L;
	puts("input name>>>");
	fgets(msg.name,N,stdin);
	msg.name[strlen(msg.name)-1]='\0';
	sendto(sockfd,&msg,LEN,0,(SA*)&serveraddr,len);//发送登录信息给服务器

	pid=fork();
	if(pid<0)
	{
		err_log("fail to fork:");
	}
	else if(pid==0)//子进程发送信息
	{
			while(1)
			{
				fgets(msg.text,M,stdin);
				msg.text[strlen(msg.text)-1]='\0';
				if(strncmp(msg.text,"quit",4)==0)//退出
				{
						msg.type=Q;
						sendto(sockfd,&msg,LEN,0,(SA*)&serveraddr,len);
						close(sockfd);
						kill(getppid(),SIGKILL);//杀死父亲
						exit(0);//自杀

				}
				else//聊天
				{
					msg.type=C;
					sendto(sockfd,&msg,LEN,0,(SA*)&serveraddr,len);
				}
			}
	}
	else //父进程接受信息
	{
			while(1)
			{
				recvfrom(sockfd,&msg,LEN,0,(SA*)&serveraddr,&len);
				printf("%s\n",msg.text);
			}
	}



	return 0;
}

  • 1
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
### 回答1: QT局域网聊天室UDP是一种使用QT编程语言开发的局域网聊天室,其通信协议采用UDP协议。 为了实现局域网聊天室的功能,首先需要建立一个服务器和多个客户端之间的通信连接。在QT中,可以使用QUdpSocket类实现UDP的网络通信功能。服务器端首先需要创建一个QUdpSocket对象来监听指定端口,以便接收来自客户端的消息。然后,服务器需要使用bind函数将QUdpSocket对象绑定到一个指定的IP地址和端口号上。 客户端在连接服务器之前,需要先创建一个QUdpSocket对象用于发送和接收消息。客户端可以使用writeDatagram函数将消息发送给服务器端,并使用bind函数将QUdpSocket对象绑定到一个指定的端口号上,以便接收来自服务器端的回复消息。 服务器端在接收到客户端发来的消息后,可以使用readDatagram函数获取消息内容,并在回复消息时使用writeDatagram函数将回复信息发送给客户端。 在QT局域网聊天室UDP中,可以通过显示聊天内容的GUI界面来实现用户之间的实时聊天。用户可以通过输入框输入自己要发送的消息,点击发送按钮后,消息将通过 UDP 协议发送给服务器端,然后服务器转发给其他在线用户。同时,服务器端接收其他用户的消息并转发给当前用户,用户可以在GUI界面看到其他用户的消息内容。 总之,QT局域网聊天室UDP通过使用UDP协议和QT编程语言的特性,实现了简单的局域网聊天功能。用户可以在局域网内实时交流信息,具有便捷、高效的特点。 ### 回答2: QT局域网聊天室是一种基于User Datagram Protocol(UDP)的网络聊天应用程序。UDP是一种无连接的协议,它带有较少的开销,使其成为实现快速通信的理想选择。 QT局域网聊天室通过创建一个UDP服务器来提供聊天服务。在局域网中的每台计算机上都可以运行一个客户端应用程序,与服务器进行通信。客户端应用程序可以发送和接收消息,实现用户之间的即时聊天。 在QT局域网聊天室中,用户可以输入要发送的消息,并且可以选择向特定的用户发送消息,也可以发送给所有在线用户。使用UDP协议的优点之一是可以轻松地广播消息给所有用户,提高了用户之间信息交流的效率。 UDP协议的主要特点之一是它的开销较低,并且不保证消息的可靠性。这意味着在传输过程中,消息可能会丢失或顺序混乱。但是,对于局域网聊天室这种要求快速通信的应用程序来说,这个问题并不重要。即使消息丢失或顺序不正确,用户还是能获取大部分信息,很少会对用户体验产生重大影响。 总结来说,QT局域网聊天室使用UDP协议提供了一种快速和高效的局域网通信方式。用户可以通过发送和接收消息进行实时聊天,并且可以广播给所有用户或特定用户。尽管UDP不保证消息的可靠性,但在这种应用程序中通常不会对用户造成重大影响。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值