Linux C/C++之TCP / UDP通信

2023-05-16

目录

1. 什么是网络

1.1 网络的定义

1.2 网络的实质

1.3 主机的类型

1.4 信息的传递

2. 网络分层

2.1 五层模型

2.2 七层模型(OSI Open System Interconnection)

2.3 每层作用以及相关协议

3. ip, 网关,子网掩码,端口

3.1 ip(Internet Protocol)

3.2 网关

3.3 子网掩码

3.4 端口

4. 大小端系统

4.1 大端系统

4.2 小端系统

4.3 注意事项

5. 什么是协议

5.1 协议的实质

5.2 协议的分类

6. 传输层协议之TCP通信

6.1 TCP通信编程模型

6.2 TCP实现简单通信

6.2.1 Server端

6.2.2 Client端

6.3 TCP实现文件传输

6.3.1 实现连接后,文件传输步骤

6.3.2 server(接收文件)端

6.3.3 client(发送文件)端

7. 传输层协议之UDP通信

7.1 UDP通信编程模型

7.2 UDP实现简单通信

7.2.1 Server端

7.2.2 Client端

7.3 UDP实现文件传输

7.3.1 Server(文件接收)端

7.3.2 Client(文件发送)端

8. TCP通信与UDP通信的优缺点

8.1 TCP通信优缺点

8.1.1 优点

8.1.2 缺点

8.2 UDP通信优缺点

8.2.1 优点

8.2.2 缺点

1. 什么是网络

1.1 网络的定义
网络(Network)是由若干节点和连接这些节点的链路构成的图,表示诸多对象及其相互联系。网络有资源共享、快速传输信息、提高系统可靠性、易于进行分布式处理和综合信息服务等特性。

1.2 网络的实质
网络就是多个主机连接到一起, 各个主机之间可以传输信息, 资源共享等功能。

1.3 主机的类型
主机可以是交换机,基站,路由器,电脑,手机等等

1.4 信息的传递
基站与基站之间通过无线电进行信息的传递。或者其它主机之间通过光,电等物理媒介进行信息的传递。

2. 网络分层

2.1 五层模型
应用层
传输层
网络层
数据链路层
物理层
2.2 七层模型(OSI Open System Interconnection)
应用层
表示层
会话层
传输层
网络层
数据链路层
物理层
2.3 每层作用以及相关协议

	应用层:为操作系统或网络应用程序提供访问网络服务的接口,常见的协议有 FTP  HTTP  HTTPS  SMTP DNS等。
    表示层:提供数据格式转换服务,解密与加密,图片的解码与编码,数据的压缩和解压缩,常见协议有 URL加密  口令加密  图片编解码等等。
    会话层:建立端连接并提供访问验证和会话管理,例如使用效验点可使会话在通信失效时从效验点恢复通信。常见:服务器验证用户登录,断点续传。
    传输层:提供应用进程之间的逻辑通信,建立连接,处理数据包错误,处理数据包次序,常见协议:TCP  UDP  SPX
    网络层:为数据在结点之间传输创建逻辑链路,并分组转发数据。例如,对子网间的数据包进行路由选择,常见的有路由器,多层交换机,防火墙,IP,IPX,RIP,OSPF。
    数据链路层:在通信实体建立数据链路连接。例如,将数据分帧并处理流控制,物理地址寻址,重发等。常见的有网卡,网桥,二层交换机。
    物理层:为数据端设备提供原始比特流的传输通路。例如,网络通信的数据传输介质由电缆与设备共同构成。常见的有中继器,集线器,网线,HUB等。

3 ip, 网关,子网掩码,端口

3.1 ip(Internet Protocol)
网络之间互连的协议,也就是为计算机网络相互连接进行通信而设计的协议,IP协议也可以叫做因特网协议。ip用来区分网络中的不同主机,例如ipv4的本质就是一个4字节(byte)的无符号(unsigned)整数。

例如: 192.168.1.123 数点格式字符串

3.2 网关
网关(Gateway)又称网间连接器、协议转换器。网关在网络层以上实现网络互连,是复杂的网络互连设备,仅用于两个高层协议不同的网络互连。网关既可以用于广域网互连,也可以用于局域网互连。 网关是一种充当转换重任的计算机系统或设备。使用在不同的通信协议、数据格式或语言,甚至体系结构完全不同的两种系统之间,网关是一个翻译器。与网桥只是简单地传达信息不同,网关对收到的信息要重新打包,以适应目的系统的需求。

3.3 子网掩码
子网掩码前三段确定路由,最后一段确定主机,子网掩码为(255.255.255.0),使用子网掩码&ip地址可以得到IP地址的前三段,使用(~子网掩码)&ip可以得到IP地址的最后一段。

3.4 端口
在同一个主机之上有多个端口,每个进程使用唯一的一个端口,例如浏览器使用 80 号端口,一般端口都是从小到大使用的,个人写的应用程序一般建议使用5000以上的端口号,一般计算机有 0 — 65535 共计 65536 个端口,因此建议使用10000左右的端口比较稳妥。

4. 大小端系统

4.1 大端系统
低位数据存放在高地址,高位数据存放在低地址。

4.2 小端系统
低位数据存放在低地址,高位数据存放在高地址。

4.3 注意事项
网络服务器均为大端系统(因为网络服务器一般是UNIX系统),因此在编写网络通信的代码时需要将小端转换为大端

大小端存储模型
在这里插入图片描述

小端系统的存储

#include <stdio.h>
 
union uu{
	char c[4];
	int n;
};
int main(){
	//类型  决定  存储方式 和 占用空间大小
	//int 4字节     x86架构    arm架构   ......
	//0x11223344   小端系统    大端系统
	
	union uu u;
	u.n = 0x11223344;
	printf("%x %x %x %x\n",u.c[0],u.c[1],u.c[2],u.c[3]);
 
	return 0;
}

在这里插入图片描述

5. 什么是协议

5.1 协议的实质
协议就像我们在学校需要遵守的规矩一样,网络通信也是如此,只有当服务器与客户端均遵守相同的规矩(协议)它们之间才能完成通信。

5.2 协议的分类
公有协议:大部分人都遵守的规矩。
私有协议:部分人遵守的协议。例如对讲机,远程监控使用公有协议就会存在安全问题,一般数据链路层和物理层均使用私有协议。

6. 传输层协议之TCP通信

6.1 TCP通信编程模型

服务器(server)客户端(client)
1. 创建socke1. 创建socket
2. 确定服务器协议地址簇2. 获取服务器协议地址簇
3. 绑定
4. 监听
5. 接受连接3. 连接服务器
6. 通信4. 通信
7. 断开连接5. 断开连接

6.2 TCP实现简单通信
6.2.1 Server端

#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <sys/types.h>        
#include <sys/socket.h>
#include <arpa/inet.h>
#include <string.h>
#include <signal.h>
 
int serverSocket,clientSocket;
void hand(int val){
	//7. 关闭连接
	close(serverSocket);
	close(clientSocket);
	printf("bye bye!\n");
	exit(0);
}
int main(int argc,char* argv[]){
	if(argc != 3) printf("请输入ip地址和端口号!\n"),exit(0);
	printf("ip: %s     port:%d\n",argv[1],atoi(argv[2]));
 
	signal(SIGINT,hand);
 
	//1. 创建socket 参数一: 协议类型(版本) 参数二: 通信媒介 参数三: 保护方式
	serverSocket = socket(AF_INET,SOCK_STREAM,0);
	if(-1 == serverSocket) printf("创建socket失败:%m\n"),exit(-1);
	printf("创建socket成功!\n");
 
	//2. 创建服务器协议地址簇
	struct sockaddr_in sAddr = { 0 };
	sAddr.sin_family = AF_INET;        //协议类型 和socket函数第一个参数一致
	sAddr.sin_addr.s_addr = inet_addr(argv[1]);  //将字符串转整数
	sAddr.sin_port = htons(atoi(argv[2]));    //将字符串转整数,再将小端转换成大端
 
	//3. 绑定服务器协议地址簇
	int r = bind(serverSocket,(struct sockaddr*)&sAddr,sizeof sAddr);
	if(-1 == r) printf("绑定失败:%m\n"),close(serverSocket),exit(-2);
	printf("绑定成功!\n");
 
	//4. 监听
	r = listen(serverSocket,10);
	if(-1 == r) printf("监听失败:%m\n"),close(serverSocket),exit(-3);
	printf("监听成功!\n");
 
	//5. 接收客户端连接
	struct sockaddr_in cAddr = {0};
	int len = sizeof(sAddr);
	clientSocket = accept(serverSocket,(struct sockaddr*)&cAddr,&len);
	if(-1 == clientSocket) printf("接收客户端连接失败:%m\n"),close(serverSocket),exit(-1);
	printf("有客户端连接上服务器了: %s\n",inet_ntoa(cAddr.sin_addr));
 
	//6. 通信
	char buff[256] = {0};
	while(1){
		r = recv(clientSocket,buff,255,0);
		if(r > 0){
			buff[r] = 0;
			printf("客户端说>> %s\n",buff);
		}
	}
 
	return 0;
}

6.2.2 Client端

#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <sys/types.h>        
#include <sys/socket.h>
#include <arpa/inet.h>
#include <string.h>
#include <signal.h>
 
int clientSocket;
void hand(int val){
	//5. 关闭连接
	close(clientSocket);
	printf("bye bye!\n");
	exit(0);
}
int main(int argc,char* argv[]){
	if(argc != 3) printf("请输入ip地址和端口号!\n"),exit(0);
	printf("ip: %s     port:%d\n",argv[1],atoi(argv[2]));
 
	signal(SIGINT,hand);
 
	//1. 创建socket 参数一: 协议类型(版本) 参数二: 通信媒介 参数三: 保护方式
	clientSocket = socket(AF_INET,SOCK_STREAM,0);
	if(-1 == clientSocket) printf("创建socket失败:%m\n"),exit(-1);
	printf("创建socket成功!\n");
 
	//2. 创建服务器协议地址簇
	struct sockaddr_in cAddr = { 0 };
	cAddr.sin_family = AF_INET;
	cAddr.sin_addr.s_addr = inet_addr(argv[1]);  //将字符串转整数
	cAddr.sin_port = htons(atoi(argv[2]));    //将字符串转整数,再将小端转换成大端
 
	//3.连接服务器
	int r = connect(clientSocket,(struct sockaddr*)&cAddr,sizeof cAddr);
	if(-1 == r) printf("连接服务器失败:%m\n"),close(clientSocket),exit(-2);
	printf("连接服务器成功!\n");
 
	
	//4. 通信
	char buff[256] = {0};
	while(1){
		printf("你想要发送:");
		scanf("%s",buff);
		send(clientSocket,buff,strlen(buff),0);
	}
 
	return 0;
}

6.3 TCP实现文件传输
6.3.1 实现连接后,文件传输步骤

接收端(Server)发送端(Client)
1. 等待客户端发送1. 发送文件名
2. 接收文件名并创建文件2. 获取文件大小并发送
3. 接收文件大小并打开文件3. 打开文件准备读取发送
4. 循环接收并写入文件4. 循环读取文件并发送文件内容
5. 写入数据完毕,关闭文件和连接5. 发送数据完毕,关闭文件和连接

6.3.2 server(接收文件)端
//Server端

#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <fcntl.h>
#include <string.h>
#include <sys/types.h>         
#include <sys/socket.h>
#include <arpa/inet.h>
 
int serverSocket,clientSocket;
 
int main(){
 
	//1. 创建socket  
	serverSocket = socket(AF_INET,SOCK_STREAM,0);
	if(-1 == serverSocket) printf("创建socket失败:%m\n"),exit(-1);
	printf("创建socket成功!\n");
 
	//2. 创建服务器协议地址簇
	struct sockaddr_in sAddr = {0};
	sAddr.sin_family = AF_INET; 
	sAddr.sin_addr.s_addr = inet_addr("127.0.0.1"); 
	sAddr.sin_port = htons(9527);  
 
	//3.绑定
	int r = bind(serverSocket,(struct sockaddr*)&sAddr,sizeof sAddr);
	if(-1 == r) printf("绑定失败:%m\n"),close(serverSocket),exit(-2);
	printf("绑定成功!\n");
 
	//4.监听
	r = listen(serverSocket,10);
	if(-1 == r) printf("监听失败:%m\n"),close(serverSocket),exit(-2);
	printf("监听成功!\n");
 
	//5.等待客户端连接
	struct sockaddr_in cAddr = {0};
	int len = sizeof(cAddr);
	clientSocket = accept(serverSocket,
		(struct sockaddr*)&cAddr,&len);
	if(-1 == clientSocket) printf("服务器崩溃:%m\n"),close(serverSocket),exit(-3);
	printf("有客户端连接上服务器了:%s\n",inet_ntoa(cAddr.sin_addr));
 
	//6. 通信
	char fileName[256] = {0};
	int fileSize = 0;
	char buff[1024] = {0};
	int fileCount; //统计写入文件内容的大小
 
	sleep(2);
	//6.1 接收文件名
	r = recv(clientSocket,fileName,255,0);
	if(r > 0){
		printf(">>>>>>%d\n",r);
		printf("接收到的文件名为: %s\n",fileName);
	}
 
	sleep(2);
	//6.2 接收文件大小
	r = recv(clientSocket,(int*)&fileSize,4,0);
	if(r == 4){
		printf("文件大小r>>> %d\n",r);
		printf("接收到的文件大小为: %d\n",fileSize);
	}
	//6.3 创建文件
	int fd = open(fileName,O_CREAT | O_WRONLY,0666);
	if(-1 == fd) printf("创建文件失败:%m\n"),
		close(serverSocket),close(clientSocket),exit(-4);
 
	sleep(2);
	//6.4 接收信息并写入文件
	while(1){
		r = recv(clientSocket,buff,1024,0);
		if(r > 0){
			write(fd,buff,r);
			fileCount += r;
			if(fileCount >= fileSize)
				break;
		}
	}
 
	//7. 关闭文件以及关闭连接
	sleep(1);
	close(fd);
	close(serverSocket);
	close(clientSocket);
	printf("文件接收完毕!\n");
 
	return 0;
}

注: accept函数为阻塞函数

6.3.3 client(发送文件)端
//Client端

#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <fcntl.h>
#include <string.h>
#include <sys/types.h>         
#include <sys/socket.h>
#include <arpa/inet.h>
#include <sys/stat.h>
 
 
int clientSocket;
 
int main(int argc,char* argv[]){
 
	//1. 创建socket  
	clientSocket = socket(AF_INET,SOCK_STREAM,0);
	if(-1 == clientSocket) printf("创建socket失败:%m\n"),exit(-1);
	printf("创建socket成功!\n");
 
	//2. 创建服务器协议地址簇
	struct sockaddr_in cAddr = {0};
	cAddr.sin_family = AF_INET; 
	cAddr.sin_addr.s_addr = inet_addr("127.0.0.1"); 
	cAddr.sin_port = htons(9527);  
 
	//3.连接服务器
	int r = connect(clientSocket,(struct sockaddr*)&cAddr,sizeof cAddr);
	if(-1 == r) printf("连接服务器失败:%m\n"),close(clientSocket),exit(-2);
	printf("连接服务器成功!\n");
 
	//4. 通信
	//4.1 打开文件
	int fd = open(argv[1],O_RDONLY,0666);
	if(-1 == fd) printf("文件打开失败:%m\n"),close(clientSocket),exit(-3);
	printf("文件打开成功!\n");
 
	//4.1 获取文件大小
	struct stat st = {0};
	stat(argv[1],&st);
	printf("文件大小为: %d\n",(int)st.st_size);
	printf("文件名为:%s\n",argv[1]);
 
	sleep(2);
	//4.2 将文件名和文件大小发送给服务器(注意先后顺序)
	send(clientSocket,argv[1],strlen(argv[1]),0);
 
	sleep(2);
	send(clientSocket,(char*)&st.st_size,4,0);
 
	//4.3 读取内容并发送
	sleep(2);
	char buff[1024] = {0};
	while(1){
		r = read(fd,buff,1024);
		if(r > 0)
			send(clientSocket,buff,r,0);
		else
			break;
	}
 
	//5. 关闭文件
	sleep(1);
	close(fd);
	close(clientSocket);
	printf("文件发送完毕!\n");
 
	return 0;
}

7. 传输层协议之UDP通信

7.1 UDP通信编程模型

服务器(Server)客户端(Client)
1. 创建Socket1. 创建Socket
2. 确定服务器协议地址簇2. 获取服务器协议地址簇
3. 绑定
4. 通信3. 通信

7.2 UDP实现简单通信
7.2.1 Server端
//Server

#include <stdio.h>
#include <unistd.h>
#include <stdlib.h>
#include <string.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <arpa/inet.h>
#include <signal.h>
 
int serverSocket;
void hand(int val){
	//5. 关闭serverSocket
	close(serverSocket);
	printf("bye bye!\n");
	exit(0);
}
 
int main(int argc,char* argv[]){
 
	if(argc != 3) printf("请输入ip地址和端口号!\n"),exit(0);
	printf("ip:%s    port:%d\n",argv[1],atoi(argv[2]));
 
	signal(SIGINT,hand);
 
	//1. 创建socket  参数一: 协议类型(版本) 参数二: 通信媒介 参数三: 保护方式
	serverSocket = socket(AF_INET,SOCK_DGRAM,0);
	if(-1 == serverSocket) printf("创建socket失败:%m\n"),exit(-1);
	printf("创建socket成功!\n");
 
	//2. 创建服务器协议地址簇
	struct sockaddr_in sAddr = {0};
	sAddr.sin_family = AF_INET; //协议类型 和socket函数第一个参数一致
	sAddr.sin_addr.s_addr = inet_addr(argv[1]); //将字符串转整数
	sAddr.sin_port = htons(atoi(argv[2]));  //整数转整数 小端转大端
 
	//3.绑定
	int r = bind(serverSocket,(struct sockaddr*)&sAddr,sizeof sAddr);
	if(-1 == r) printf("绑定失败:%m\n"),close(serverSocket),exit(-2);
	printf("绑定成功!\n");
	
	//4.通信
	char buff[256];
	struct sockaddr_in cAddr = {0};
	int len = sizeof(cAddr);
 
	while(1){
		//如果还需要向客户端发送东西用recvfrom
		//udp精髓  向一个协议地址簇发东西
		
		//收消息
		r = recvfrom(serverSocket,buff,255,0,(struct sockaddr*)&cAddr,&len);
		if(r > 0){
			buff[r] = 0;  //添加字符串结束符号
			printf(">> %s\n",buff);
		}
		printf("你想对客户端说什么: ");
			memset(buff,256,0);
			scanf("%s",buff);
			sendto(serverSocket,buff,strlen(buff),0,
				(struct sockaddr*)&cAddr,sizeof cAddr);
	}
 
	return 0;
}

7.2.2 Client端
//Client

#include <stdio.h>
#include <unistd.h>
#include <stdlib.h>
#include <string.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <arpa/inet.h>
#include <signal.h>
 
int clientSocket;
void hand(int val){
	//4. 结束
	close(clientSocket);
	printf("bye bye!\n");
	exit(0);
}
 
int main(int argc,char* argv[]){
	if(argc != 3) printf("请输入ip地址和端口号!\n"),exit(0);
	printf("ip:%s    port:%d\n",argv[1],atoi(argv[2]));
 
	signal(SIGINT,hand);
 
	//1. 创建socket  参数一: 协议类型(版本) 参数二: 通信媒介 参数三: 保护方式
	clientSocket = socket(AF_INET,SOCK_DGRAM,0);
	if(-1 == clientSocket) printf("创建socket失败:%m\n"),exit(-1);
	printf("创建socket成功!\n");
	//2. 创建服务器协议地址簇
	struct sockaddr_in cAddr = {0};
	cAddr.sin_family = AF_INET; //协议类型 和socket函数第一个参数一致
	cAddr.sin_addr.s_addr = inet_addr(argv[1]); //将字符串转整数
	cAddr.sin_port = htons(atoi(argv[2]));  //整数转整数 小端转大端
	
	//3.通信
	char buff[256];
	char temp[256];
	int r;
	int len = sizeof cAddr;
	while(1){
		//发消息
		printf("你想发送什么: ");
		scanf("%s",buff);
 
		sendto(clientSocket,buff,strlen(buff),0,
			(struct sockaddr*)&cAddr,len);
		
		//收消息
		r = recvfrom(clientSocket,temp,255,0,
			(struct sockaddr*)&cAddr,&len);
 
		if(r > 0){
			temp[r] = 0;
			printf("服务器发来信息>> %s\n",temp);
		}
 
	}
 
	return 0;
}

这样就实现了傻瓜式的一应一答的双向通信

7.3 UDP实现文件传输
7.3.1 Server(文件接收)端
//Server端(文件接收)

#include <stdio.h>
#include <unistd.h>
#include <stdlib.h>
#include <string.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <arpa/inet.h>
#include <fcntl.h>
 
int serverSocket;
 
int main(){
 
	//1. 创建socket  
	serverSocket = socket(AF_INET,SOCK_DGRAM,0);
	if(-1 == serverSocket) printf("创建socket失败:%m\n"),exit(-1);
	printf("创建socket成功!\n");
 
	//2. 创建服务器协议地址簇
	struct sockaddr_in sAddr = {0};
	sAddr.sin_family = AF_INET; //协议类型 和socket函数第一个参数一致
	sAddr.sin_addr.s_addr = inet_addr("127.0.0.1"); //将字符串转整数
	sAddr.sin_port = htons(9527);  
 
	//3.绑定
	int r = bind(serverSocket,(struct sockaddr*)&sAddr,sizeof sAddr);
	if(-1 == r) printf("绑定失败:%m\n"),close(serverSocket),exit(-2);
	printf("绑定成功!\n");
	
	//4.通信(实现文件传输)
	struct sockaddr_in cAddr = {0};
	char fileName[256] = {0};
	int fileSize = 0;
	char buff[1024] = {0};
	int fileCount; //统计写入文件内容的大小
	int len = sizeof(cAddr);
 
	sleep(2);
	//4.1 接收文件名
	r = recvfrom(serverSocket,fileName,255,0,
		(struct sockaddr*)&cAddr,&len);
	if(r > 0){
		printf(">>>>>>%d\n",r);
		printf("接收到的文件名为: %s\n",fileName);
	}
 
	sleep(2);
	//4.2 接收文件大小
	r = recvfrom(serverSocket,(int*)&fileSize,4,0,
		(struct sockaddr*)&cAddr,&len);
	if(r == 4){
		printf("文件大小r>>> %d\n",r);
		printf("接收到的文件大小为: %d\n",fileSize);
	}
	//4.3 创建文件
	int fd = open(fileName,O_CREAT | O_WRONLY,0666);
	if(-1 == fd) printf("创建文件失败:%m\n"),
		close(serverSocket),exit(-4);
 
	sleep(2);
	//4.4 接收信息并写入文件
	while(1){
		r = recvfrom(serverSocket,buff,1024,0,
			(struct sockaddr*)&cAddr,&len);
		if(r > 0){
			write(fd,buff,r);
			fileCount += r;
			if(fileCount >= fileSize)
				break;
		}
	}
 
	//5. 关闭serverSocket
	sleep(1);
	close(fd);
	close(serverSocket);
	printf("bye bye!\n");
 
	return 0;
}

7.3.2 Client(文件发送)端
//Client端(文件发送)

#include <stdio.h>
#include <unistd.h>
#include <stdlib.h>
#include <string.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <arpa/inet.h>
#include <fcntl.h>
#include <sys/stat.h>
 
 
int clientSocket;
 
int main(int argc,char* argv[]){
 
	//1. 创建socket  
	clientSocket = socket(AF_INET,SOCK_DGRAM,0);
	if(-1 == clientSocket) printf("创建socket失败:%m\n"),exit(-1);
	printf("创建socket成功!\n");
 
	//2. 创建服务器协议地址簇
	struct sockaddr_in cAddr = {0};
	cAddr.sin_family = AF_INET; //协议类型 和socket函数第一个参数一致
	cAddr.sin_addr.s_addr = inet_addr("127.0.0.1"); //将字符串转整数
	cAddr.sin_port = htons(9527);  //小端转大端
	
	//3.通信(文件发送)
	//3.1 打开文件
	int fd = open(argv[1],O_RDONLY,0666);
	if(-1 == fd) printf("文件打开失败:%m\n"),close(clientSocket),exit(-3);
	printf("文件打开成功!\n");
 
	//3.1 获取文件大小
	struct stat st = {0};
	stat(argv[1],&st);
	printf("文件大小为: %d\n",(int)st.st_size);
	printf("文件名为:%s\n",argv[1]);
 
	sleep(2);
	//3.2 将文件名和文件大小发送给服务器(注意先后顺序)
	sendto(clientSocket,argv[1],strlen(argv[1]),0,
		(struct sockaddr*)&cAddr,sizeof cAddr);
 
	sleep(2);
	sendto(clientSocket,(char*)&st.st_size,4,0,
		(struct sockaddr*)&cAddr,sizeof cAddr);
 
	//3.3 读取内容并发送
	sleep(2);
	char buff[1024] = {0};
	while(1){
		int r = read(fd,buff,1024);
		if(r > 0)
			sendto(clientSocket,buff,r,0,
				(struct sockaddr*)&cAddr,sizeof cAddr);
		else
			break;
	}
 
	//4. 文件传输完成
	sleep(1);
	close(fd);
	close(clientSocket);
	printf("bye bye!\n");
 
	return 0;
}

8. TCP通信与UDP通信的优缺点

8.1 TCP通信优缺点
8.1.1 优点
TCP可以建立稳定的连接,并且可靠,稳定 TCP的可靠体现在TCP在传递数据之前,会有三次握手来建立连接,而且在数据传递时,有确认、窗口、重传、拥塞控制机制,在数据传完后,还会断开连接用来节约系统资源。

8.1.2 缺点
数据传输速率慢,效率低,占用系统资源高,易被攻击 TCP在传递数据之前,要先建连接,这会消耗时间,而且在数据传递时,确认机制、重传机制、拥塞控制机制等都会消耗大量的时间,而且要在每台设备上维护所有的传输连接,事实上,每个连接都会占用系统的CPU、内存等硬件资源。 而且,因为TCP有确认机制、三次握手机制,这些也导致TCP容易被人利用,实现DOS、DDOS、CC等攻击。

8.2 UDP通信优缺点
8.2.1 优点
数据传输速率快,比TCP稍安全 UDP没有TCP的握手、确认、窗口、重传、拥塞控制等机制,UDP是一个无状态的传输协议,所以它在传递数据时非常快。没有TCP的这些机制,UDP较TCP被攻击者利用的漏洞就要少一些。

8.2.2 缺点
不能像TCP那样建立稳定的连接并且不可靠,不稳定 因为UDP没有TCP那些可靠的机制,在数据传递时,如果网络质量不好,就会很容易丢包。

原文链接:https://blog.csdn.net/ShiXiAoLaNga/article/details/123763323

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

Linux C/C++之TCP / UDP通信 的相关文章

  • 错误:命令“c++”失败,退出状态为 1

    所以我尝试按照以下说明安装 Pyv8https andrewwilkinson wordpress com 2012 01 23 integrating python and javascript with pyv8 https andre
  • Python将文件从Linux复制到WIndows

    我正在构建一个网站 该网站有一个表单 可以捕获用户数据并在用户数据上运行一些cgi cgi 的第一步是需要将文件从 Linux Web 服务器复制到 Windows 计算机 服务器将使用 Active Directory 角色帐户作为复制凭
  • 使用c在linux上分块读写

    我有一个 ASCII 文件 其中每一行都包含一个可变长度的记录 例如 Record 1 15 characters Record 2 200 characters Record 3 500 characters Record n X cha
  • 裸机交叉编译器输入

    裸机交叉编译器的输入限制是什么 比如它不编译带有指针或 malloc 的程序 或者任何需要比底层硬件更多的东西 以及如何才能找到这些限制 我还想问 我为目标 mips 构建了一个交叉编译器 我需要使用这个交叉编译器创建一个 mips 可执行
  • 如何反汇编、修改然后重新组装 Linux 可执行文件?

    无论如何 这可以做到吗 我使用过 objdump 但它不会产生我所知道的任何汇编器都可以接受的汇编输出 我希望能够更改可执行文件中的指令 然后对其进行测试 我认为没有任何可靠的方法可以做到这一点 机器代码格式非常复杂 比汇编文件还要复杂 实
  • 为什么docker容器提示“权限被拒绝”?

    我使用以下命令来运行 docker 容器 并从主机映射目录 root database 到容器 tmp install database docker run it name oracle install v root database t
  • SMP 上如何处理中断?

    SMP 对称多处理器 多核 机器上如何处理中断 内存管理单元是只有一个还是多个 假设两个线程 A 和 B 运行在不同的内核上 同时 访问页表中不存在的内存页面 在这种情况下 将会出现页面错误 并从内存中引入新页面 将会发生的事件的顺序是什么
  • 如何在perl中使用O_ASYNC和fcntl?

    我想使用 O ASYNC 选项 当管道可以读取时 SIGIO 的处理程序将运行 但以下代码不起作用 任何人都可以帮助我吗 bin env perl use Fcntl SIG IO sub print catch SIGIO n my fl
  • 完整的 C++ i18n gettext()“hello world”示例

    我正在寻找完整的 i18ngettext 你好世界的例子 我已经开始了一个基于的脚本使用 GNU gettext 的本机语言支持教程 https web archive org web 20130330233819 http oriya s
  • 运行 shell 命令并将输出发送到文件?

    我需要能够通过 php 脚本修改我的 openvpn 身份验证文件 我已将我的 http 用户设置为免通 sudoer 因为这台机器仅在我的家庭网络中可用 我目前有以下命令 echo shell exec sudo echo usernam
  • 如何在特定的Java版本上运行应用程序?

    如何运行具有特定 Java 版本的应用程序 我安装了三个 Java 版本 myuser mysystem sudo update alternatives config java There are 3 choices for the al
  • 错误号:11,资源暂时不可用

    我正在使用 c 套接字来实现可靠的 UDP 协议 我正在使用以下代码在等待确认的套接字上设置超时 我不确定为什么会收到 errno 11 资源暂时不可用 set timer for recv socket struct timeval tv
  • 在嵌入式系统上将内核控制台发送到哪里?

    我正在开发一个嵌入式系统 该系统当前通过串行端口 1 上的控制台输出启动 Linux 使用启动加载程序中的控制台启动参数 然而 最终我们将使用这个串行端口 内核控制台输出的最佳解决方案是什么 dev null 能否以某种方式将其放在 pty
  • 为什么 call_usermodehelper 大多数时候都会失败?

    从内核模块中 我尝试使用 call usermodehelper 函数来执行可执行文件 sha1 该可执行文件将文件作为参数并将文件的 SHA1 哈希和写入另一个文件 名为输出 可执行文件完美运行 int result 1 name hom
  • 由于 abi::cxx11 符号导致的链接问题?

    我们最近收到一份报告 因为GCC 5 1 libstdc 和双 ABI http gcc gnu org onlinedocs libstdc manual using dual abi html 它似乎Clang 不知道 GCC 内联名称
  • 如何指定配置脚本的包含目录

    我的工作场所有一个 Linux 系统 其中包含相当旧的软件包 并且没有 root 访问权限 我正在从源代码编译我需要的包 prefix somewhere in homedir 我的问题是我只是不知道如何说服配置在特定目录中查找头文件 源码
  • 如何通过不同的接口路由 TCP/IP 响应?

    我有两台机器 每台机器都有两个有效的网络接口 一个以太网接口eth0和 tun tap 接口gr0 目标是使用接口在机器 A 上启动 TCP 连接gr0但然后让机器 B 的响应 ACK 等 通过以太网接口返回 eth0 因此 机器 A 发出
  • 了解 netty 通道缓冲区和水印

    我正在尝试了解网络缓冲区和水印 作为一个测试用例 我有一个 netty 服务器 它向客户端写入数据 客户端被阻止 基本上每次读取之间有 10 秒的睡眠时间 在正常 I O 下 如果接收方被阻塞 TCP 发送方将受到限制 由于流量控制 发送速
  • 有没有办法提高linux管道的性能?

    我正在尝试使用 64 位将超高速数据从一个应用程序传输到另一个应用程序CentOS http en wikipedia org wiki CentOS6 我使用以下方法进行了基准测试dd发现阻碍我的是管道而不是程序中的算法 我的目标是达到
  • 使用 InputStream 通过 TCP 套接字接收多个图像

    每次我从相机捕获图像时 我试图将多个图像自动从我的 Android 手机一张一张地发送到服务器 PC 问题是read 函数仅在第一次时阻塞 因此 从技术上讲 只有一张图像被接收并完美显示 但在那之后当is read 回报 1 该功能不阻塞

随机推荐

  • 使用驱动器中J:的光盘之前需要将其格式化。

    http tieba baidu com p 3203627680 不知道神马原因致使U盘无法打开 大家千万注意 xff1a 以后遇见这种情况千万别格式化 xff08 当然如果你的U盘或者硬盘里没有重要东西那就另当别论 xff09 xff0
  • 404、500、502等HTTP状态码介绍

    一些常见的状态码为 xff1a 200 服务器成功返回网页 404 请求的网页不存在 503 服务不可用 详细分解 xff1a 1xx xff08 临时响应 xff09 表示临时响应并需要请求者继续执行操作的状态代码 代码 说明 100 x
  • 2020年电赛题目,命题专家权威解析!

    关注 星标公众号 xff0c 直达精彩内容 来源 xff1a 德州仪器TI校园计划 大学生电子设计竞赛培训网上次发了关于电赛题目前三道题目解析的视频 xff1a 2020年电赛题目 xff0c 命题专家们怎么看 xff1f xff0c 这篇
  • php curl请求信息和返回信息设置代码实例

    在用curl抓取网页内容的时候 xff0c 经常要知道 xff0c 网页返回的请求头信息 xff0c 和请求的相关信息 xff0c 特别是在请求过程中存在重定向的时候获取请求返回头信息对分析请求内容很有帮助 下面就是一个请求中存在重定向的例
  • URL特殊字符转义

    问题描述 xff1a 在工作中 xff0c 因为需要将另外一个系统的一批产品转移到自己系统 xff0c 产品基础资料什么的 xff0c 都没问题 xff0c 直接给字段插入数据库就好 xff0c 但是遇到了图片的问题 xff0c 图片是在别
  • PHP中GET/POST方法参数传递空格+逗号等特殊字符处理办法

    自己在项目开发中写了个自用接口 xff0c 用GET方法传参 xff08 用户名和密码 xff09 最近收到用户反馈 xff1a 密码为特殊字符时会出错 我一开始想是不是php的mysql real escape string函数将特殊字符
  • canvas 背景透明

    theCanvas 61 document getElementById 39 canvasOne 39 var context 61 theCanvas getContext 39 2d 39 context fillStyle 61 3
  • Http压力测试工具HttpTest4Net

    HttpTest4Net是一款基于C 实现的和HTTP压力测试工具 通过工具可以简单地对HTTP服务进行一个压力测试 虽然VS NET也集成了压力测试项目 但由于VS自身占用的资源导致了在配置不高的PC上难以做到高并发压力测试 再加上需要装
  • PHP获取今天、昨天、明天的日期

    php view plain copy lt php echo 34 今天 34 date 34 Y m d 34 34 lt br gt 34 echo 34 昨天 34 date 34 Y m d 34 strtotime 34 1 d
  • Http协议与TCP协议简单理解

    https blog csdn net sundacheng1989 article details 28239711 在C 编写代码 xff0c 很多时候会遇到Http协议或者TCP协议 xff0c 这里做一个简单的理解 TCP协议对应于
  • LINUX重启MYSQL的命令

    LINUX重启MYSQL的命令 标签 xff1a mysqllinuxservice脚本web服务server 2010 06 25 10 21 62152人阅读 评论 0 收藏 举报 分类 xff1a Linux xff08 6 xff0
  • PHP:curl模拟form表单上传文件

    lt form action 61 34 34 method 61 34 post 34 enctype 61 34 multipart form data 34 gt lt input type 61 34 file 34 name 61
  • HTTP状态码大全

    1 信息类 xff1a 表示接收到请求并且继续处理 100 客户必须继续发出请求 101 客户要求服务器根据请求转换HTTP协议版本 2 响应成功 xff1a 表示动作被成功接收 理解和接受 200 表明该请求被成功地完成 xff0c 所请
  • 如何准备电赛?19年电赛经验总结!

    关注 星标公众号 xff0c 直达精彩内容 写在前面的话 最近忙着各大厂的实习面试 xff0c 趁着准备简历的功夫回顾了一下19年电赛的比赛经历 xff0c 总体来说还算说得过去 现在把我参加电赛的经验分享出来 xff0c 希望对之后的学弟
  • Arduino(5) 使用Mega2560设计上下位机串口通信系统的下位机

    前言 因项目需求 xff0c 我们要从PC端去控制一些外部设备 xff0c 比如激光器 光放大器等 xff0c 这些设备一般使用到的都是低速的串口通信 xff0c 所以我们需要设计一个上下位机串口通信系统来控制这些设备 这篇文章先讲如何使用
  • vue地址去掉 #

    vue router 设置 history 模式 vue 项目往往会搭配 vue router 官方路由管理器 xff0c 它和 vue js 的核心深度集成 xff0c 让构建单页面应用变得易如反掌 vue router 默认为 hash
  • Jetson Nano 入坑之路 ---- (6)GPIO使用(输入输出与回收)

    1 安装 Jetson GPIO 库 Jetson GPIO库 已经预装在Nano xff0c 如果卸载或者丢失 xff0c 就需要自己重新安装一次了 sudo pip install Jetson GPIO sudo pip3 insta
  • Liunx下的Cmake编译C/C++程序方法精要

    前言 我们在很多第三方库中都能够看到CMakeLists txt的身影 这就是我们熟悉的Cmake编译方法所需要的文件 本篇博客就来讲解一下此文件大致需要如何撰写和使用 如果后续有需要 xff0c 会再写个 详解 本例程是笔者项目中所用的内
  • FPGA入门实验-基于状态机实现串口回环收发

    任务目标 基于状态机实现串口回环收发 最近生产实习的FPGA培训课程内容 xff0c 还是挺简单的 具体原理其他文章应该都烂大街了 xff0c 重点是状态机的写法 xff0c 还是很少博主写 xff0c 没怎么看到 xff0c 基本上都是时
  • Linux C/C++之TCP / UDP通信

    目录 1 什么是网络 1 1 网络的定义 1 2 网络的实质 1 3 主机的类型 1 4 信息的传递 2 网络分层 2 1 五层模型 2 2 七层模型 xff08 OSI Open System Interconnection xff09