net、udp、tcp

embedded/2024/12/22 11:03:29/

Makefile的main.c文件中的全局变量SONG song,要在fun.c文件里面写成extern SONG song

编译方法

第一次编写


网络编程 

物理层的网线规定有八根,颜色不一样,功能不一样,光猫把光信号转换成电信号,光纤10Gb

WiFi叫无线局域网,一般也就50米左右,手机流量叫蜂窝网络,随时随地上网。

链路层:先格式化一下,网络可以通过交换机连接起来。

网络层:通过ip地址找到目标

传输层:数据以何种方式传输?tcp可靠传输,传输过程中数据准确的到达对方。udp可能会丢包 。一般下载文件上传文件多以tcp为主,一般视频,音频 (实时性重要)一般用udp

OSI模型

物理层

解决两个硬件之间怎么通信的问题,常见的物理媒介有光纤、电缆、中继器等。它主要定义物理设备标准,如网线的接口类型、光纤的接口类型、各种传输介质的传输速率等。

它的主要作用是传输比特流(就是由1、0转化为电流强弱来进行传输,到达目的地后在转化为1、0,也就是我们常说的数模转换与模数转换)。这一层的数据叫做比特。

链路层(把设备连接起来)

在计算机网络中由于各种干扰的存在,物理链路是不可靠的。该层的主要功能就是:通过各种控制协议,将有差错的物理信道变为无差错的、能可靠传输数据帧的数据链路。

它的具体工作是接收来自物理层的位流形式的数据,并封装成帧,传送到上一层;同样,也将来自上层的数据帧,拆装为位流形式的数据转发到物理层。这一层的数据叫做帧。

网络

计算机网络中如果有多台计算机,怎么找到要发的那台?如果中间有多个节点,怎么选择路径?这就是路由要做的事。

该层的主要任务就是:通过路由选择算法,为报文(该层的数据单位,由上一层数据打包而来)通过通信子网选择最适当的路径。这一层定义的是IP地址,通过IP地址寻址,所以产生了IP协议。

传输层

当发送大量数据时,很可能会出现丢包的情况,另一台电脑要告诉是否完整接收到全部的包。如果缺了,就告诉丢了哪些包,然后再发一次,直至全部接收为止。

简单来说,传输层的主要功能就是:监控数据传输服务的质量,保证报文的正确传输。

会话层(网络断开,连接的状态)

虽然已经可以实现给正确的计算机,发送正确的封装过后的信息了。但我们总不可能每次都要调用传输层协议去打包,然后再调用IP协议去找路由,所以我们要建立一个自动收发包,自动寻址的功能。于是会话层出现了:它的作用就是建立和管理应用程序之间的通信。

表示层(加密,解密)

表示层负责数据格式的转换,将应用处理的信息转换为适合网络传输的格式,或者将来自下一层的数据转换为上层能处理的格式。

应用层

应用层是计算机用户,以及各种应用程序和网络之间的接口,其功能是直接向用户提供服务,完成用户希望在网络上完成的各种工作。前端同学对应用层肯定是最熟悉的。

TCP/IP模型(也叫tcp/ip协议栈):专门描述互联网的模型(把OSI模型合并了一下)

TCP/IP协议族

  • dns 域名解析  把域名转成ip地址
  • DHCP 动态主机配置协议(路由器分配地址)
  • http  超文本传输协议(使用网页就会用到这个协议)
  • FTP  互联网远距离传输用ftp(可以断点续传)
  • TFTP 简单文件传输协议(传输本地文件)---局域网内
  • SNMP   网络管理  网络状态监测
  • TCP 传输控制协议   一种可靠的传输方式  自带超时重传   必须要有应答    实时性比较差
  • UDP   实时性好  会丢包   节省网络开销
  • ARP  地址解析协议    在以太网环境中,数据的传输所依懒的是MAC地址而非IP地址,而将已知IP地址转换为MAC地址的工作是由ARP协议来完成的。
  • RIP和OSPF都是路由协议

TCP编程基础知识


  • 网关:也叫gate,跟个门一样,没出去就是局域网,出去就是互联网,默认是0.1(后两位)
  • 广播:最后一位是255)给这个位发,所有人都接收到了(只能是局域网里,一个人发所有人收)
  • 组播:让想收到的人收到(类似于群聊)

IP地址一般都是点分十进制(分为四段,每一段最小0最大255)

A类中第一段表示有多少个网络,是网络号,后面的数字表示有多少台主机(2的64次方)

B类中前两段表示有多少个网络(比如说128.0和128.1代表两个网络),后面数字表示有多少台主机(2的16次方)

C类前三段表示有多少个网络,后面数字表示有某一台主机(主机号)------我们一般用的是这种

linux的网络配置命令

配置完一定要重启sudo reboot 才会生效

ifconfig:查看网卡状态相关信息

硬件地址

手动设置ip地址,然后重启

查看网络状态(是否连接)

网络接口

  • socket 套接字  是文件描述符(网络文件需要收发)
  • ip地址是用来找主机的
  • 端口号用来识别进程的

网络字节序

小端存储--数据的低位在低内存

  • 计算机是小端    网络设备是大端
  • ip地址和端口号要去找主机设备--------都要大小端转换一下

UDP(有服务端和客户端,一对多的关系)简单一点----无连接,不显示状态信息,不可靠

  • socket类似于open,将网络设备打开,打开后拿到一个文件描述符
  • 客户端找服务器需要ip地址和端口号,bind就是给套接字设置ip地址和端口号的 
  • 服务器先收,因为客户得先告诉服务器要啥

代码:(客户端找服务器)

固定的就选这个IPv4对应的

服务端: 

SA是强转一下,转成下面这个类型

#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <string.h>
#include <sys/types.h>          /* See NOTES */
#include <sys/socket.h>
#include <netinet/in.h>
#include <netinet/ip.h>
#include <arpa/inet.h>
#include <time.h>
typedef struct sockaddr * (SA);
int main(int argc, char *argv[])
{int sockfd = socket(AF_INET,SOCK_DGRAM,0);//第一步,可能会有少量丢包,0是默认方式if(-1 == sockfd){perror("socket");exit(1);}// man 7 ip struct sockaddr_in ser,cli;//in代表internet互联网,这个是对方和自己的地址结构体bzero(&ser,sizeof(ser));bzero(&cli,sizeof(cli));ser.sin_family = AF_INET;// 大小端转化 host to net short ser.sin_port = htons(50000);//小端转大端,50000是端口号ser.sin_addr.s_addr = inet_addr("192.168.203.128");//写自己ip,大端转小端,数字转字符串int ret = bind(sockfd,(SA)&ser,sizeof(ser));//第二步,绑定if(-1 == ret){perror("bind");exit(1);}socklen_t len = sizeof(cli);while(1){char buf[512]={0};recvfrom(sockfd,buf,sizeof(buf),0,(SA)&cli,&len);//第三步,收,0代表工作方式,有人发就接受,没人就等着time_t tm;time(&tm);//拿到时间sprintf(buf,"%s %s",buf,ctime(&tm));sendto(sockfd,buf,strlen(buf),0,(SA)&cli,len);//第四步,发出去,0是默认方式}close(sockfd);return 0;
}

客户端:

#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <string.h>
#include <sys/types.h>          /* See NOTES */
#include <sys/socket.h>
#include <netinet/in.h>
#include <netinet/ip.h>
#include <arpa/inet.h>
#include <time.h>
typedef struct sockaddr * (SA);int main(int argc, char *argv[])
{int sockfd = socket(AF_INET,SOCK_DGRAM,0);//第一步if(-1 == sockfd){perror("socket");exit(1);}struct sockaddr_in ser;bzero(&ser,sizeof(ser));ser.sin_family = AF_INET;// 大小端转化 host to net short ser.sin_port = htons(50000);ser.sin_addr.s_addr = inet_addr("192.168.203.128");while(1){char buf[512]="hello,this is udp test";sendto(sockfd,buf,strlen(buf),0,(SA)&ser,sizeof(ser));//第二步bzero(buf,sizeof(buf));recvfrom(sockfd,buf,sizeof(buf),0,NULL,NULL);//第三步printf("buf is %s\n",buf);sleep(1);}close(sockfd);return 0;
}

 结果:

UDP(用户数据报)(半双工,要么收要么发)

 发完链路就自动释放了,比较节省空间,网络开销比较小,丢包就是因为没有维护链路的状态

数据报:数据和数据间是有间隔的,收发次数要对应,不然就丢了,并且在收的大小建议大于等于包的大小,即使小了,剩下的也不会再收到了

UDP特征

  • 数据有边界
  • 收发次数要对应
  • recvfrom如果没有发送,就会阻塞
  • sendto不会阻塞,他只管发,收不收都可以

UDP传文件的代码

服务端:

#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <string.h>
#include <sys/types.h>          /* See NOTES */
#include <sys/socket.h>
#include <netinet/in.h>
#include <netinet/ip.h>
#include <arpa/inet.h>
#include <time.h>
#include <fcntl.h>
typedef struct sockaddr * (SA);
int main(int argc, char *argv[])
{int sockfd = socket(AF_INET,SOCK_DGRAM,0);if(-1 == sockfd){perror("socket");exit(1);}// man 7 ip struct sockaddr_in ser,cli;bzero(&ser,sizeof(ser));bzero(&cli,sizeof(cli));ser.sin_family = AF_INET;// 大小端转化 host to net short ser.sin_port = htons(50000);//ser.sin_addr.s_addr = inet_addr("127.0.0.1");//活的地址,也代表自己的地址,本地回环,自己跟自己测,这个数据不会发出去ser.sin_addr.s_addr = INADDR_ANY;//代表本机任何一个可用的IP地址,自己跟自己也可以,跟外面也可以,不用大小端转换int ret = bind(sockfd,(SA)&ser,sizeof(ser));if(-1 == ret){perror("bind");exit(1);}socklen_t len = sizeof(cli);int fd = open("2.png",O_WRONLY|O_CREAT|O_TRUNC,0666);//trunc是清空,只要有创建后面就给666if(-1 == fd){perror("open");exit(1);}while(1){char buf[512]={0};int rd_ret = recvfrom(sockfd,buf,sizeof(buf),0,(SA)&cli,&len);if(0 == strcmp(buf,"^_^")){break;}write(fd,buf,rd_ret);//收多少写多少bzero(buf,sizeof(buf));strcpy(buf,"go on");//防止发的太快来不及写(收),所以控制他发的速度sendto(sockfd,buf,strlen(buf),0,(SA)&cli,len);}close(sockfd);close(fd);return 0;
}

客户端:

#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <string.h>
#include <sys/types.h>          /* See NOTES */
#include <sys/socket.h>
#include <netinet/in.h>
#include <netinet/ip.h>
#include <arpa/inet.h>
#include <time.h>
#include <fcntl.h>
typedef struct sockaddr * (SA);int main(int argc, char *argv[])
{int sockfd = socket(AF_INET,SOCK_DGRAM,0);if(-1 == sockfd){perror("socket");exit(1);}struct sockaddr_in ser;bzero(&ser,sizeof(ser));ser.sin_family = AF_INET;// 大小端转化 host to net short ser.sin_port = htons(50000);ser.sin_addr.s_addr = inet_addr("192.168.203.128");//自己跟自己可以写any,跟别的必须写客户端IP地址int fd = open("/home/linux/1.png",O_RDONLY);if(-1 == fd){perror("open");exit(1);}char buf[512]={0};while(1){bzero(buf,sizeof(buf));int rd_ret = read(fd,buf,sizeof(buf));if(0==rd_ret){break;}sendto(sockfd,buf,rd_ret,0,(SA)&ser,sizeof(ser));bzero(buf,sizeof(buf));recvfrom(sockfd,buf,sizeof(buf),0,NULL,NULL);}bzero(buf,sizeof(buf));strcpy(buf,"^_^");sendto(sockfd,buf,3,0,(SA)&ser,sizeof(ser));//走到这里证明发送结束了,告诉客户端发送结束了,因为无连接close(sockfd);close(fd);return 0;
}

结果:

练习:UDP的聊天室(一个人发,全都能收到)

服务端是负责转发的,除了不给发消息的人转发,其他人都转

服务端:

#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <string.h>
#include <sys/types.h>          /* See NOTES */
#include <sys/socket.h>
#include <netinet/in.h>
#include <netinet/ip.h>
#include <arpa/inet.h>
#include <time.h>
typedef struct sockaddr * (SA);
typedef enum {CMD_LOGIN,CMD_CHAT,CMD_LOGOUT}TYPE;
typedef struct 
{TYPE type;char name[50];char context[128];}MSG;
typedef struct 
{struct sockaddr_in cli;int flag; // 0  free 1 occu
}LIST;
#define MAX 10
LIST list[MAX]={0};//最多多少人
int do_login(int sockfd,MSG* msg,struct sockaddr_in* cli)
{int i = 0 ;for(i=0;i<MAX;i++){if(1 == list[i].flag )//等于一证明人在,没退出{sendto(sockfd,msg,sizeof(MSG),0,(SA)&list[i].cli,sizeof(list[i].cli));}}for(i=0;i<MAX;i++){if(0 == list[i].flag ){list[i].flag =1;//list[i].cli = *cli;memcpy(&list[i].cli,cli,sizeof(*cli));break;}}return 0;
}int do_chat(int sockfd, MSG* msg,struct sockaddr_in*cli)//转发
{int i = 0 ;for(i=0;i<MAX;i++){if(1 == list[i].flag && 0!=memcmp(&list[i].cli,cli,sizeof(*cli)) )//确保有人,并且发送方和接收方的ip地址不一样{sendto(sockfd,msg,sizeof(MSG),0,(SA)&list[i].cli,sizeof(list[i].cli));}}
}
int do_logout(int sockfd, MSG* msg,struct sockaddr_in*cli)
{return 0;
}
int main(int argc, char *argv[])
{int sockfd = socket(AF_INET,SOCK_DGRAM,0);if(-1 == sockfd){perror("socket");exit(1);}// man 7 ip struct sockaddr_in ser,cli;bzero(&ser,sizeof(ser));bzero(&cli,sizeof(cli));ser.sin_family = AF_INET;// 大小端转化 host to net short ser.sin_port = htons(50000);ser.sin_addr.s_addr = inet_addr("127.0.0.1");int ret = bind(sockfd,(SA)&ser,sizeof(ser));if(-1 == ret){perror("bind");exit(1);}socklen_t len = sizeof(cli);MSG msg;while(1){bzero(&msg,sizeof(msg));recvfrom(sockfd,&msg,sizeof(msg),0,(SA)&cli,&len);switch(msg.type){case CMD_LOGIN:do_login(sockfd,&msg,&cli);break;case CMD_LOGOUT:do_logout(sockfd,&msg,&cli);break;case CMD_CHAT:do_chat(sockfd,&msg,&cli);break;}}close(sockfd);return 0;
}

客户端:(并行)

#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <string.h>
#include <sys/types.h>          /* See NOTES */
#include <sys/socket.h>
#include <netinet/in.h>
#include <netinet/ip.h>
#include <arpa/inet.h>
#include <time.h>
typedef struct 

http://www.ppmy.cn/embedded/105395.html

相关文章

数据库水平分表方案

数据库分表有很多策略&#xff0c;如下&#xff1a; 数据库分表是处理大型数据库中数据量过大的一种常见策略&#xff0c;它可以提高查询性能、减少锁竞争、降低维护成本等。以下是一些常见的数据库分表方案&#xff1a; 1. **垂直分表&#xff08;Vertical Partitioning&…

【Python机器学习】NLP词频背后的含义——隐性语义分析

隐性语义分析基于最古老和最常用的降维技术——奇异值分解&#xff08;SVD&#xff09;。SVD将一个矩阵分解成3个方阵&#xff0c;其中一个是对角矩阵。 SVD的一个应用是求逆矩阵。一个矩阵可以分解成3个最简单的方阵&#xff0c;然后对这些方阵求转置后再把它们相乘&#xff…

gitlab 包含模型文件,比较大,怎么上传

当你的 GitLab 项目包含较大的模型文件或其他大文件时&#xff0c;直接上传可能会遇到一些限制。你可以使用以下几种方法来处理&#xff1a; 方法 1&#xff1a;调整 Git 的文件大小限制 调整 GitLab 的限制&#xff1a; 如果你有权限管理 GitLab 实例&#xff0c;你可以调整 …

UDP英译汉网络词典

这里我们用UDP实现一个简单的英译汉小词典。我们还是仿照前一篇的UDP编程&#xff0c;将各自的组件封装起来&#xff0c;实现高内聚低耦合。 一. 字典翻译功能实现 首先我们将我们的字典知识库放在txt文本中。 apple: 苹果 banana: 香蕉 cat: 猫 dog: 狗 book: 书 pen: 笔 ha…

vue、小程序识别换行

vue 1、\n <pre></pre>标签识别返回的\n换行符&#xff0c;与css的 white-space: pre-wrap(保留空白符序列&#xff0c;但是正常地进行换行。);&#xff0c;pre-line(合并空白符序列&#xff0c;但是保留换行符。)注意代码中的换行也会被识别到&#xff0c;如果标…

String核心设计模式——建造者模式

目录 建造者模式 优点 缺点 使用场景 结构 步骤 1 Item.java Packing.java 步骤 2 Wrapper.java Bottle.java 步骤 3 Burger.java ColdDrink.java 步骤 4 VegBurger.java ChickenBurger.java Coke.java Pepsi.java 步骤 5 Meal.java 步骤 6 MealBuilder…

网络编程TCP和UDP

将TCP的CS模型再敲一遍 TCP服务器 1->创建原始的套接字描述符 2->将原始套接字与主机ip绑定 3->将原始套接字设置监听状态 4->接收客户端连接&#xff0c;获取客户端信息&#xff0c;因为原始套接字被用了&#xff0c;所以创建新的套接字描述符用于客户端通信…

[论文笔记]RAFT: Adapting Language Model to Domain Specific RAG

引言 今天带来一篇结合RAG和微调的论文&#xff1a;RAFT: Adapting Language Model to Domain Specific RAG。 为了简单&#xff0c;下文中以翻译的口吻记录&#xff0c;比如替换"作者"为"我们"。 本文介绍了检索增强微调(Retrieval Augmented Fine Tunin…