计算机网络课程设计之网络聊天程序的设计与实现

2023-05-16

TCP和UDP在接收方的区别(实际上本实验中用不着)

UDP 协议(User Datagram Protocol 用户数据报协议),是一 种保护消息边界的,不保障可靠数据的传输。就是指传输协议把数据当作一条独立的消息在网上传输,接收端只能接收独立的 消息。也就是说存在保护消息边界,接收端一次只能接收发送端发出的一个数据包

TCP 协议(Transmission Control Protocol 传输控制协议), 是一种流传输的协议。他提供可靠的、有序的、双向的、面向连接的传输。 如果发送端连续发送数据,接收端有可能在一次接收动作中, 会接收两个或者更多的数据包

举例来说,假如,我们连续发送三个数据包,大小分别是 2k、4k、8k,这三个数据包都已经到达 了接收端的网络堆栈中,如果使用 UDP 协议,不管我们使用多大的接收缓冲区去接收数据,我们必须 有三次接收动作,才能够把所有的数据包接收完。而使用 TCP 协议,我们只要把接收的缓冲区大小设 置在 14k 以上,我们就能够一次把所有的数据包接收下来,只需要有一次接收动作。

正文:实验部分

思路:具体学习参考B站大佬,他的代码无法实现全双工,原因是Socket开启了阻塞,我改成非阻塞之后就出现了意料之外的错误,由于后面还有别的实验要做,这里就没修改了。
先贴一份实现简易聊天功能的代码,主要是注解。这是实现聊天室的基础
#include "pch.h"
#include <stdio.h> 
#include <Winsock2.h> 

#pragma comment( lib, "WSOCK32.LIB")

void main() {


	printf("服务器 SocketDLL初始化");
	/****** SocketDLL的初始化 ******/
	WORD wVersionRequested;
	WSADATA wsaData;
	int err;
	wVersionRequested = MAKEWORD(1, 1);
	err = WSAStartup(wVersionRequested, &wsaData);
	if (err != 0) { return; }
	if (LOBYTE(wsaData.wVersion) != 1 || HIBYTE(wsaData.wVersion) != 1)
	{
		WSACleanup();   return;
	}

	/**创建服务器Socket**/

	// AF_INET : 使用IP地址族
	// 套接字类型为SOCK_STREAM流类型, 也就是适用于TCP
	// UDP的话是SOCK_DGRAM 数据报套接字
	SOCKET sockSrv = socket(AF_INET, SOCK_STREAM, 0);



	/*****初始化服务器的包结构********/

	// 封装成sockaddr_in 类,俗称地址包,保存端口号和IP地址
	SOCKADDR_IN addrSrv;
	// 将IP地址 INADDR_ANY (0x00000)主机字节转换成网络字节:高字节在前面
	//addrSrv.sin_addr.S_un.S_addr = htonl(INADDR_ANY);
	// 我们弃用这种默认值,使用局域网中的IP
	char ip[] = "127.0.0.1";
	// inet_addr:将点分十进制的IP 转换成二进制,然后再转换成网络字节
	addrSrv.sin_addr.S_un.S_addr = inet_addr(ip);
	// 设置为IP协议族
	addrSrv.sin_family = AF_INET;
	// 设置端口号,把主机字节转换成网络字节
	addrSrv.sin_port = htons(6000);


	/***将服务器Socket和服务器包进行绑定*****/

	// 强制转换的作用在于:SOCKADDR_IN 地址包的形式,只是方便了我们设置参数
	// 而使用的时候,bind还是需要把这些参数揉和到一起。
	bind(sockSrv, (SOCKADDR*)&addrSrv, sizeof(SOCKADDR));


	// 让服务器Socket开启监听,并且设置最大的等待连接数
	// 等待连接数(半连接)过大会给服务器造成负载
	listen(sockSrv, 5);

	SOCKADDR_IN addrClient;
	int len = sizeof(SOCKADDR);
	while (1) {
		SOCKET sockConn = accept(sockSrv, (SOCKADDR*)&addrClient, &len);
		char sendBuf[50];
		// inet_ntoa 是把二进制IP转换成点分十进制,是上面那个的逆
		// 调用springf将字符串转换成 适合传输的类型
		sprintf(sendBuf, "Welcome %s to here!", inet_ntoa(addrClient.sin_addr));
		// 进行发操作
		send(sockConn, sendBuf, strlen(sendBuf) + 1, 0);
		char recvBuf[50];
		// 接收操作
		recv(sockConn, recvBuf, 50, 0);
		printf("%s\n", recvBuf);
		closesocket(sockConn);
	}
}

简易客户端

#include <stdio.h>
#include <Winsock2.h>
void main()
{
WORD wVersionRequested;
WSADATA wsaData;
int err;
wVersionRequested = MAKEWORD( 1, 1 );
err = WSAStartup( wVersionRequested, &wsaData );
if ( err != 0 ) {
return;
}
if ( LOBYTE( wsaData.wVersion ) != 1 || HIBYTE( wsaData.wVersion ) != 1 ) {
WSACleanup( );
return;
}
SOCKET sockClient=socket(AF_INET,SOCK_STREAM,0);
SOCKADDR_IN addrSrv;
addrSrv.sin_addr.S_un.S_addr=inet_addr("127.0.0.1");
addrSrv.sin_family=AF_INET;
addrSrv.sin_port=htons(6000);
connect(sockClient,(SOCKADDR*)&addrSrv,sizeof(SOCKADDR));
send(sockClient,"hello",strlen("hello")+1,0);
char recvBuf[50];
recv(sockClient,recvBuf,50,0);
printf("%s\n",recvBuf);
closesocket(sockClient);
WSACleanup();
}

下面的代码是我写的实现全双工和多线程处理,不过存在BUG

客户端


#include "pch.h"
#include <Winsock2.h> 
#include <cstdlib>
#include <stdio.h> 
#include <iostream>

#pragma comment(lib, "ws2_32.lib")

using namespace std;

// 全局常量
const int SEND_SIZE = 1000;
const int MAX_BUF_SIZE = 200;


// 全局变量
SOCKET sockClient;
SOCKADDR_IN addrSrv;

// 接收线程的设置是死循环不断得提交recv申请,如果有反馈,就输出。
DWORD WINAPI Client_Receive_Thread(LPVOID lp) {
	SOCKET *s = (SOCKET*)lp;
	int nrecv;
	while (true)
	{
		// 监听服务器端消息
		char recvBuf[SEND_SIZE];
		// recv 的第一个参数是当前socket
		int res = recv(sockClient, recvBuf, SEND_SIZE, 0); // 最后参数设置成0,表示非阻塞
		if (res > 0) // 由于socket默认的阻塞,因此recv会自动阻塞
		{
			printf("%s\n", recvBuf);

		}
	}
}

void main() {
	printf("客户端 SocketDLL初始化");
	/****** SocketDLL的初始化 ******/
	WORD wVersionRequested;
	WSADATA wsaData;
	int err;
	wVersionRequested = MAKEWORD(1, 1);
	err = WSAStartup(wVersionRequested, &wsaData);
	if (err != 0) { return; }
	if (LOBYTE(wsaData.wVersion) != 1 || HIBYTE(wsaData.wVersion) != 1) {
		WSACleanup();   return;
	}


	sockClient = socket(AF_INET, SOCK_STREAM, 0);
	unsigned long ul = 1;
	int ret = ioctlsocket(sockClient, FIONBIO, (unsigned long *)&ul);
	if (ret == SOCKET_ERROR) {
		printf("非阻塞化失败!");
		return;
	}
	/****设置地址包*****/
	// 巡回测试IP
	addrSrv.sin_addr.S_un.S_addr = inet_addr("192.168.1.86");
	addrSrv.sin_family = AF_INET;
	addrSrv.sin_port = htons(6000);

	char username[50];
	printf("请输入你的姓名: ");
	scanf("%s", username);


	for(int i=1;i<=5;i++)// 非阻塞下,不知道如何建立连接了。
	{
		cout << "尝试发送连接请求...." << endl;
		// 发起到服务器的连接,第二个参数设置了服务器端的参数
		int ret = connect(sockClient, (SOCKADDR*)&addrSrv, sizeof(SOCKADDR));
		if (ret == 0)
		{
			cout << "连接成功" << endl;
			// 建立连接,且第一次发送username
			send(sockClient, username, SEND_SIZE, 0);
			break;
		}
		cout << "连接失败" << endl;
	}
	

	// 客户端开启一个线程,负责监听服务器端
	LPVOID *lp = (LPVOID*)&sockClient;
	HANDLE hThread = CreateThread(NULL, 0, Client_Receive_Thread, lp, 0, NULL);

	// 主线程用于输入
	char input[50];
	char msg[MAX_BUF_SIZE];
	while (true)
	{

		scanf("%s", input);

		if (strcmp(input, "exit") == 0)
		{
			printf("bye\n");
			break;
		}
		else if (strcmp(input, "send") == 0) {
			scanf("%s", msg);
			printf("success send msg: %s\n", msg);
			send(sockClient, msg, SEND_SIZE, 0);
		}
	}
	// 关闭连接
	closesocket(sockClient);
	WSACleanup();
}

服务器端

#include "pch.h"
#include <stdlib.h>
#include <stdio.h>
#include <WinSock2.h>
#include <iostream>
#include <WS2tcpip.h>
#include <cstring>

#pragma comment(lib,"ws2_32.lib")
using namespace std;



// 常量

const int SEND_SIZE = 1000;
const int MAX_BUF_SIZE = 500;
const int NICKNAME_LEN = 20;
const int MAX_CLIENT_COUNT = 20;

// 变量

int clientCount = 0;



// 封装成Client结构
struct Client
{
	SOCKET s;
	SOCKADDR_IN sin;
	char name[NICKNAME_LEN];
}Cli[MAX_CLIENT_COUNT];



DWORD WINAPI ServerListeningConnect(LPVOID lp) {
	SOCKET *s = (SOCKET*)lp;
	int nrecv;
	int len = sizeof(SOCKADDR);
	while (true)
	{
		Cli[clientCount + 1].s = accept(*s, (SOCKADDR*)&Cli[clientCount + 1].sin, &len);

		// 这里不清楚是否是阻塞,因此加上判断
		if (Cli[clientCount + 1].s != INVALID_SOCKET)
		{
			clientCount++;

			unsigned long ul = 1;
			int ret = ioctlsocket(Cli[clientCount].s, FIONBIO, (unsigned long *)&ul);
			if (ret == SOCKET_ERROR) {
				printf("非阻塞化失败!");
				return 0;
			}

			// 获取客户端的姓名
			recv(Cli[clientCount].s, Cli[clientCount].name, SEND_SIZE  , 0);
			 
			// 反馈。不晓得能反馈到哪
			
			 
			for (int i = 1; i <= clientCount; i++)
			{
				char sendBuf[MAX_BUF_SIZE] = "Welcome [";
				strcat(sendBuf, Cli[i].name);
				strcat(sendBuf, "] 加入直播间,当前直播间有");
				char number[50];
				itoa(clientCount, number, 50);
				strcat(sendBuf, number);
				strcat(sendBuf, "人");
				printf("%s\n", sendBuf);
				send(Cli[i].s, sendBuf, SEND_SIZE, 0);
				
			}
			

			
		}

	}
}

int main()
{
	WORD wVersionRequested;
	WSADATA wsaData;
	int err;
	wVersionRequested = MAKEWORD(1, 1);
	err = WSAStartup(wVersionRequested, &wsaData);
	if (err != 0) {
		return 0 ;
	}
	if (LOBYTE(wsaData.wVersion) != 1 || HIBYTE(wsaData.wVersion) != 1) {
		WSACleanup();
		return 0;
	}

	printf("初始化成功。。。。\n");
	SOCKET sockSrv = socket(AF_INET, SOCK_STREAM, 0);
	unsigned long ul = 1;
	int ret = ioctlsocket(sockSrv, FIONBIO, (unsigned long *)&ul);
	if (ret == SOCKET_ERROR) {
		printf("非阻塞化失败!");
		return 0;
	}

	SOCKADDR_IN addrSrv;
	addrSrv.sin_addr.S_un.S_addr = inet_addr("192.168.1.86");
	addrSrv.sin_family = AF_INET;
	addrSrv.sin_port = htons(6000);
	bind(sockSrv, (SOCKADDR*)&addrSrv, sizeof(SOCKADDR));
	listen(sockSrv, 5);


	// 开启线程监听连接

	LPVOID *lp = (LPVOID*)&sockSrv;
	HANDLE hThread = CreateThread(NULL, 0, ServerListeningConnect, lp, 0, NULL);


	// 开启线程监听是否客户端发送了消息
	//就写在主线程吧
	// 
	
	while (true)
	{

		char recvbuf[MAX_BUF_SIZE];
		for (int i = 1; i <= clientCount; i++)
		{
			// 当收到消息时。这里有点担心recv是阻塞的,这样的话收到第一个后,就会卡住
			if (recv(Cli[i].s, recvbuf, sizeof(recvbuf), 0) != INVALID_SOCKET)
			{
				// 向另外的客户端进行发送
				char sendbuf[SEND_SIZE];
				strcpy(sendbuf, "[");
				strcat(sendbuf, Cli[i].name);
				strcat(sendbuf, "]:>");
				strcat(sendbuf, recvbuf);
				for (int j = 1; j <= clientCount; j++)
				{
					if (j == i)
						continue;
					
					printf("服务器接收到了来自%d 发给 %d  的 %s\n", i,j,recvbuf);
					printf("服务器即将发送 %s\n", sendbuf);
					send(Cli[j].s, sendbuf, SEND_SIZE, 0);
				}
			}
		}
	}
}

 
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

计算机网络课程设计之网络聊天程序的设计与实现 的相关文章

  • Qt 文件树的实现

    Qt 文件树的实现 xff08 QTreeWidget xff0c QTreeWidgetItem xff09 使用Qt框架创建文件树主要是使用了Qt仲的QTreeWidget控件和QTreeWidgetItem控件 其最主要的功能包括文件
  • chromeOS中Linux安装Flatpak,切换Flatpak数据源,安装Remmina应用

    本文基于ChromeOS 版本106 0 5249 112 xff08 正式版本 xff09 xff0c Debain 11版本 设置 开发者 Linux开发环境 启用 chromebook开启Linux容器 以下内容涉及到的技术均为Deb
  • 性能学习笔记--k8s下mysql的连接数分析和调优

    项目背景 xff1a k8s的架构下 xff0c 登录并发100后 xff0c 发现cpu的利用率过高 xff0c 超过75 xff1b 开始不知道是哪个微服务导致的cpu利用率过高 xff0c 需要进行分析 xff08 最终分析是mysq
  • C++比较函数cmp

    本文将简单介绍C 43 43 比较函数 cmp 排序函数sort sort函数是我们常用的库函数 xff0c 它的参数如下 xff1a span class token keyword void span sort span class t
  • 弹性云服务器ECS的选择:为什么我更推荐华为云?

    前言 作为一名嵌入式开发者 xff0c 平常难免不了需要一台云服务器来搭建一个调试物联网设备的测试平台 x1f604 xff0c 因此平时也没少购买云服务器 xff0c 但是云服务器厂商那么多 xff0c 我们到底应该如何做出选择呢 xff
  • git中忽略所有文件后,白名单中添加文件夹及其所有子文件(夹)

    此点很容易就出问题了 xff0c 我用的想法是要么添加 subfiledir 要么添加 subfiledir 但是按照git的逻辑 xff0c 第一行只会让subfiledir添加进来 xff0c 但是其所有子文件以及文件夹是不会被添加进来
  • 51单片机外部中断

    span class token keyword void span span class token function IrInit span span class token punctuation span span class to
  • 51单片机定时器2用作串口

    使用定时器2用作串口 span class token macro property span class token directive hash span span class token directive keyword defin
  • 二进制的计算(原码、补码以及反码)

    带符号 5 2 0000 0101 gt 5 1000 0010 gt 2 然后两个数据都转为补码进行相加 正数的补码等于原码 负数的补码等于符号位不变 xff0c 剩下的取反加一 算补码的时候符号位不参与计算 0000 0101 43 加
  • iwr6843-ROS构建

    需求 ubuntu 18 04版本 安装ros 安装教程 首先安装必要软件 sudo apt install git curl vim y 设置您的计算机以接受来自 packages ros org 的软件 sudo sh c 39 ech
  • 51nod - 1364 最大字典序排列

    给出一个1至N的排列 xff0c 允许你做不超过K次操作 xff0c 每次操作可以将相邻的两个数交换 xff0c 问能够得到的字典序最大的排列是什么 xff1f 例如 xff1a N 61 5 xff0c 1 2 3 4 5 xff0c k
  • esp8266_贝壳物联_arduino

    功能 接收串口数据 xff0c 将串口数据上报到贝壳物联的数据接口 此处为接收0和1数据 xff0c 上报到贝壳物联 贝壳物联平台通讯协议 ArduinoJson解析 ArduinoJson Assistant非常好用的工具 span cl
  • 简历信息粘贴板

    简历信息粘贴板 gitee链接 x1f602 最近简历投递感觉很麻烦 xff0c 所以想整个这个 xff0c 欢迎体验 有用可以整个 随便也水一个文 xff0c 好久没更了 x1f466 描述 厌倦了麻烦的简历填写了吗 是不是感觉切换查找复
  • Python装饰器简单说明

    Python装饰器 官方定义 装饰器本质上是一个Python函数 其实就是闭包 xff0c 它可以让其他函数在不需要做任何代码变动的前提下增加额外功能 xff0c 装饰器的返回值也是一个函数对象 装饰器用于有以下场景 xff0c 比如 插入
  • cpp装饰器模式

    装饰器模式 结构型模式 xff1a 在不改变现有对象结构的情况下 xff0c 向对象添加新的功能 xff0c 同时不改变其结构 重点在于动态的增加删除功能 xff0c 装饰类和被装饰类独立 xff0c 不会耦合 返回的对象已经不是原来的对象
  • windows新增右键菜单,通过wsl中的vim打开文件

    文章目录 查看wsl打开方式添加右键菜单增加图标效果 非常简单的方式 x1f44d 查看wsl打开方式 可以看到我这里使用ubuntu2004 exe可以打开 添加右键菜单 按下win输入regedit xff0c 在右边选择管理员打开 然
  • iwr6843isk-HARbag

    文章目录 描述说明数据信息使用方法动作类型jumpsquatswavewalkboxingjack iwr6843isk搭建ROS环境雷达配置参数to txt中数据预处理 二阶段滑窗处理 环境 github链接 https gitee co
  • PVE+NUT+群晖等配置

    文章目录 配置文件说明 默认配置 翻译的 ups conf 设置ups通信相关 upsd conf 设置ups客户访问的相关信息 upsd users 设置upsd用户 nut conf nut的配置 主要是模式 xff0c 决定使用哪些文
  • stm32霸道-lvgl移植学习(一)

    文章目录 效果有用链接要求创建工程屏幕驱动以及触屏驱动LVGL PortWidgets demo其它 效果 目前显示驱动显示较慢 xff0c 后续会优化 有用链接 LVGL官网 代码下载 要求 要求最低要求 建议要求架构16 32 64位微

随机推荐

  • E6410安装PVE直通显卡安装LibreELEC系统

    文章目录 查看cpu是否支持直通音频笔记本关盖设定BIOS设定启动内核IOMMU支持添加驱动黑名单绑定核显到vfio模块然后新建一个虚拟机安装LibreELEC注意事项重启 VM 时 GPU 直通失败如果直通后遇到问题了 xff0c 开机出
  • 关于SublimeText3和MinGW安装的一些心得

    本人也是为了学习C 43 43 xff0c 在无意中找到用Sublime Text3和MinGW来进行组合搭建从而完成代码的编译的运行 安装过程期间 xff0c 也出现了一些错误 xff0c 下面就把我的出现的一些错误贴出来 xff0c 看
  • confluence linux 安装教程

    jdk的安装 参考此链接 confluence下载 Confluence官网 linux安装 将下载后的安装包上传到linux系统中 xff0c 并授予权限 xff0c 注意请使用root用户安装 xff0c 否则会出现部分功能无法使用的情
  • Boost库编译指南

    1 Boost 库简介 Boost 是一个开源的 C 43 43 库集合 xff0c 提供了许多高质量的库 xff0c 涵盖了许多不同的领域 xff0c 如智能指针 多线程编程 正则表达式 数学库等等 Boost 的目标是提高 C 43 4
  • 解决Flask中出现的跨域问题has been blocked by CORS policy: No ‘Access-Control-Allow-Origin‘ header...

    今天在用flask做接口进行本地调用测试时发现调用报错 如图所示 解决办法 xff1a 在项目目录打开终端 xff0c 安装以下库 pip install U flask cors 再在代码中插入 CORS app resources 61
  • 【Web笔记】Html学习手册

    HTML简介 HTML是 超文本标记语言 xff08 HyperText Markup Language xff09 的简称 HTML的前世今生 从初期的网络诞生后 xff0c 已经出现了许多HTML版本 版本发布时间HTML1991HTM
  • webrtc-kurento

    WebRTC 呼叫者通过 navigator mediaDevices getUserMedia en US 捕捉本地媒体 呼叫者创建一个RTCPeerConnection 并调用 RTCPeerConnection addTrack 注
  • windows10远程连接centos图像化桌面步骤和遇到的问题

    一 安装配置XRDP 首先需要切换到root用户下 xff1b 1 安装epel库 1 xff09 检测系统是否已经安装epel库 rpm qa grep epel 2 xff09 安装epel库 yum install epel rele
  • linux磁盘分区、挂载、扩容

    1 fdisk l 查看磁盘情况 xff0c 可以看到总共4块磁盘 xff0c sda是系统盘及根目录 xff0c 剩余sdb sdc sdd三块磁盘可用 root 64 openEuler dev fdisk l Disk dev sdd
  • QT 线程之QWaitCondition(深入理解)

    QWaitCondition 允许线程在某些情况发生时唤醒另外的线程 一个或多个线程可以阻塞等待一QWaitCondition 用wakeOne 或wakeAll 设置一个条件 wakeOne 随机唤醒一个 xff0c wakeAll 唤醒
  • Qt QMessageBox使用详解

    本文详细的介绍了QMessageBox控件的各种操作 xff0c 例如 xff1a 消息提示框的使用 判断消息提示框的按钮 标准图标和自定义图标 定时关闭 自定义样式等操作 本文作者原创 xff0c 转载请附上文章出处与本文链接 Qt QM
  • C++ permutation排列算法详解(深入了解,一文学会)

    排列就是一次对对象序列或值序列的重新排列 例如 xff0c ABC 中字符可能的排列是 xff1a 34 ABC 34 34 ACB 34 34 BAC 34 34 BCA 34 34 CAB 34 34 CBA 34 三个不同的字符有 6
  • QT QMenuBra QMenu QAction 菜单栏 操作详解

    本文详细的介绍了QMenuBra QMenu QAction 菜单栏的各种操作 xff0c 例如操作 xff1a 新建界面 加入菜单项 加入子菜单 新建二级子菜单 QAction分隔符 pMenuBar 点击信号 触发信号 设置图标 设置禁
  • 网络编程POSIX规范要求数据类型

    数据类型 说明 来源 int8 t 带符号8位整数 lt sys types h gt uint8 t 无符号8位整数 lt sys types h gt int16 t 带符号16位整数 lt sys types h gt uint16
  • 解决ajax的delete、put方法接受不到参数的问题

    通过修改配置文件来实现Put和Delete请求的参数传递的问题 在web xml中添加如下代码 xff1a lt filter gt lt filter name gt HttpMethodFilter lt filter name gt
  • - Dockerfile 指令、构建过程

    查看Dockerfile中可以使用的全部指令 xff1a lt http docs docker com reference builder gt 制作Docker image 有两种方式 xff1a 一是使用 Docker contain
  • python正则表达式匹配邮箱地址是否合法

    题目 xff1a 1 xff09 请尝试写一个验证Email地址的正则表达式 版本一应该可以验证出类似的Email xff1a someone 64 gmail com bill gates 64 microsoft com 2 xff09
  • 公网IP和内网IP的区别? 什么是127.0.0.1?

    IP地址是设备在网络上的唯一标识符 xff0c 比如无线路由器有两个IP xff0c 公网IP xff08 例如100 78 118 73 连接互联网 xff0c 私有 xff08 内网 xff09 IP xff08 如192 168 1
  • 计算机网络课程设计之Tracert与Ping 程序设计与实现

    一 预备知识 ICMP ICMP的报文是封装在IP数据部分中的 按照我的理解 xff0c ICMP就是在网络层中 xff0c 反馈一些转发 访问等操作时的附带信息 ICMP分为两种 xff0c ICMP差错报告报文 xff08 IP传输时的
  • 计算机网络课程设计之网络聊天程序的设计与实现

    TCP和UDP在接收方的区别 xff08 实际上本实验中用不着 xff09 UDP 协议 User Datagram Protocol 用户数据报协议 xff0c 是一 种保护消息边界的 xff0c 不保障可靠数据的传输 就是指传输协议把数