参考博主

http://t.csdn.cn/9ldOh

http://t.csdn.cn/9VpGz

http://t.csdn.cn/QsYdv

感谢博主。

TCP/IP 是互联网的基础, TCP代表传输控制协议,IP代表互联网协议。目前有两个版本IP,一个是32位地址的IPv4 和一个是128位的 IPv6 。而IPv4 是现如今使用最多的IP版本,也是这次讨论的重点。

一、IP主机和IP地址

    每一个注意由一个32位的IP地址来标识。为了方便起见,通常用32位的IP低质号用记点法标识例如:134.121.64.1  也可以用主机名标识如 dns1.eec.wsu.edu 。实际上应用程序通常使用主机名而不是IP地址。因为给定其中一个,我们都可以通过dns(域名系统)服务器找到另外一个,两者之间可以相互转换。

IP地址分为两部分 NeiworkID 和 HostID 字段。其中,IP 可以分为A~E类。例如B类IP分为一个16位NeiworkID,前两位是10 。发往UP地址的数据包首先被发送到具有相同networkID的路由器默认IP地址位127.0.0.1.

二、IP数据包格式

 
      IP数据包由IP头、发送方IP地址、接收方IP地址和数据组成。每个IP数据包的大小最大为64K。IP头包含有关数据包的信息。内容如下:   

     IP主机可能距离很远通常不可能从一个主机直接向另一个主机发送数据包。路由器是转发数据包的特殊IP主机,它可以向普通IP主机和其他路由器发送数据包。

三、TCP/IP在网络中的数据流

  应用层的数据被传到传输层会添加TCP 或者UDP包头来标识使用的传输协议。合并后的数据被传到IP网络层,添加一个包含IP地址的IP报头来标识发送和接收主机。然后合并后的数据传递到网络链路层,再次将数据分成多个帧,添加发送和接收网络的地址,用于在物理网络之间的传输。

四、套接字编程

服务器套接字编程步骤如下:

1.创建socket;
2.绑定socket和端口号;
3.监听端口号;             (UDP省略)
4.接收来自客户端的连接请求;(UDP省略)
5.从socket中读取字符;
6.发送消息回客户机。

客户端套接字编程步骤如下: 

1.创建socket;
2.连接指定计算机的端口; (UDP省略)
3.向socket中写入信息;
4.从服务器接收消息。

在 netdb.h 和 sys/socket.h中有套接字的地址结构定义

struct sockaddr_in {
   sa_family_t sin_family;  //TCP/IP网络的sin_family 始终设置为AF_INET
   in_port_t sin_port;       //包含网络字节顺序排列的端口号
   struct in_addr sin_addr ;   //按网络字节顺序排列的IP地址
}
 
struct in_addr{        
   unit32_t s_addr;     //按网络字节顺序排列的IP地址
}

4.1 创建套接字

int  socket(int domain, int type, int protocol);


4.2绑定socket和端口号 

int bind(int sockfd, const struct sockaddr *addr, socklen_t addrlen);

     bind系统调用将addr指定的地址分配文件描述符 sockfd所引用的套接字,addrlen指定addr所指向地址结构的大小对于用于联系其他UDP服务器主机的UDP套接字,必须绑定到客户机地址,允许服务器发回应答。对于接收客户机的TCP套接字,必须先将其绑定到服务器主机地址。

4.3、UDP 套接字

将缓冲区中len字节数据发送到dest_addr标识的目标主机:

ssize_t sendto(int fd, const void *buf,size_t len,int flags,const struct sockaddr *dest_addr,socklen_t tolen);

从缓冲区中len字节数接收数据:

ssize_t recvfrom(int fd, void *buf, size_t len,int flags,struct sockaddr *src_addr, socklen_t *len);

4.4 TCP 套接字


  在绑定socket 和端口号后  TCP服务器用 listen 和 accpet 来监听、接受客户机的连接。

//backlog 定义了等待连接的最大长度
int listen(int sockfd, int backlog);
 
 
//提取等待连接队列上的第一个连接请求同于监听sockfd,执行时造成进程阻塞,直到客户机通过connect建立连接
int accept(int sockfd, struct sockaddr *addr, socklen_t *addrlen); //  返回新的文件描述符
 
//如果sockfd 时SOCK_DGRAM (USD 套接字)类型时,addr时发送数据报的默认地址,也是接收数据报的唯一地址。如果时 SOCK_STREAM (TCP 套接字)类型时,connect连接到绑定到addr指定的套接字
int connect(int sockfd, const struct sockaddr *addr, socklen_t addrlen);

发送接收数据,可以使用  send/read   或者 recv/write  来接收和发送数据。read 和 write  是对文件描述符的读取和写入。

//对已经连接的fd 发送数据 ,flags 通常是0 
ssize_t send(int fd , const void *buf , size_t len , int flags);
 
//对已经连接的fd 接收数据 ,flags 通常是0 
ssize_t recv(int fd , void *buf , size_t len , int flags);

 五、传输层协议之TCP通信

5.1 TCP通信编程模型

5.2 TCP实现简单通信

5.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;
}

5.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;
}

5.3 TCP实现文件传输

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

5.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;
}

5.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;
}

测试结果如图:

 六、 传输层协议之UDP通信

6.1 UDP通信编程模型

6.2 UDP实现简单通信

6.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;
}

 6.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;
}

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

6.3 UDP实现文件传输

6.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;
}

6.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;
}

 测试结果如下:

七、 TCP通信与UDP通信的优缺点

7.1 TCP通信优缺点

7.1.1 优点

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

7.1.2 缺点

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

7.2 UDP通信优缺点

7.2.1 优点

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

7.2.2 缺点

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

八、使用${CROSS_COMPILE}编译各个程序

8.1 配置环境(临时)

export ARCH=arm
export CROSS_COMPILE=arm-linux-gnueabihf-
export PATH=$PATH:/home/suliu/qemu/100ask/100ask_imx6ull-qemu/ToolChain/gcc-linaro-6.2.1-2016.11-x86_64_arm-linux-gnueabihf/bin

8.2 编译

arm-linux-gnueabihf-gcc -o server.o server.c   //arm下运行的程序
arm-linux-gnueabihf-gcc -o client.o client.c
gcc -o server.o server.c   //ubuntu下运行的程序
gcc -o client.o client.c

在开发板内mount nfs,并运行各个程序;理解运行状态

8.3服务器端(ubuntu主机)

创建根目录和共享挂载点

sudo mkdir -p /srv/nfs4/www

将挂载目录绑定到共享挂载点

sudo mount --bind /home/suliu/Desktop/tcp/ /srv/nfs4/www

导出文件系统
打开/etc/exports文件

sudo vim /etc/exports

添加以下行

/srv/nfs4 127.0.0.1(rw,nohide,insecure,no_subtree_check,async,no_root_squash)
/srv/nfs4/www 127.0.0.1(rw,nohide,insecure,no_subtree_check,async,no_root_squash)

保存文件并导出共享

sudo exportfs -ar

查看当前活动的导出及其状态

exportfs -v
/srv/nfs4       127.0.0.1(rw,async,wdelay,nohide,insecure,no_root_squash,no_subtree_check,sec=sys,rw,insecure,no_root_squash,no_all_squash)
/srv/nfs4/www   127.0.0.1(rw,async,wdelay,nohide,insecure,no_root_squash,no_subtree_check,sec=sys,rw,insecure,no_root_squash,no_all_squash)

在服务器端执行下面命令,强制重新读取/etc/exports文件

[root@localhost log]# exportfs -ra
[root@localhost log]# exportfs

8.4客户端(开发板)

运行开发板

cd /home/suliu/qemu/ubuntu-18.04_imx6ul_qemu_system
./qemu-imx6ull-gui.sh 

查看ip

ifconfig
ens33: flags=4163<UP,BROADCAST,RUNNING,MULTICAST>  mtu 1500
        inet 192.168.1.133  netmask 255.255.255.0  broadcast 192.168.1.255
        inet6 fe80::d8af:2afa:14a3:d96f  prefixlen 64  scopeid 0x20<link>
        ether 00:0c:29:64:d3:91  txqueuelen 1000  (Ethernet)
        RX packets 80442  bytes 77555991 (77.5 MB)
        RX errors 0  dropped 0  overruns 0  frame 0
        TX packets 40343  bytes 7869307 (7.8 MB)
        TX errors 0  dropped 0 overruns 0  carrier 0  collisions 0

lo: flags=73<UP,LOOPBACK,RUNNING>  mtu 65536
        inet 127.0.0.1  netmask 255.0.0.0
        inet6 ::1  prefixlen 128  scopeid 0x10<host>
        loop  txqueuelen 1000  (Local Loopback)
        RX packets 31049  bytes 3439747 (3.4 MB)
        RX errors 0  dropped 0  overruns 0  frame 0
        TX packets 31049  bytes 3439747 (3.4 MB)
        TX errors 0  dropped 0 overruns 0  carrier 0  collisions 0

8.5运行程序(开发板做客户端,主机做服务器)

#服务器(ubuntu)执行.out文件(gcc)
book@book-virtual-machine:/srv/nfs4/www$ ./server.out 
#客户端(ubuntu)执行.o文件(arm-linux-gnueabihf-gcc)
[root@qemu_imx6ul:~/mnt]# ./client.o 10.0.2.2

8.6echo sever

服务端改进

/* 在服务端打印数据后面加上 */
    iRecvLen = send(iSocketClient, ucRecvBuf, strlen(ucRecvBuf), 0);
    if(iRecvLen <= 0)
    {
        close(iSocketClient);
        return -1;
    }
/* 在客户端发送数据后面加上 */
iRecvLen = iRecvLen = recv(iSocketClient, ucRecvBuf, 999, 0);
        if (iRecvLen <= 0)            
        {
            close(iSocketClient); /*一直接受服务器传来的消息*/
            return -1;
        }
        else 
        {
            ucRecvBuf[iRecvLen] = '\0';  /* 加上结束符  */
            printf("Feedback:%s\n", ucRecvBuf);
        }

8.7echo大写

/* 一个完整字符串大写转换函数 */
#include<stdio.h>

int main()
{
    char ch[100];
    int i;
    while(scanf("%c",&ch[i])!=EOF)
    {
        if(ch[i]>='a'&&ch[i]<='z')
                    ch[i]=ch[i]-32;  
                        printf("%c",ch[i]);
    }
    return 0;
}

/* 修改为我们使用的函数 */
int charup(unsigned char ch[1000]);     //声明
charup(ucRecvBuf);                      //调用
int charup(unsigned char ch[1000])
{
    int i = 0;
    while (ch[i] != '\0')
    {
        if(ch[i]>='a'&&ch[i]<='z')
        ch[i]=ch[i]-32;  
        i ++;
    }        
    return 0;
}

Logo

更多推荐