2021-11-07

网络编程第一天

一、网络发展史

**1.网络发展史

苏联与美国冷战的一种产物
2.网络传输原来是不稳定的,不保证数据的完整性
出现了TCP/IP模型
TCP是为了保证数据的完整性**
3.OSI模型(理想)
OSI(open system interconnect):开放式系统互联,是IOS(国际标准化组织)

**OSI模型划分

二、OSI定义了7层框架,

应用层
表示层
会话层
传输层
网络数据链路层
物理层
这7层模型是独立工作的,他们之间互不干扰,通过接口传递信息**

1.应用层 —> 二进制—>大小端模式()
为了给应用程序提供服务,直接面向用户,例如电子邮件,浏览器内容,主要协议是
http(文本传输协议), https(超级文本传输协议), www

2.表示层(对信进行翻译或者加密)
负责: 数据进行编码,转换(加密)

3.会话层(收件人地址,收件人电话)
建立应用链接,选择合适的服务,给对方发送请求链接,获取对方联系方式

4.传输层(送信到快递点)
建立,管理和维护端到端的连接

5.网络层(快递与快递之间的网点)
IP地址和路由的选择

6.数据链路层
提供介质访问和链路管理,将 比特数据 转为 字节(是大端模式), 使用链路地址(MAC)
来访问介质(123-456-789-000)

7.物理层
通过物理介质进行数据创输,电缆,空气(电磁脉冲)、光纤。

4.现实例子
	-----------应用层---------------
		应用层 : 老板需要发送文件给老外
		表示层 : 助理帮老板对文件进行翻译,加密
		会话层 : 前台美女对文件写上收件人的地址,联系方式等等
	-----------内核层---------------
		传输层 : 跑邮局的员工,亲自把把信送到邮局,等待收信(安全),把这种方式称为TCP
												  把信放到邮局直接跑路(不安全),这种方式称为UDP
		网络层 : 各种快递的网点,比如北京(192.168.1.5)到广州(192.168.1.6)需要经过武汉网点(192.168.1.7)
		
	-----------硬件驱动层---------------
		数据链路层与物理层,选择什么快递传输
		

三、TCP/IP模型

1.将应用层,表示层,会话层,合成为应用层
老板自己写信,翻译,写收信人地址

2.传输层(TCP/UDP)
跑邮局

2.网络层

4.数据链路层,物理层

6.数据是如何从应用层到硬件
"用户数据"—>经过应用层–>“应用层头”+“用户数据”
“应用层头”+“用户数据”—>表示层–>“应用层头”+“表示层”+“用户数据”

“应用层头”+“表示层”+“会话层”+“传输层”+…+“数据链路层”+“用户数据”
这样做的好处是保证数据完整性

7.如何实现数据传输
要熟悉传输层与网络层,通过这两层进行数据传输

8.通过设置TCP/UDP协议进行网络通信

1.TCP : 流式协议

安全的传输协议,防止数据丢包,一般用于qq,密码登录
对网络的带宽(网速)较高

2.UDP : 数据报协议

不安全传输协议,可能会导致数据丢包,视频传输,广播和组播
对网络的带宽要求不高

四、如何通过TCP/UDP进行通信

1.通过套接字(socket),将应用层与内核层打通,可以设置数据创输方式


		#include <sys/types.h>    
		#include <sys/socket.h>

		int socket(int domain, int type, int protocol);
		参数 :
			domain : 设置IPV4属性
			type : 选择TCP还是UDP协议
				SOCK_STREAM : TCP协议
				SOCK_DGRAM : UDP协议
				
			protocol : 缺省值,不用的,不开放的协议 默认为 0

		返回值 : 
			成功访问可以访问内核套接字,是一个文件描述符(文件的ID)
			失败返回 -1

2.IP地址与端口

(1)用于主机通信的连接 192.168.xxx.100
(2)所有主机通信必须是同一网段 192.168.xxx
(3)两个通信的程序端口号一致,端口号 是用于确定和哪个主机中的哪个进程间通信 用的
(4)端口号是一个16位整型 0-65535
注意 0 - 1023 是已经被系统使用了,所以用户只能使用 1024 - 65535

五、字节序,大端模式和小端模式测试

	回想大小端模式

小端模式 : 低字节数据存放低地址,高字节数据存放高地址
大断模式 : 低字节数据存放高地址,高字节数据存放低地址

练习 : 测试自己的系统是大端模式还是小端模式

代码


#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <socket.h>

 union {
        short s;
        char c[sizeof(short)];   //char c[2];
    } un;

int main(int argc, char const *argv[])
{
   
    un.s = 0x0102; // 01: 高位   02:低位
    if(sizeof(short)==2) {
        if(un.c[0]==1 && un.c[1] == 2)         //大端序:高位存放低地址
            printf("big-endian\n");
        else if (un.c[0] == 2 && un.c[1] == 1)  //小端序:高位存放高地址
            printf("little-endian\n");
        else
            printf("unknown\n");
    } else
        printf("sizeof(short)= %d\n",sizeof(short));
        
    return 0;
}

小端:较高的有效字节存放在较高的的存储器地址,较低的有效字节存放在较低的存储器地址。
大端:较高的有效字节存放在较低的存储器地址, 较低的有效字节存放在较高的存储器地址。

如果将一个16位的整数0x1234存放到一个短整型变量(short)中。这个短整型变量在内存中的存储在大小端模式由下表所示。

地址偏移 0x12 34
大端模式 小端模式
0x00 低: 12(OP0) 34(OP1)
0x01 高: 34(OP1) 12(OP0)

因为ARM和X86平台都是小端模式,而网络传输是大端模式,不匹配,所以需要将ip和端口号转换为大端模式

字节序转换接口:
		linux: man 3 htons
		h --> host 主机
		to --> 转换
		n --> net 网络
		s --> short 短整型
		#include <arpa/inet.h>
		// 将主机端口号转为网络字节序 长整型(大端模式)
		uint32_t htonl(uint32_t hostlong);
		// 将主机端口号转为网络字节序 短整型	
		uint16_t htons(uint16_t hostshort);
		// 将网络字节序转为主机端口号 长整型(小端模式)
		uint32_t ntohl(uint32_t netlong);
		// 将网络字节序转为主机端口号 短整型
		uint16_t ntohs(uint16_t netshort);
		
		将ip转为网络字节序
			#include <sys/socket.h>
			#include <netinet/in.h>
			#include <arpa/inet.h>
			// 将主机ip转为网络ip(大端模式)
			in_addr_t inet_addr(const char *cp);
			// 将网络ip转为主机ip(小端模式)
			char *inet_ntoa(struct in_addr in);

六、TCP通信流程

实现服务器server.c

1.创建套接字(买手机)
			int socket = socket(AF_INET, SOCK_STREAM, 0); // AF_INET : ipv4 SOCK_STREAM : TCP
			if(socket == -1)
			{
				perror("socket faile");
				return -1;
			}

```bash
2.设置ip和端口号(设置手机卡)
		头文件:linux:         /usr/include/linux/in.h   
		
		struct sockaddr_in serAddr;
		socklen_t len = sizeof(serAddr); // 获取结构体大小
		bzero(&serAddr,sizeof(serAddr));
		serAddr.sin_family = AF_INET; // 设置ipv4 
		serAddr.sin_port = htons(5000); // 将端口号(确定主机的哪个进程通信)转为大端模式
		//serAddr.sin_addr.s_addr = inet_addr("192.168.24.3");// 将ip设置为网络模式(确定和哪一个主机进行通信)
		/* Address to accept any incoming messages. */
		// 自动获取服务器ip
		#define	INADDR_ANY		((unsigned long int) 0x00000000)
		serAddr.sin_addr.s_addr = htonl(INADDR_ANY);
		

```bash
3.绑定手机,绑定的是服务器(rose)自己的ip和端口号
			//int bind(int sockfd, struct sockaddr *my_addr, socklen_t addrlen);
			int ret = bind(socket,(struct sockaddr *)&serAddr,len);	
			if(ret == -1)
			{
				perror("bind faile");
				return -1;
			}
			
4.监听(设置来电显示)	
			listen(socket,5);
			
5.等待连接(电话)
	int accept(int s, struct sockaddr *addr, socklen_t *addrlen);
		参数:
			s : 服务区的socket套接字
			struct sockaddr *addr : 保存的是客户端的ip和端口号
			addrlen : 结构体大小
		返回值 :
			成功会返回已连接的套接字,通过这个套接字和客户端进行通信
			失败返回-1
6.畅聊
			// 发送信息
			#include <sys/types.h>
			#include <sys/socket.h>

			int send(int s, const void *msg, size_t len, int flags);
			参数:
				s : 已连接的套接字,accep()的返回值
				msg : 需要发送的数据
				len : 数据的大小
				flags : 缺省值,默认为0
			返回值:
				成功返回实际发送的内容大小
				失败返回-1
		
			// 接收信息
			ssize_t recv(int sockfd, void *buf, size_t len, int flags);
			参数:
				sockfd : 已连接的套接字,accep()的返回值
				msg : 需要存放接收方的数据
				len : 数据的大小
				flags : 缺省值,默认为0
			返回值:
				成功返回实际接收的内容大小
				失败返回-1
		7.关闭
			close()

实现客户端client

client.c(Jack)
		1.创建套接字(买手机)
			int socket = socket(AF_INET, SOCK_STREAM, 0);
			if(socket == -1)
			{
				perror("socket faile");
				return -1;
			}
2.设置ip和端口号(设置手机卡),注意此处的ip是服务器的ip,端口号(服务器和客户端一致)
		struct sockaddr_in serAddr;
		socklen_t len = sizeof(serAddr); // 获取结构体大小
		bzero(&serAddr,sizeof(serAddr));
		serAddr.sin_family = AF_INET; // 设置ipv4 
		serAddr.sin_port = htons(5000); // 将端口号(确定主机的哪个进程通信)转为大端模式
		serAddr.sin_addr.s_addr = inet_addr(192.168.24.3);// 将ip设置为网络模式(确定和哪一个主机进行通信)
		 
3.建立连接(打电话)
			#include <sys/types.h>          /* See NOTES */
			#include <sys/socket.h>

			int connect(int sockfd, const struct sockaddr *addr,socklen_t addrlen);
			参数 : 
				sockfd : 客户端的套接子
				addr : 保存的是服务器的ip和端口号
				addrlen : 结构体大小
			返回值 : 成功返回正整数
					失败返回 -1

在这里插入图片描述

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

Qt历险记

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值