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# P2P聊天应用程序设计

    我想创建一个不使用显式服务器的简单聊天应用程序 主要要求是用户可以同时与许多朋友聊天 就像在 Skype 等上一样 我在这里指的不是会议聊天 而是多个单独的聊天窗口 目前 我只想要一个 LAN 消息应用程序 但如果设计能够轻松扩展到 Int
  • 在本地主机上使用相同的 IP 和端口创建套接字

    我在 Linux 上看到奇怪的行为 我看到远程端和本地端都显示相同的 IP 和端口组合 以下是 netstat 输出 netstat anp 网络统计grep 6102 tcp 0 0 139 185 44 123 61020 0 0 0
  • 使用脚本检查 git 分支是否领先于另一个分支

    I have branch1 and branch2我想要某种 git branch1 isahead branch2 这将显示如果branch1已承诺branch2没有 也可能指定这些提交 我无法检查差异原因branch2 is在之前br
  • 如何从 Bash 命令行在后台 Vim 打开另一个文件?

    我正在从使用 Gvim 过渡到使用控制台 Vim 我在 Vim 中打开一个文件 然后暂停 Vim 在命令行上运行一些命令 然后想返回到 Vim Ctrl Z 在正常模式下 暂停 Vim 并返回到控制台 fg可用于将焦点返回到 Vim job
  • 为什么 OS X 和 Linux 之间的 UTF-8 文本排序顺序不同?

    我有一个包含 UTF 8 编码文本行的文本文件 mac os x cat unsorted txt foo foo 津 如果它有助于重现问题 这里是文件中确切字节的校验和和转储 以及如何自己生成文件 在 Linux 上 使用base64 d
  • BASH:输入期间按 Ctrl+C 会中断当前终端

    我的 Bash 版本是 GNU bash version 4 3 11 1 release x86 64 pc linux gnu 我有一段这样的代码 while true do echo n Set password read s pas
  • 从 Docker 容器发送多播数据包(到多播组)

    我有一个通过 UDP 多播发送消息的应用程序 我一直试图将其放在 docker 下 我在尝试从 Docker 容器发送多播数据包时遇到了很大的阻力 我已经能够通过 net host运行 docker 容器的选项 然而 我想坚持使用桥接配置
  • 嵌入清单文件以要求具有 mingw32 的管理员执行级别

    我正在 ubuntu 下使用 i586 mingw32msvc 交叉编译应用程序 我很难理解如何嵌入清单文件以要求 mingw32 具有管理员执行级别 对于我的例子 我使用了这个hello c int main return 0 这个资源文
  • 如何从 C++ 程序中重新启动 Linux?

    我有一个 Qt 4 GUI 我需要在下拉菜单中提供一个选项 允许用户选择重新启动计算机 我意识到这对于以其他方式重新启动计算机的能力来说似乎是多余的 但选择需要保留在那里 我尝试使用 system 来调用以下内容 suid root she
  • Java 客户端到服务器未知来源

    我有一个简单的乒乓球游戏 需要通过网络工作 服务器将创建一个带有球和 2 个球棒位置的游戏 当客户端连接到服务器时 服务器将创建一个名为 PongPlayerThread 的新类 它将处理客户端到服务器的输入和输出流 我的服务器工作100
  • ssh 连接超时

    我无法在 git 中 ssh 到 github bitbucket 或 gitlab 我通常会收到以下错误消息 如何避免它 输出 ssh T email protected cdn cgi l email protection i ssh
  • Tomcat Intellij Idea:远程部署

    RackSpace 云服务器 Ubuntu 12 04 Intellij Idea 11 1 2 Windows 8 Tomcat 7 0 26 JDK 6 在 Intellij Idea 上 当我尝试在远程 Tomcat 7 服务器上运行
  • 有没有一种快速方法可以从 Jar/war 中删除文件,而无需提取 jar 并重新创建它?

    所以我需要从 jar war 文件中删除一个文件 我希望有类似 jar d myjar jar file I donot need txt 的内容 但现在我能看到从 Linux 命令行执行此操作的唯一方法 不使用 WinRAR Winzip
  • 如何使用 JSch 将多行命令输出存储到变量中

    所以 我有一段很好的代码 我很难理解 它允许我向我的服务器发送命令 并获得一行响应 该代码有效 但我想从服务器返回多行 主要类是 JSch jSch new JSch MyUserInfo ui new MyUserInfo String
  • 适用于 Linux 的轻量级 IDE [关闭]

    就目前情况而言 这个问题不太适合我们的问答形式 我们希望答案得到事实 参考资料或专业知识的支持 但这个问题可能会引发辩论 争论 民意调查或扩展讨论 如果您觉得这个问题可以改进并可能重新开放 访问帮助中心 help reopen questi
  • 对卡在 CLOSE_WAIT 状态的连接进行故障排除

    我有一个在 Windows 上的 WebLogic 11g 中运行的 Java 应用程序 几天后它变得没有响应 我注意到的一个可疑症状是大量连接 大约 3000 个 出现在netstat即使服务器空闲 也具有 CLOSE WAIT 状态 由
  • Google BQ:运行参数化查询,其中参数变量是 BQ 表目标

    我正在尝试从 Linux 命令行为 BQ 表目标运行 SQL 此 SQL 脚本将用于多个日期 客户端和 BQ 表目标 因此这需要在我的 BQ API 命令行调用中使用参数 标志 parameter 现在 我已经点击此链接来了解参数化查询 h
  • 在 .gitconfig 中隐藏 GitHub 令牌

    我想将所有点文件存储在 GitHub 上 包括 gitconfig 这需要我将 GitHub 令牌隐藏在 gitconfig 中 为此 我有一个 gitconfig hidden token 文件 这是我打算编辑并放在隐藏令牌的 git 下
  • 我们真的应该使用 Chef 来管理 sudoers 文件吗?

    这是我的问题 我担心如果 Chef 破坏了 sudoers 文件中的某些内容 可能是 Chef 用户错误地使用了说明书 那么服务器将完全无法访问 我讨厌我们完全失去客户的生产服务器 因为我们弄乱了 sudoers 文件并且无法再通过 ssh
  • 向现有 TCP 和 UDP 代码添加 SSL 支持?

    这是我的问题 现在我有一个 Linux 服务器应用程序 使用 C gcc 编写 它与 Windows C 客户端应用程序 Visual Studio 9 Qt 4 5 进行通信 是什么very在不完全破坏现有协议的情况下向双方添加 SSL

随机推荐

  • 使用驱动器中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