UDP-创建群聊

服务器

objectivec 复制代码
#include <stdio.h>
#include <stdlib.h>
#include <sys/socket.h>
#include <sys/types.h>
#include <arpa/inet.h>
#include <string.h>
#include <unistd.h>

#define send_port "8888"
#define send_ip "192.168.1.6"
//存储用户端信息
typedef struct user{
	struct sockaddr_in user;
	struct user* next;
	struct user* prve;
}USER;

//创建链表
USER* creat_link(void){
	USER* head=(USER*)malloc(sizeof(struct user));
	head->next=NULL;
	head->prve=NULL;
	memset(&(head->user),0,sizeof(head->user));
	return head;

}
//新用户上线
void add_link(USER* head,struct sockaddr_in usr){

	USER* uhead=(USER*)malloc(sizeof(USER));
	uhead->next=head->next;
	uhead->prve=head;
	uhead->user=usr;
	head->next=uhead;
	return ;
}

//用户下线
void delete_link(USER* head){
	USER* temp =NULL;
	temp=head->prve;
	temp->next=head->next;
	head->next->prve=temp;
	free(head);

	return ;
}



int main(int argc, const char *argv[])
{
	//创建链表
	USER* head=creat_link();


	int sockfd = socket(AF_INET,SOCK_DGRAM,0);
	if(sockfd<0){
		perror("socket");
		return -1;
	}
	int optval=1;
	int spt=setsockopt(sockfd,SOL_SOCKET,SO_BROADCAST,(void *)&optval,sizeof(optval));
	if(spt<0){
		perror("setsockopt");
		return -1;
	}

	//绑定广播地址
	struct sockaddr_in bro_addr;
	memset(&bro_addr,0,sizeof(bro_addr));
	bro_addr.sin_family=AF_INET;
	bro_addr.sin_port=htons(atoi(send_port));
	bro_addr.sin_addr.s_addr=inet_addr(send_ip);
	memset(bro_addr.sin_zero,0,sizeof(bro_addr.sin_zero));
	int bindflag=bind(sockfd,(struct sockaddr*)&bro_addr,sizeof(bro_addr));
	if(bindflag<0){
		perror("bind");
		return -1;
	}
	//创建子进程
	//int key=0;
	int pfd[2]={0};
	if(pipe(pfd)<0){
		perror("pipe");
		return -1;
	}
	printf("无名管道创建成功\n");
	pid_t pid=fork();
	if(pid>0){  	//父进程
		while(1){
			ssize_t res=0;
			USER* temp;
			res=read(pfd[0],temp,sizeof(temp));
			if(res<0){
				perror("read");
				return -1;
			}
			USER* p=(temp)->next;
			while(p!=NULL){
				printf("%d\n",__LINE__);
				char send_buf[1024];
				memset(send_buf,0,sizeof(send_buf));
				ssize_t res=0;
				res=read(pfd[0],send_buf,sizeof(send_buf));
				if(res<0){
					perror("read");
					return -1;
				}
				int sendflag=sendto(sockfd,send_buf,sizeof(send_buf),0,(struct sockaddr*)&(p->user),sizeof(p->user));
				if(sendflag<0){
					perror("sendto");
					return -1;
				}
			}
		}
	}
	/*子进程
	 * 实现客户端的查询是否有客户端上线
	 * 已上线的客户端,进行数据传输
	 * 判断是否有客户端用户要退出
	 * */
	else if(0==pid){
		while(1){
			char recv_buf[1024];//定义字符串,用于接收数据
			memset(recv_buf,0,sizeof(recv_buf));//将字符串清空
			struct sockaddr_in recv_addr;//定义一个结构体变量,用于接收IP和端口号
			memset(&recv_addr,0,sizeof(recv_addr));//清空结构体
			socklen_t len=sizeof(recv_buf);//计算字符串的大小
			int recvflag=recvfrom(sockfd,recv_buf,sizeof(recv_buf),0,(struct sockaddr *)&recv_addr,&len);//接收数据
			if(recvflag<0)//判断接收数据是否成功
			{
				printf("recvfrom error!\r\n");
				return -4;
			}
			USER* p=head;//创建一个链表节点
			int k=0;
			while(p->next!=NULL){
				p=p->next;
				in_port_t port=p->user.sin_port;
				if(port==recv_addr.sin_port){
					int i=strcmp(recv_buf,"quit");
					if(i==0){
						delete_link(p);
						p=NULL;
						k=1;
						break;
					}
					USER** phead=head;
					if(write(pfd[1],phead,sizeof(phead))<0){
						perror("地址_write");
						return -1;
					}
					if(write(pfd[1],recv_buf,sizeof(recv_buf))<0){
						perror("write");
						return -1;
					}
					printf("IP:%s PORT:%d  data:%s\n",\
							inet_ntoa(recv_addr.sin_addr),ntohs(recv_addr.sin_port),recv_buf);
					k=1;
				}
			}
			if(p->next==NULL&&0==k){
				add_link(p,recv_addr);
				printf("IP:%s   PORT:%d上线\n",\
						inet_ntoa(recv_addr.sin_addr),ntohs(recv_addr.sin_port));
			}
		}

	}
	else{
		perror("fork");
		return -1;
		
	}



	//printf("数据发送完成:%s\n",recv_buf);

	close(sockfd);

	return 0;
}

客户端

objectivec 复制代码
#include <stdio.h>
#include <stdlib.h>
#include <sys/socket.h>
#include <sys/types.h>
#include <arpa/inet.h>
#include <string.h>
#include <unistd.h>

#define send_port "8888"
#define send_ip "192.168.1.6"

int main(int argc, const char *argv[])
{
	int sockfd = socket(AF_INET,SOCK_DGRAM,0);
	if(sockfd<0){
		perror("socket");
		return -1;
	}
	int optval=1;
	int spt=setsockopt(sockfd,SOL_SOCKET,SO_BROADCAST,(void *)&optval,sizeof(optval));
	if(spt<0){
		perror("setsockopt");
		return -1;
	}
	struct sockaddr_in send_addr;
	memset(&send_addr,0,sizeof(send_addr));
	send_addr.sin_family=AF_INET;
	send_addr.sin_port=htons(atoi(send_port));
	send_addr.sin_addr.s_addr=inet_addr(send_ip);
	memset(send_addr.sin_zero,0,sizeof(send_addr));
	char buf[64];
	memset(buf,0,sizeof(buf));
	//fgets(buf,sizeof(buf),stdin);
	//buf[strlen(buf)-1]='\0';
	ssize_t buf_len= sizeof(buf);
	if(sendto(sockfd,buf,buf_len,0,(struct sockaddr*)&send_addr,sizeof(send_addr))<0){
		perror("sendto");
		return -1;
	}
	int pfd[2]={0};
	if(pipe(pfd)<0){
		perror("pipe");
		return-1;
	}
	pid_t pid=fork();
	if(pid>0){
		while(1){
			char buf[64];
			memset(buf,0,sizeof(buf));
			fgets(buf,sizeof(buf),stdin);
			buf[strlen(buf)-1]='\0';
			ssize_t buf_len= sizeof(buf);
			if(sendto(sockfd,buf,buf_len,0,(struct sockaddr*)&send_addr,sizeof(send_addr))<0){
				perror("sendto");
				return -1;
			}
			if(strcmp(buf,"quit")==0){
				if(write(pfd[1],buf,sizeof(buf))<0){
					perror("write");
					return -1;
				}
				printf("退出群聊\n");
				pid_t id=wait(NULL);
				break;
			}
		}

	}
	else if(pid==0){
		while(1){
			ssize_t res=0;
			char bufc[1024];
			res=read(pfd[0],bufc,sizeof(bufc));
			if(res<0){
				perror("read");
				return -1;
			}
			if(strcmp(bufc,"quit")==0){
				exit(0);
			}
			char recv_buf[1024];//定义字符串,用于接收数据
			memset(recv_buf,0,sizeof(recv_buf));//将字符串清空
			struct sockaddr_in recv_addr;//定义一个结构体变量,用于接收IP和端口号
			memset(&recv_addr,0,sizeof(recv_addr));//清空结构体
			socklen_t len=sizeof(recv_buf);//计算字符串的大小
			int recvflag=recvfrom(sockfd,recv_buf,sizeof(recv_buf),0,(struct sockaddr *)&recv_addr,&len);
			if(recvflag<0)//判断接收数据是否成功
			{
				printf("recvfrom error!\r\n");
				return -4;
			}                                                                                            
			printf("IP:%s PORT:%d  data:%s\n",\
					inet_ntoa(recv_addr.sin_addr),ntohs(recv_addr.sin_port),recv_buf);

		}

	}else{
		perror("fork");
		return -1;
	}
	printf("数据发送完成\n");
	close(sockfd);

	return 0;
}
相关推荐
子正27 分钟前
一键编译包含多个独立模块和应用的工程(linux cmake)
linux·运维·cmake
小阳睡不醒28 分钟前
小白成长之路-Linux Shell脚本练习
linux·运维·服务器
dessler1 小时前
代理服务器-LVS的DR模式
linux·运维·云计算
江山如画,佳人北望2 小时前
stm32-c8t6实现语音识别(LD3320)
stm32·单片机·嵌入式硬件
baowxz2 小时前
航芯MCU使用IAR+Jlink调试
单片机·嵌入式硬件
wangxinwei20002 小时前
stm32_LAN8720驱动
stm32·单片机·嵌入式硬件
大叔带刺2 小时前
AUTOSAR实战教程--DoIP_01_配置项解释
单片机·嵌入式硬件
梦星辰.2 小时前
VSCode CUDA C++进行Linux远程开发
linux·c++·vscode
远方16092 小时前
0x-2-Oracle Linux 9上安装JDK配置环境变量
java·linux·oracle
小胖同学~2 小时前
Linux--vsFTP配置篇
stm32·单片机·嵌入式硬件