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;
}
相关推荐
ye1501277745526 分钟前
DC6v-36V转3.2V1A恒流驱动芯片WT7017
单片机·嵌入式硬件·其他
炫友呀7 小时前
Centos 更新/修改宝塔版本
linux·运维·centos
scilwb10 小时前
RoboCon考核题——scilwb
单片机
花小璇学linux11 小时前
imx6ull-驱动开发篇24——Linux 中断API函数
linux·驱动开发·嵌入式软件
林开落L11 小时前
库制作与原理(下)
linux·开发语言·centos·库制作与原理
点灯小铭11 小时前
基于STM32单片机智能RFID刷卡汽车位锁桩设计
stm32·单片机·汽车·毕业设计·课程设计
wxy31911 小时前
嵌入式LINUX——————TCP并发服务器
java·linux·网络
Castamere12 小时前
配置 Linux 终端 (zsh)
linux
bai54593613 小时前
STM32 软件I2C读写MPU6050
stm32·单片机·嵌入式硬件
小韩博13 小时前
metasploit 框架安装更新遇到无法下载问题如何解决
linux·网络安全·公钥·下载失败