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

熵编码(五)-CABAC(一) 基础篇

前两篇算术编码文章介绍了算术编码原理和步骤。本篇文章介绍CABAC,基于上下文自适应的二进制算术编码。本文对CABAC的基本原理进行了详细的介绍和分析,下篇文章将会对H264编码中的CABAC熵编码的实际应用进行介绍。

尹佑壮的博客 3879

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

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

weixin_73870552的博客 1075

HarmonyOS NEXT 开发者预览版Beta招募应知测试

本次HarmonyOS NEXT 开发者预览版 Beta 招募活动为开发者预览版尝鲜升级,主要供开发者进行应用调测使用,除部分系统应用外,其他所有应用将被清除,因此在进行HarmonyOS NEXT 开发者预览版升级前,需进行数据备份。通过应知测试,并提交了参加HarmonyOS NEXT 开发者预览版招募 Beta 活动的报名信息,就会立刻审核通过并且收到新版本。手机在参加HarmonyOS NEXT 开发者预览版 Beta 招募活动前,需要对应机型升级到招募要求对应的基线版本,并预留内存空间。

长久公子的博客 8648

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

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

EQ_cyc的博客 3011

利用CiteSpace实现知网专利文献的高效计量与可视化分析

本文详细介绍了如何利用CiteSpace软件对中国知网(CNKI)的专利文献进行高效的文献计量与可视化分析。文章提供了从数据获取、格式转换、参数设置到图谱解读的完整工作流,旨在帮助研究者快速掌握该工具,从而洞察技术领域的研究热点、核心机构、学者合作网络及发展趋势,提升专利情报分析效率。

weixin_28520495的博客 292

单相全桥逆变器中比例谐振(PR)控制的优化设计与实现

本文深入探讨了比例谐振(PR)控制在单相全桥逆变器中的优化设计与实现。通过对比PID控制,详细阐述了PR控制在50Hz基波频率处实现无静差跟踪和强抗干扰性的原理。文章提供了从理论建模、参数整定(Kp, Kr, ωc)到仿真验证的完整实战流程,并介绍了准比例谐振(QPR)控制以增强频率鲁棒性,以及多谐振点设计以抑制特定谐波等进阶优化方法,最终实现THD从3%降至1%以内的显著性能提升。

weixin_29056781的博客 176

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

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

2301_77954967的博客 1473

如何利用VS2017创建一个简单的窗口

#如何利用VS2017创建一个简单的窗口 1、新建->Windows桌面向导 2、应用程序类型->桌面应用程序,点击确定 3、点击调试->开始调试 可建立如下图的窗口 4、可以在生成的项目文件的中找到windows17_2的应用程序,打开界面如下: 注:新建空白项目也可以,注意在解决方案资源器中添加.cpp文件,如源.cpp文件,下载代码见博文 ...

weixin_46894139的博客 2914

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

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

m0_47670683的博客 532

Arco Design Pro PC端商家后台框架 | Axure高保真原型库

摘要:本Axure原型设计方案基于字节跳动ArcoDesignPro规范,提供企业级后台快速搭建方案。包含动态表格、表单验证等核心组件,采用中继器驱动设计,支持响应式布局。方案覆盖80%后台常用交互,可节省60%原型制作时间,配套完整设计文档和组件库,实现原型到开发的高效衔接。特别适用于电商、SaaS等后台系统开发,支持权限管理、数据分析等场景,显著提升团队协作效率。

招风的黑耳优快云 3971

ZLMediaKit在Windows下启用WebRtc编译(64位)

准备软件 cmake-gui vs2017 已经编译好的windows版本openssl(下载地址) 当然,你完全可以自己按照openssl的官网教程自己编译windows版本的openssl libsrtp编译安装 首先,需要将下载好的openssl解压并添加到环境变量。如下图,将下图路径添加到环境变量 其次,下载libsrtp(下载地址) 下载后解压并新建build文件夹,如下图: 在合适位置新建文件夹放置install后的srtp文件,如"D:\develop20..

byna11sina11的博客 1万+

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

Java实现--多用户聊天室

c_y_s_的博客 4010

【WRFDA教程第一期】运行观测预处理程序(OBSPROC)

运行观测预处理程序(OBSPROC)

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

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

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

抵扣说明:

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

余额充值