$ -网络编程LinuxC 基础知识--基本思路

——首先来看一下 TCP/IP 网络分层模型

数据链路层(网络接口层)

网卡接口的网络驱动程序,处理数据在物理媒介上的传输;不同的物理网络具有不同的电气特性,网络驱动程序隐藏实现细节,为上层协议提供一致的接口。

  • 以太网帧格式
    IP数据包交付过程中,在数据链路层会对数据包进行添加报头信息。其实更准确的来说,以太网协议是一个规定数据链路层以及物理层的协议,不能仅仅说是一个数据链路层的协议。
    以太网帧就是将网络层交付的数据添加报头信息之后,此时的数据以帧的形式传递 ,下面是以太网帧格式:
    在这里插入图片描述
    目的地址&源地址都指的是MAC地址,第三个有一个2字节的类型标识,有三种值: ①IP、②ARP、③RARP。
  1. 如果类型码为0800,那么在数据链路层解包完毕后,将数据交付给网络层的IP协议来处理报文。
  2. 如果类型码为0806,那么在向上层交付的时候就交付给ARP协议,将IP地址转换为MAC地址。
  3. 如果类型码为0835,就交付给RARP协议(Reverse ARP),将MAC地址转换成IP地址。

在以太网帧格式的最后还有一个CRC校验码,来校验数据是否异常。

  • APR数据报格式(地址解析协议)
    获取下一跳 路由节点的mac地址
  • RARP 反向地址解析协议
    通过ARP&RARP来实现IP地址与机器物理地址(MAC地址)之间的互相转换。

!!!ARP & RARP 是处于网络层与数据链路层之间的一种协议

网络层(Internet层)

  • IP协议
    逐跳转发模式,根据数据包的目的IP地址决定数据如何发送,如果数据包不能直接发送到目的地,IP协议负责寻找下一个合适的下一跳路由器,并将数据包交付给该路由器转发。 IP协议是网络层最重要的协议。无论传输层使用哪种协议都要通过IP协议来确定到达目的计算机的路由。IP协议规定了在生存期TTL(8位,最大为255)内传送数据,超过生存期就会丢弃数据,再由丢弃数据的路由器向发送者返回一个ICMP超时报文。
  • ICMP协议
    因特网控制报文协议,用于检测网络连接,如果数据在传输过程中出现问题,ICMP协议将产生错误报文。

传输层

为两台主机的应用程序提供端到端的通信。

  • TCP 传输控制协议
    TCP提供一种面向链接的、可靠的基于流的数据传输服务;使用超时重发、数据确认等方式确保数据被正确地发送到目的地。
    TCP 通信过程:
    1. 建立连接 三次握手
      ① 链接的发起端(客户端)向目标计算机(服务器)发送一个请求建立连接的数据包。
      ② 服务器接收到请求后,对同步信号作出响应,并发送自己的同步信号给客户端。
      ③ 客户端对服务器发来的同步信号进行响应,完成之后即->建立连接完成
    2. 关闭
      ① 请求主机发送一个关闭连接给另一方。
      ② 另一方收到关闭连接请求后,发送一个接受请求的确认数据包,并且关闭它的socket链接。
      ③ 请求主机接收到确认数据包后,发送一个确认数据包,告知另一方其发送的确认已经收到,请求主机关闭它的socket链接。
  • UDP 用户数据报协议
    UDP向应用程序提供一种无连接的,基于数据报的服务,该协议通常被用于不需要可靠数据传输的网络环境中,UDP不需要建立连接,也不需要维持链接,所以也就不保证数据报按照顺序正确的到达目的地,由应用程序来完成。

应用层

应用程序逻辑的实现。
主要有ping、telnet、DNS、HTTP、FTP、DHCP等协议


  • IP地址
    IP地址为4字节,32位; 例如这样一个IP地址:‘123.43.11.09‘,它是以字符串形式显示的但是在传输过程中需要转换为(unsigned int)类型,所以它是有传输数据上限的 。

  • IP地址的分类:

    • 首先,IP地址以 点分十进制 表示,地址格式为:
      IP地址=网络地址+主机地址 或者 IP地址=主机地址+子网地址+主机地址
  • 端口
    网络地址是用来识别唯一的每台计算机,但每台计算机上通常都会同时运行更多个应用程序,它们可能要同时访问网络。所以对于同一台计算机上的多个应用程序,TCP和UDP协议采用16位的端口号来识别它们。一台主机上的不同进程可以绑定到不同的端口上,这些进程就可以同时访问网络而互不干扰。
    简单来说,端口号port用来表示一台主机上一个唯一的进程。
    端口号是一个16位无符号整数(0-2^16),(0~65535), 又分为保留端口(知名端口):有权威机构规定用途,其余的为自由端口,用户可以自由申请和使用。

  • C/S 模型
    客户机/服务器 模型,既可以使用TCP协议也可以使用UDP协议,在C/S模型中,通常情况下,服务器的端口号和IP地址是固定的,客户端程序连接到服务器IP和端口,所以一般情况下客户端的程序设计相对要简单一些,服务器要考虑多个客户端同时请求服务的问题。

  • B/S 模型
    浏览器/服务器 模型,用户通过www浏览器实现,三层架构:
    ① 客户端表示层:Web浏览器组成,不存放任何应用程序。
    ② 应用服务器层(事物逻辑层):由一台或者多台服务器组成,具有良好的可扩展性。
    ③ 数据中心(数据处理层):由数据库系统组成,用于存放业务数据。

总的来说,B/S 是一种特殊的具体化的 C/S模型,B/S模型的客户端软件特指浏览器,服务器一般是Web服务器,使用HTTP协议通信。其工作过程是C/S模型的具体化、实例化。


$ socket 套接字

套接字函数:
  • >>>>>>>① socket()函数: 创建套接字

		#include <sys/types.h>
		#include <sys/socket.h>
		int socket(int domain,int type,int protocol);

名空间: 制定套接字的地址格式
- PF_LOCAL 本地名空间:套接字地址为普通文件名
- PF_INET Internet名空间:套接字地址由Internet地址和端口号(用于区分一台主机上的多个套接字)确定

通信类型: 控制套接字如何传输和处理数据包
- SOCK_STREAM 连接(connection)类型:确保所有包依序传输,如果丢包,则请求重传
- SPCK_DGRAM 数据报(datagram)类型:不保证包的到达顺序,包可能丢失

协议: 确定数据如何传输
- 机器会自动选择最佳的协议来进行传输,因此不需要我们自行修改定义,通常传递0 ,让系统自动选择
返回值:
- 一个新的套接字文件描述符

  • >>>>>>>② close()函数: 释放套接字

int close (int fd);
  • >>>>>>>③ connect()函数: 创建两个套接字之间的连接

=> 客户端发起该系统调用,试图与服务器建立套接字连接

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

参数:
- 套接字文件描述符
- 指向套接字地址结构体的指针(服务器地址)
- 服务器地址字符串的长度

返回值:
- 0 表示连接成功、-1 表示连接失败

  • >>>>>>>④ bind() 函数

=> 用来将一个套接字与某个端口以及IP地址绑定

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

参数:
- 可以将my_addr 的 sin_addr 设置为 INADDR_ANY 而不是某个确定的IP地址就可以绑定到任何网络接口。
- 对于只有一个IP地址的计算机,INADDR_ANY 对应的就是它的IP地址;
- 对于多宿主主机(拥有多块网卡),INADDR_ANY 表示本服务器程序将处理来自所有网络接口上相应端口的连接请求

返回值:
- 函数执行成功返回0,有错误发生时返回-1,错误代码存入errno

  • >>>>>>>⑤ listen() 函数

-> 指定同时可以对服务器发起连接请求的最大客户端数量 ,通常默认最大为128(即同时处于三次握手状态的客户端最大数量)

int listen(int s ,int backlog);

= 如果超过最大数量,之后的连接请求将被服务器拒绝

返回值:
- 执行成功返回0,出错返回-1,错误代码去errno

  • >>>>>>>⑥ accept() 函数

=> 接受一个连接请求

int accept(int s, struct sockaddr *addr,socklen_t *addrlen);

参数:
- s :由socket创建,经函数bind绑定到某一端口上,再由listen转化来的监听套接字
- addr :传出 参数,从来保存客户端的主机地址&端口
- addrlen :传入传出参数 ,第二个参数所指向的结构体的大小

返回值:
- 返回一个新的套接字文件标识符,进程可以利用这个新的套接字描述符与客户端交换数据
- 参数 s 所指定的套接字继续等待客户端的链接请求


- 客户端&服务端 基本流程

  • server.c
    1. socket(); 建立套接字
    2. bind(); 绑定IP地址 端口号 (初始化结构体 struct sockaddr_in addr)
    3. listen(); 指定最大同时发起连接请求的客户端数量 默认值128
    4. accept(); 阻塞等待客户端发起连接
    5. read(); 从客户端读取数据
    6. 处理数据
    7. write(); 将处理好的数据写回客户端
      (… 循环读取->处理->写回…)
    8. close(); 关闭套接字
  • client.c
    1. socket(); 建立套接字
    2. bind(); 可以依赖“隐式绑定”
    3. connect(); 发起连接
    4. write();
    5. read();
      (…loops…)
    6. close();
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
网络编程在 ARM-Linux 上与在其他平台上的网络编程基本相同,在 ARM-Linux 上使用的套接字函数库也是基于 BSD Socket 的。下面是一个简单的网络编程实验,可以在 ARM-Linux 上运行。 首先,需要创建一个 TCP 服务器,可以使用以下代码: ```c #include <stdio.h> #include <stdlib.h> #include <string.h> #include <unistd.h> #include <sys/types.h> #include <sys/socket.h> #include <netinet/in.h> #include <arpa/inet.h> #define PORT 8080 int main() { int server_fd, new_socket, valread; struct sockaddr_in address; int opt = 1; int addrlen = sizeof(address); char buffer[1024] = {0}; char *hello = "Hello from server"; // Creating socket file descriptor if ((server_fd = socket(AF_INET, SOCK_STREAM, 0)) == 0) { perror("socket failed"); exit(EXIT_FAILURE); } // Forcefully attaching socket to the port 8080 if (setsockopt(server_fd, SOL_SOCKET, SO_REUSEADDR | SO_REUSEPORT, &opt, sizeof(opt))) { perror("setsockopt"); exit(EXIT_FAILURE); } address.sin_family = AF_INET; address.sin_addr.s_addr = INADDR_ANY; address.sin_port = htons( PORT ); // Forcefully attaching socket to the port 8080 if (bind(server_fd, (struct sockaddr *)&address, sizeof(address))<0) { perror("bind failed"); exit(EXIT_FAILURE); } if (listen(server_fd, 3) < 0) { perror("listen"); exit(EXIT_FAILURE); } if ((new_socket = accept(server_fd, (struct sockaddr *)&address, (socklen_t*)&addrlen))<0) { perror("accept"); exit(EXIT_FAILURE); } valread = read( new_socket , buffer, 1024); printf("%s\n",buffer ); send(new_socket , hello , strlen(hello) , 0 ); printf("Hello message sent\n"); return 0; } ``` 这个程序创建了一个 TCP 服务器并绑定到 8080 端口。当客户端连接到服务器时,服务器会发送“Hello from server”字符串,然后关闭连接。 接下来,需要创建一个 TCP 客户端,可以使用以下代码: ```c #include <stdio.h> #include <stdlib.h> #include <string.h> #include <unistd.h> #include <sys/types.h> #include <sys/socket.h> #include <netinet/in.h> #include <arpa/inet.h> #define PORT 8080 int main(int argc, char const *argv[]) { int sock = 0, valread; struct sockaddr_in serv_addr; char *hello = "Hello from client"; char buffer[1024] = {0}; if ((sock = socket(AF_INET, SOCK_STREAM, 0)) < 0) { printf("\n Socket creation error \n"); return -1; } serv_addr.sin_family = AF_INET; serv_addr.sin_port = htons(PORT); // Convert IPv4 and IPv6 addresses from text to binary form if(inet_pton(AF_INET, "127.0.0.1", &serv_addr.sin_addr)<=0) { printf("\nInvalid address/ Address not supported \n"); return -1; } if (connect(sock, (struct sockaddr *)&serv_addr, sizeof(serv_addr)) < 0) { printf("\nConnection Failed \n"); return -1; } send(sock , hello , strlen(hello) , 0 ); printf("Hello message sent\n"); valread = read( sock , buffer, 1024); printf("%s\n",buffer ); return 0; } ``` 这个程序创建了一个 TCP 客户端并连接到 127.0.0.1 的 8080 端口。它发送“Hello from client”字符串,然后等待服务器的响应。 可以使用以下命令编译和运行这两个程序: ```bash arm-linux-gcc -o server server.c arm-linux-gcc -o client client.c ``` ```bash ./server & ./client ``` 这些程序应该能够在 ARM-Linux 上运行,并且客户端应该能够接收到服务器发送的“Hello from server”字符串。这个实验展示了如何在 ARM-Linux 上进行基本的网络编程

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值