UDP 聊天室实现 经典错误

【Linux网络编程】基于UDP实现多人聊天室 基于UDP实现的多人聊天室,内附详细的服务器和客户端的思路步骤和代码实现。以及个个模块的实现。最后附上源代码给大家借鉴参考,希望对大家有所帮助。 代码中可能有许多不规范的地方,逻辑可能并不严谨,还请各位大佬不吝赐教。 整体项目并不复杂,只需要想清楚service和client分别需要做什么事。画好流程图,就会很清晰的将思路缕顺。从而只需要模块化的完成相应代码即可。 阅读详情
//服务器端
#include "Header.h"
typedef struct
{
	char name[10];
	SA_IN	 address;
}USER;
//XXX :用户链表
typedef struct Hnode_list
{
	USER data;
	struct Hnode_list *next;
}Hlink,*plink;

int  memoryError(plink  p) ;
int  creatUserList(plink head);
int findUser(plink  head,char name[10]);
int delUser(plink  head,char name[10]);
int getAllUser(plink const head);
int addUser(plink head,USER data);
//XXX :用户链表

void ProcessLogin(char* command,SA_IN rec_addr);
void ProcessChat(char* command);

plink head;

int main(void)
{
	char buf[BUFFERSIZE];
	SA_IN	 address, rec_addr;
	int socket_fd;
	socklen_t length;
	head=malloc(sizeof(Hlink));//用户列表头
	creatUserList(head);	//创建列表

	if((socket_fd = socket(AF_INET,SOCK_DGRAM,0)) == -1)
	{
		perror("套接字创建失败");
		exit(-1);
	}

	memset(&address,0,sizeof(address));
	address.sin_family = AF_INET;
	address.sin_addr.s_addr = inet_addr("127.0.0.1");
	address.sin_port = htons(8000);

	if(bind(socket_fd,(SA *)&address,sizeof(address)) == -1)
	{
		perror("套接字绑定失败");
		exit(-1);
	}

	int i=0;
	length = sizeof(rec_addr);
	while(1)
	{
		printf("==%d==\n",i);
		if(recvfrom(socket_fd,buf,sizeof(buf),0,(SA *)&rec_addr,&length) == -1)
		{
			perror("接收消息失败");
		}
		printf("%hu\n",ntohs(rec_addr.sin_port));
		switch(buf[0])
		{
			case 'L':
			ProcessLogin(buf,rec_addr);
			break;
			case 'C':
			ProcessChat(buf);
			break;
			case 'Q':break;
			default : printf("ERROR");break;
		}
		i++;
	}
	close(socket_fd);
}


void ProcessLogin(char* command,SA_IN rec_addr)
{

	int socket_fd;
	char name[10];
	char ip[32];
	char buf[BUFFERSIZE];
	USER user;

	strcpy(name,command+1);
	strcpy(ip,inet_ntoa(rec_addr.sin_addr));

	if((socket_fd = socket(AF_INET,SOCK_DGRAM,0)) == -1)
	{
		perror("套接字创建失败");
		exit(-1);
	}
	if(findUser(head,name)==-1)
	{
		strcpy(user.name,name);
		user.address=rec_addr;
		addUser(head,user);
		buf[0]='Y';
		if(sendto(socket_fd,buf,sizeof(buf),0,(SA *)&rec_addr,sizeof(rec_addr))==-1)
		{
			perror("登录失败");
		}
	}
	else
	{
		buf[0]='N';
		if(sendto(socket_fd,buf,sizeof(buf),0,(SA *)&rec_addr,sizeof(rec_addr))==-1)
		{
			perror("登录失败");
		}
	}

	close(socket_fd);

}


void ProcessChat(char* command)
{

	int socket_fd;
	char buf[BUFFERSIZE];
	SA_IN 	address;

	if((socket_fd = socket(AF_INET,SOCK_DGRAM,0)) == -1)
	{
		perror("套接字创建失败");
		exit(-1);
	}


	plink p=head->next;
	while(p!=NULL)
	{
		address=(p->data).address;
		sprintf(buf,"%s\n",command+1);
//		if(strncmp(buf,(p->data).name,strlen((p->data).name))==0)   //屏蔽属于自己的消息
//		continue;
		if(sendto(socket_fd,buf,sizeof(buf),0,(SA *)&address,sizeof(address))<0)
		{
			perror("消息发送失败");
		}
		printf("%s:%hu\n",buf,ntohs(address.sin_port));
		p=p->next;
	}

	close(socket_fd);
}


//XXX:使用带头结点的单向链表   存放用户信息

int  memoryError(plink  p)  //判断内存是否申请成功
{
	if(p==NULL)
	{
	  printf("MEMORY ERROR!");
	  return 1;
	 }
	 return 0;
}

int  creatUserList(plink head)
{
	if(memoryError(head))
		return -1;
	head->next=NULL;
}


int addUser(plink head,USER data)  //始终在表头插入
{
	plink new_create=malloc(sizeof(Hlink));
	if(memoryError(new_create))
		return -1;

	new_create->data=data;
	new_create->next=head->next;
	head->next=new_create;
}

int getAllUser(plink const head)
{
	plink p=head->next;

	while(p!=NULL)
	{
		printf("%s:%s:%hu\n",(p->data).name,inet_ntoa((p->data).address.sin_addr)
		,ntohs((p->data).address.sin_port));
		p=p->next;
	}
}

int delUser(plink  head,char name[10])
{
	plink q=head;
	plink p=head->next;

	while(p!=NULL)
	{
		if(strcmp((p->data).name,name)==0)
		break;
		q=p;
		p=p->next;
	}
	if(p==NULL)
	{
		printf("删除用户失败\n");
		return -1;
	}
	q->next=p->next;
	free(p);
	p=NULL;
}

int findUser(plink  head,char name[10])
{
	plink p=head->next;
	while(p!=NULL)
	{
		if(strcmp((p->data).name,name)==0)
		return 0;
		p=p->next;
	}
	if(p==NULL)
	return -1;
}

//XXX:使用带头结点的单向链表   存放用户信息



//客户端

#include "Header.h"

void dispMessage(int signo);
void killAll(int signo);
char* ProcessLogin(SA_IN serv_addr);

pid_t pid;

int main(void)
{
	signal(SIGUSR1,dispMessage);
	signal(SIGINT,killAll);
	int socket_fd;
	char buf[BUFFERSIZE];
	char name[10];
	SA_IN serv_addr;
	//XXX:服务器配置信息
	memset(&serv_addr,0,sizeof(serv_addr));
	serv_addr.sin_family = AF_INET;
	serv_addr.sin_addr.s_addr = inet_addr("127.0.0.1");
	serv_addr.sin_port = htons(8000);
	//XXX

	strcpy(name,ProcessLogin(serv_addr));
	if((socket_fd = socket(AF_INET,SOCK_DGRAM,0)) == -1)
	{
		perror("套接字创建失败");
		exit(-1);
	}

	if((pid=fork())==-1)
	{
		perror("子进程创建失败");
		return -1;
	}


	if(pid==0)//子进程
	{
		sprintf(buf,"C%s上线了",name); //sendto在此处相当于第一次放送,这跟tcp connect 差不多,会自动分配ip端口号、、错误根源
		if(sendto(socket_fd,buf,sizeof(buf),0,(SA *)&serv_addr,sizeof(serv_addr)) < 0)
		{
			perror("发送失败");
		}
		while(1)
		{
			pause();
			if(recvfrom(socket_fd,buf,sizeof(buf),0,NULL,NULL)==-1)
			{
				perror("接收消息失败");
			}
			printf("[收到消息]%s\n",buf);
		}
	}
	char buf_temp[BUFFERSIZE];
	while(1)//父进程
	{
		printf("<请输入>");
		scanf("%s", buf_temp);
		sprintf(buf,"C%s说:%s",name,buf_temp);
		if(sendto(socket_fd,buf,sizeof(buf),0,(SA *)&serv_addr,sizeof(serv_addr)) < 0)
		{
			perror("发送失败");
		}
		kill(pid,SIGUSR1);
	}
}

//////////////////////////////////////////////Siganl//////////////////////////////////////////////
void killAll(int signo)
{
	printf("\n%d进程结束\n",getpid());
	exit(-1);
}

void dispMessage(int signo)
{
	;
}
//////////////////////////////////////////////Siganl//////////////////////////////////////////////

char* ProcessLogin(SA_IN serv_addr)
{
	int socket_fd;
	char buf[BUFFERSIZE];
	static char name[10];
	if((socket_fd = socket(AF_INET,SOCK_DGRAM,0)) == -1)
	{
		perror("套接字创建失败");
		exit(-1);
	}
	while(1)
	{
	printf("请输入用户名:");
	buf[0]='L';
	scanf("%s",buf+1);
	strcpy(name,buf+1);
	if(sendto(socket_fd,buf,sizeof(buf),0,(SA *)&serv_addr,sizeof(serv_addr)) < 0)
		{
			perror("登录失败");
		}
	recvfrom(socket_fd,buf,sizeof(buf),0,NULL,NULL);
	if(buf[0]=='N')
	{
		printf("该用户名已被使用,请重新输入用户名\n");
	}
	else if(buf[0]=='Y')
	{
		printf("登录成功\n");
		close(socket_fd);
		return name;
		break;
	}
	}
	//printf("==END===\n");

}

//错误原因
yang@ubuntu:~/Day_33/ChartRoom$ ./Server
==0==
43490//登陆端口号
==1==
42934//子进程接受的端口号,不匹配

liu上线了
:43490
==2==
42934
liu说:sdasda
:43490
==3==
42934
liu说:sadasda
:43490
==4==
42934
liu说:adasdas
:4

python网络编程实验二 基于UDP的聊天室程序 实验内容 编写基于UDP的聊天室程序,实现多人聊天功能。自己设计应用协议,要求实现以下功能: 用户注册 用户登录 公聊 私聊 服务器端源码 #!/usr/bin/env python import socket #创建网络连接 def main(): server = socket.socket(socket.AF_INET,socket.SOCK_DGRAM)#创建UDP套接字 ... 阅读详情

相关推荐

UDP网络聊天室

在引用中提到了利用fork来实现简单的并发服务器,这是因为fork可以创建一个与父进程一样的子进程,从而实现并发处理客户端请求。使用协程也可以实现并发,协程是一种轻量级的线程,可以在同一个线程中实现并发执行多个任务。使用线程可以实现并发,线程是轻量级的执行单元,可以在同一个进程中并发执行多个任务。使用进程池也可以实现并发,进程池是一组预先创建好的进程,可以重复使用来处理多个任务。所以,并发不仅仅是通过fork来实现,还可以使用线程、进程池、协程等方式来实现。这条语句,因为会跳过被删除结点的后一个结点。

weixin_45192798的博客 465

jmeter-Failed to create UDP port(UDP端口创建失败)

出现该问题,就是jmeter的slave进程监听端口被占用,导致不能使用该端口 修改master机器的jmeter.property文件,该配置文件在jmeter的bin目录下,默认配置只开放了10个端口范围给监听使用,只需要修改即可 我这里改成30个,从4445到4475的端口都允许jmeter使用 jmeterengine.nongui.port=4445 jmeterengine.nongui.maxport=4475 ...

qq_40308101的博客 4525

Linux环境下的UDP聊天室实现

用户数据报协议(UDP)是一种简单但无连接的网络传输层协议,它在IP协议基础上增加了端口信息,用于识别源和目标应用程序。UDP不像TCP那样提供完整的连接、排序和可靠性保证,而是以一种最小的开销提供一种快速、不可靠的服务,适用于对实时性要求高但可以容忍一定数据丢失的应用场景,如视频会议、在线游戏、DNS查询等。套接字(Socket)是网络通信的基石,它提供了一种机制,使得运行在不同机器上的应用程序能够进行数据交换。套接字是一种特殊的系统调用接口,允许程序通过网络与其他机器上的程序通信。

weixin_42350014的博客 1018

UDP常见问题

UDP首部 (1)源端口号:在需要对方回信时选用,不需要时可全用0 (2)目的端口号:在终点交付时使用 (3)长度:UDP用户数据报的长度,最小值是8 (4)检验和:检测UDP用户数据报在传输中是否有错,有错就丢弃 为什么UDP不可靠? 因为UDP没有保证可靠传输的机制。 (1)不保证消息交付:不对已发生的数据进行确认,也没有超时重传机制 (2)不保证交付顺序:UDP首部不含序号字段,所以报文段的接收可能会失序。 (3)不跟踪连接状态: UDP是无连接协议,不建立连接或重启状态机 (4)不需要拥塞.

baldist的博客 2221

实现基于UDP协议的多人聊天室项目

多路复用技术是一种允许单一网络连接同时传输多组数据的技术,这对于构建像聊天室这样的应用至关重要。在TCP环境中,最常见的多路复用实现是通过选择I/O模型来完成的,例如select、poll和epoll。然而,UDP作为一个无连接的协议,其本身并不提供多路复用的支持。因此,实现UDP多路复用通常需要借助于操作系统提供的工具和接口。

weixin_31749299的博客 735

UDP与MFC实现聊天室完整示例

本文还有配套的精品资源,点击获取 简介:本示例展示了如何利用UDP协议和MFC库来创建一个简单但功能完整的聊天室应用程序。UDP作为无连接的协议,提供实时性高的数据传输,适合如聊天室这样的应用。MFC的类库简化了Windows应用程序的开发流程,特别是GUI应用程序。示例中详细介绍了UDP套接字编程、服务端和客户端实现、多线程处理、消息广播、数据格式化、错误处理、控件与事件...

weixin_36288992的博客 1499

【Linux网络】基于UDP的Socket编程,实现简单聊天室

本文介绍了基于UDP协议实现的简单聊天室程序。客户端通过sendto发送消息,recvfrom接收消息,并使用多线程实现并行收发。服务器端通过recvfrom接收消息,使用vector维护在线用户列表,并通过线程池将消息转发给所有在线用户。主要实现了登录识别、消息转发和退出处理功能,其中首次发送消息视为登录,"QUIT"消息触发退出。文章详细阐述了客户端和服务器的实现思路,并提供了关键代码模块,包括UDP套接字创建、消息收发、在线用户管理以及线程池优化等内容。最后还对IP地址和端口号转换

记录学习与成长 5083

C++网络编程:UDP聊天室的构建与实践

C++网络编程可以通过多种接口实现,其中最为广泛使用的是POSIX socket标准和Windows平台特有的Winsock库。多路复用技术是一种I/O模型,允许单个线程监视多个文件描述符,当某个文件描述符就绪(例如,读操作可以无阻塞地进行)时,能够通知程序进行相应的读写操作。在UDP聊天室应用中,多路复用技术尤为重要,因为它可以有效地处理多个客户端的并发连接和数据交换。select。

weixin_35189483的博客 669

手把手实现UDP多人聊天室

本文介绍了一个基于UDP协议的多人聊天室实现方案。通过UDP的无连接特性实现低延迟通信,服务器采用单向链表管理用户信息,支持用户加入/退出通知、消息转发和用户名重复校验三大核心功能。文章详细讲解了服务器端和客户端的核心设计,包括数据结构、多线程处理以及常见问题排查方法(如消息转发失败问题)。最后提供了完整的源码实现和运行步骤,适合网络编程初学者参考学习。该方案在Linux环境下开发,使用C语言实现,通过多线程解决客户端同时收发消息的问题,并包含异常处理机制确保程序稳定运行。

2301_81150760的博客 2256

TCP与UDP混合协议聊天室设计与实现

网络通信是现代社会信息交换的核心,涉及从日常的网页浏览到复杂的多用户在线游戏。在这些通信活动中,传输层协议扮演着至关重要的角色。本章从网络通信的基本概念入手,解释数据在不同计算机间传递所需遵循的规则和方法,进而深入讨论TCP(传输控制协议)和UDP(用户数据报协议)的特性以及它们在聊天室等应用中扮演的基础角色。用户数据报协议(UDP)是一种面向无连接的网络协议,它允许数据报在没有预先建立连接的情况下通过网络发送给目标主机。

weixin_29781865的博客 465

SRAM ECC原理与应用:从汉明码到高可靠嵌入式系统设计

在嵌入式系统与高可靠性计算领域,内存数据完整性是系统稳定运行的基石。软错误(Soft Error)由宇宙射线或芯片内部粒子引发,可能导致存储单元发生位翻转,进而引发程序跑飞或数据损坏。为应对这一物理层挑战,错误校验与纠正(ECC)技术应运而生,其核心原理基于扩展汉明码,通过增加校验位实现单错误纠正、双错误检测(SECDED)能力。这项技术通过硬件透明纠错,在提升系统可靠性的同时,几乎不影响访问性能。在汽车电子、工业控制及航空航天等对安全性要求极高的场景中,ECC已成为保障长期稳定运行的关键硬件机制。本文聚焦

weixin_28728265的博客 529

UDP聊天室,TCP服务站【线程池实现】

今天我们所写的TCP代码仍然是有bug的,因为没有处理数据边界。

weixin_73870552的博客 1075

数据分析——员工离职预测

员工离职预测一. 题目描述二. 数据说明三. 步骤实现1.导入并查看2.数据探索性分析3.数据处理4.模型分析5.结果分析(1) 可视化的结果分析(2)特征选择结果分析(3)多模型交叉验证结果分析 一. 题目描述 员工是否准备离职是困扰用人单位的问题,其关系到单位业务的开展及新人员的招聘,及时的分析出有离职倾向的员工成为关键的因素。数据主要包括影响员工离职的各种因素(工资、出差、工作环境满意度、工作投入度、是否加班、是否升职、工资提升比例等)以及员工是否已经离职的对应记录。 二. 数据说明 数据分为训练数据

weixin_43925467的博客 1万+

MFC中基于TCP/UDP协议的网络聊天室(ODBC链接MySQL、基于对话框、简易网络聊天室、TCP/UDP协议)

MFC中基于TCP/UDP协议的网络聊天室(MySQL、基于对话框、简易网络对话框、TCP/UDP协议)

EQ_cyc的博客 3011

基于Simulink的超级电容快速响应特性建模与仿真

本文介绍了基于Simulink的超级电容快速响应特性建模与仿真方法。主要内容包括:超级电容的工作原理、一阶RC等效电路模型及其动态电压方程;通过Simulink搭建超级电容模型的两种方法(Simscape Electrical推荐方案和基础模块透明教学方案);仿真100A×100ms放电脉冲下的电压响应特性,并与锂电池进行动态对比;分析超级电容在混合储能系统中的功率分配优势。文章还提供了工程实践要点和扩展方向,如电压均衡、温度影响评估以及与DC-DC变换器集成等。通过建模实践,验证了超级电容在毫秒级响应、高

xiaoheshang_123的博客 98

【新能源汽车测试工程师必看!DBC文件50条实战技巧,看懂这篇直接封神】

如果你是新能源汽车研发/测试工程师,还在为信号解析错误、报文找不到、DBC看不懂、实车故障复现不了头疼——那这篇文章,你一定要!在整车电控开发里,DBC = CAN总线的官方字典。没有DBC,报文就是一串乱码;读不懂DBC,测试寸步难行;用不好DBC,排查故障全靠猜。本文总结50条全网最实用、最贴近实车、最能解决问题的DBC技巧,从基础语法到新能源专用信号,从工具操作到故障排错,全部来自一线台架、实车、高压平台实战经验。不废话、不空谈、不玄学,全是能直接落地的硬货!

优快云-新能源汽车研发测试专业博主 1368

【Linux网络】构建基于UDP的简单聊天室系统

本篇博文对【Linux网络】构建基于UDP的简单聊天室系统做了一个较为详细的介绍,不知道对你有没有帮助呢觉得博主写得还不错的三连支持下吧!会继续努力的~

2301_77954967的博客 1473

【Python基础】01 如何安装Python及集成环境

本文详细介绍了Python 3.13开发环境的完整搭建流程,涵盖三大操作系统(Windows/macOS/Linux)的Python安装方法、PyCharm专业IDE的配置使用,以及pip包管理工具的应用技巧。内容包括:Python 3.13各系统安装指南、PyCharm社区版与专业版的安装配置、环境验证方法、pip的基本命令与镜像源优化、虚拟环境管理,以及常见问题的解决方案。通过本教程,读者可获得一个高效完备的Python开发环境,为后续编程学习打下坚实基础。

nmdbbzcl的博客 1416

Python网络编程UDP协议概述及UDP协议多人聊天室模型

UDP协议概述 UDP协议——User Datagram Protocol,即用户数据包协议,UDP协议是无连接、不可靠、高效率数据传输协议。 UDP协议优点:开销小、速度快、无连接。 UDP协议缺点:无确认重传和排序、无流控制、无错误恢复。 UDP协议是面向报文的传输协议,它对报文既不拆分也不合并,而是给报文添加头部后就向下交给IP层。发现错误时不要重传,只是简单地把错误的报文扔掉、或给应用程序提供警告。 UDP协议广泛运用在强调数据传输速率的多媒体应用领域,例如网络聊天、在线视频、网络游戏、实时监控、

m0_47670683的博客 532

基于Simulink使用激光雷达数据跟踪车辆仿真(附源码)

这些模型将长方体的尺寸定义为状态转换期间的常量,并且它们的估计值在滤波器的校正阶段随时间演变。下面的动画显示了在滤波器的预测阶段将具有不同概率的恒定速度和恒定转弯率模型混合在一起的效果。此示例显示了如何使用带有 IMM 过滤器的 JPDA 跟踪器来跟踪使用激光雷达传感器的对象。图像和激光雷达数据读取器从 MAT 文件中读取记录的数据,并分别输出参考图像和点云中点的位置。跟踪器块选中“启用所有轨道输出”和“启用可检测的跟踪 ID 输入”复选框,以从跟踪器输出所有轨道,并将其检测概率作为其状态的函数进行计算。

珞瑜的博客 2565

STM32开发笔记85: SX1268驱动程序设计(芯片唤醒)

单片机型号:STM32L053R8T6 本系列开发日志,将详述SX1268驱动程序的整个设计过程,本篇介绍芯片唤醒驱动程序。 一、RxDutyCycle模式 在讲述本篇内容之前,我们先来看一下SX1268的一种模式RxDutyCycle,译为中文为接收占空比模式。其可使用SetRxDutyCycle命令进入RxDutyCycle模式,我们来看一下该命令的详细解释。 该命令具有2个参数,...

snmplink的博客 4065

Java实现--基于服务器的多用户聊天室

Java实现--多用户聊天室

c_y_s_的博客 4010

TensorRT量化实战教程:从PTQ到QAT,让你的模型推理速度飞起来

无论是PTQ的“快速落地”,还是QAT的“精度极致”,TensorRT量化技术都能成为你模型部署路上的“性能引擎”。通过本教程的实战项目,你已掌握从技术原理到工程落地的全流程能力——现在,不妨将你的模型代入其中,亲眼见证它在速度与精度的双重提升中“焕发生机”。若你在实操中遇到任何卡点,随时可以针对具体问题交流,我会尽全力帮你突破量化部署的每一个瓶颈。

FJN110的博客 238
上一篇: 广播,组播的实现
下一篇: 百度辞典单机版,qt项目
MrBugYang
博客等级 码龄18年 21粉丝 35原创
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

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

抵扣说明:

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

余额充值