9.7(UDP局域网多客户端聊天室)

服务器端

c 复制代码
#include<myhead.h>
#define SERIP "192.168.0.132"
#define SERPORT 8888
#define MAX 50
//定义用户结构体
typedef struct{
	struct sockaddr_in addr;
	int flag;
}User;

User users[MAX];//用户列表

void add_user(struct sockaddr_in *client){

	// 检查用户是否已经在列表中
	for (int i = 0; i < MAX; i++) {
		if (users[i].flag == 1 && memcmp(&users[i].addr, client, sizeof(struct sockaddr_in)) == 0) {
			// 用户已经在列表中
			return;
		}
	}
	for(int i=0;i<MAX;i++){
		if(users[i].flag==0){
			users[i].addr = *client;
			users[i].flag = 1;
			break;
		}
	}
}

//向用户转发消息,排除发送者
void transform(char *buff,struct sockaddr_in *send,int oldfd){
	for(int i=0;i<MAX;i++){
		if(users[i].flag!=0){
			if(memcmp(&users[i].addr,send,sizeof(struct sockaddr_in))!=0){
				sendto(oldfd,buff,strlen(buff),0,(struct sockaddr *)&users[i].addr,sizeof(users[i].addr));

			}
		}
	}

}


int main (int argc, const char *argv[])
{


	//定义套接字
	int oldfd = socket(AF_INET,SOCK_DGRAM,0);
	if(oldfd==-1){
		perror("oldfd");
		return -1;
	}

	int kkk=2; 
	if(setsockopt(oldfd,SOL_SOCKET,SO_BROADCAST,&kkk,sizeof(kkk))==-1){ 
		perror("setsockopt"); 
		return -1;
	} 

	//绑定端口
	struct sockaddr_in server = {
		.sin_family = AF_INET,
		.sin_addr.s_addr = inet_addr(SERIP),
		.sin_port = htons(SERPORT)
	};
	int server_len = sizeof(server);
	if(bind(oldfd,(struct sockaddr *)&server,server_len)==-1){
		perror("bind");
		return -1;
	}

	printf("UDP聊天服务器启动,端口号为:%d\n",SERPORT);

	//IO多路复用
	struct pollfd fds[1];
	fds[0].fd = oldfd;
	fds[0].events = POLLIN;

	char buff[1024];

	struct sockaddr_in client;
	int client_len = sizeof(client);
	while(1){


		int poll_count = poll(fds,1,-1);

		if(fds[0].revents == POLLIN){
			memset(buff,0,sizeof(buff));
			int len = recvfrom(oldfd,buff,sizeof(buff),0,(struct sockaddr *)&client,&client_len);

			if(len == 0){
				perror("recvfrom");
				return -1;
			}

			buff[len] = '\0';
			printf("接收到来自%s:%d的消息%s\n",inet_ntoa(client.sin_addr),ntohs(client.sin_port),buff);


			//添加用户到列表
			add_user(&client);

			//转发给其他用户
			transform(buff,&client,oldfd);
		}
	}

	close(oldfd);

	return 0;
}

客户端

c 复制代码
#include<myhead.h>
#define SERIP "192.168.0.132"
#define SERPORT 8888
#define MAX 50

int main (int argc, const char *argv[])
{

	//创建套接字
	int oldfd = socket(AF_INET,SOCK_DGRAM,0);
	if(oldfd==-1){
		perror("oldfd");
		return -1;
	}
	

	struct sockaddr_in server={
		.sin_family = AF_INET,
		.sin_port = htons(SERPORT),
		.sin_addr.s_addr = inet_addr(SERIP)
	};

	struct sockaddr_in client;
	int client_len = sizeof(client);
	int server_len = sizeof(server);

	printf("UDP客户端启动,连接到服务器%s:%d\n",inet_ntoa(server.sin_addr),ntohs(server.sin_port));
	char message[20] = "UDP客户端连接";
	sendto(oldfd,message,strlen(message),0,(struct sockaddr *)&server,server_len);
	
	struct pollfd fds[2];
	fds[0].fd = oldfd;
	fds[0].events = POLLIN;
	fds[1].fd = 0;
	fds[1].events = POLLIN;


	char buff[1024];
	while(1){
		int poll_count = poll(fds,2,5000);

		if(poll_count == -1){
			perror("poll_count");
			return -1;
		}
		if(poll_count == 0){
			continue;
		}

		if(fds[0].revents == POLLIN){
			memset(buff,0,sizeof(buff));
			int len = recvfrom(oldfd,buff,sizeof(buff),0,(struct sockaddr *)&server,&server_len);
			if(len<0){
				perror("recvfrom");
				continue;
			}
			buff[len]='\0';
			printf("服务器发来消息:%s\n",buff);
		}

		if(fds[1].revents==POLLIN){
			memset(buff,0,sizeof(buff));
			if(fgets(buff,sizeof(buff),stdin)!=NULL){
				buff[strlen(buff)-1]='\0';
				sendto(oldfd,buff,strlen(buff),0,(struct sockaddr *)&server,server_len);
			}
		}
	
	}

	close(oldfd);
	return 0;
}

效果:

使用UDP以及I/O多路复用,实现了聊天内容的转发,以及在各个终端窗口的实时显示

不足

无法识别用户并再转发时加上用户的信息

相关推荐
wxh_无香花自开20 分钟前
Linux 笔记:rpm命令
linux·运维·笔记·rpm
张童瑶27 分钟前
Linux SSH配置密钥文件及免密登录
linux·运维·ssh
布茹 ei ai27 分钟前
QtWeatherApp - 简单天气预报软件(C++ Qt6)(附源码)
开发语言·c++·qt·开源·开源项目·天气预报
tianyuanwo28 分钟前
Linux密码加密技术深度解析:从盐值到加密算法的完整指南
linux·密码加密
Wpa.wk28 分钟前
自动化测试 - 文件上传 和 弹窗处理
开发语言·javascript·自动化测试·经验分享·爬虫·python·selenium
LinHenrY122730 分钟前
初识C语言(编译和链接)
c语言·开发语言·蓝桥杯
_OP_CHEN30 分钟前
【Python基础】(二)从 0 到 1 入门 Python 语法基础:从表达式到运算符的全面指南
开发语言·python
roman_日积跬步-终至千里30 分钟前
【Starrocks】StarRocks 排错:`Invalid method name: ‘heartbeat‘`(BE 心跳端口/协议错误)
服务器·网络·php
l1t31 分钟前
利用小米mimo为精确覆盖矩形问题C程序添加打乱函数求出更大的解
c语言·开发语言·javascript·人工智能·算法
我命由我1234539 分钟前
Python Flask 开发:在 Flask 中返回字符串时,浏览器将其作为 HTML 解析
服务器·开发语言·后端·python·flask·html·学习方法