【嵌入式Linux】嵌入式Linux应用开发基础知识之网络通信
文章目录
- 前言
- 1、网络通信--TCP
- 1.1、常用概念辨析
- 1.2、程序分析
- 2、网络通信--UDP
- 程序分析
- 参考资料
前言
韦东山嵌入式Linux应用开发基础知识学习笔记
文章中大多内容来自韦东山老师的文档,还有部分个人根据自己需求补充的内容
视频教程地址: https://www.bilibili.com/video/BV1kk4y117Tu
1、网络通信–TCP
1.1、常用概念辨析
IP和端口
所有的数据传输,都有三个要素 :源、目的、长度
怎么表示源或者目的呢?请看下图:
▲源和目的
所以,在网络传输中需要使用“IP和端口”来表示源或目的
网络传输中的2个对象:server和client
我们经常访问网站,这涉及2个对象:网站服务器,浏览器。网站服务器平时安静地呆着,浏览器主动发起数据请求。网站服务器、浏览器可以抽象成2个软件的概念:server程序、client程序。
▲server和client
两种传输方式:TCP/UDP
参考文章:计算机网络模型(TCP五层模型)
TCP和UDP 原理上的区别
TCP向它的应用程序提供了面向连接的服务。这种服务有2个特点:可靠传输、流量控制(即发送方/接收方速率匹配)。它包括了应用层报文划分为短报文,并提供拥塞控制机制。
UDP协议向它的应用程序提供无连接服务。它没有可靠性,没有流量控制,也没有拥塞控制。
为何存在UDP协议
TCP和UDP的区别
通过报文格式可以很直观的看出TCP相对于UDP为什么传输效率低,安全性高
▲TCP报文格式
▲UDP报文格式
TCP/UDP网络通信大概交互图
▲面向连接的TCP流模式
▲UDP用户数据包模式
1.2、程序分析
▲面向连接的TCP流模式
server.c
:服务器端运行程序
#include <sys/types.h> /* See NOTES */
#include <sys/socket.h>
#include <string.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <unistd.h>
#include <stdio.h>
#include <signal.h>
/* socket* bind* listen* accept* send/recv*/
#define SERVER_PORT 8888 //端口号
#define BACKLOG 10 //最大监听连接数量int main(int argc, char **argv)
{int iSocketServer; //服务器socket文件描述符int iSocketClient; //客户端socket文件描述符struct sockaddr_in tSocketServerAddr; //服务器socket addressstruct sockaddr_in tSocketClientAddr; //客户端socket addressint iRet;int iAddrLen; //客户端socket address长度int iRecvLen; //从客户端接收数据长度unsigned char ucRecvBuf[1000]; //从客户端接收数据缓冲区int iClientNum = -1; //客户端索引 signal(SIGCHLD,SIG_IGN);//AF_INET:IPV4 SOCK_STREAM:TCP传输 0:只存在一个协议来支持给定协议族中的特定套接字类型iSocketServer = socket(AF_INET, SOCK_STREAM, 0);if (-1 == iSocketServer){printf("socket error!\n");return -1;}//设定协议族tSocketServerAddr.sin_family = AF_INET;//主机字节序转换成网络字节序tSocketServerAddr.sin_port = htons(SERVER_PORT); /* host to net, short *///INADDR_ANY:本机上所有的IPtSocketServerAddr.sin_addr.s_addr = INADDR_ANY;memset(tSocketServerAddr.sin_zero, 0, 8);//绑定socket文件描述符和socket addressiRet = bind(iSocketServer, (const struct sockaddr *)&tSocketServerAddr, sizeof(struct sockaddr));if (-1 == iRet){printf("bind error!\n");return -1;}//设定iSocketServer最大监听数量BACKLOGiRet = listen(iSocketServer, BACKLOG);if (-1 == iRet){printf("listen error!\n");return -1;}while (1){iAddrLen = sizeof(struct sockaddr);/*iSocketServer可以接受连接,建立连接的客户端的socket address保存在iSocketClient长度信息保存在iAddrLen,且如果连接成功,系统返回iSocketClient*/iSocketClient = accept(iSocketServer, (struct sockaddr *)&tSocketClientAddr, &iAddrLen);if (-1 != iSocketClient){iClientNum++;//inet_ntoa:net to ASCIIprintf("Get connect from client %d : %s\n", iClientNum, inet_ntoa(tSocketClientAddr.sin_addr));//复制出子进程if (!fork()){/* 子进程fork() == 0 *//* 子进程源码 */while (1){/* 接收客户端发送数据并显示 */iRecvLen = recv(iSocketClient, ucRecvBuf, 999, 0);if (iRecvLen <= 0){close(iSocketClient);return -1;}else{//添加结束符ucRecvBuf[iRecvLen] = '\0';printf("Get Msg From Client %d: %s\n", iClientNum, ucRecvBuf);}} }//父进程}}close(iSocketServer);return 0;
}
client.c
:客户端运行程序,使用./client <IP>
来和服务器建立连接
#include <sys/types.h> /* See NOTES */
#include <sys/socket.h>
#include <string.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <unistd.h>
#include <stdio.h>/* socket* connect* send/recv*/#define SERVER_PORT 8888int main(int argc, char **argv)
{int iSocketClient;struct sockaddr_in tSocketServerAddr; int iRet;unsigned char ucSendBuf[1000];int iSendLen;if (argc != 2){printf("Usage:\n");printf("%s <server_ip>\n", argv[0]);return -1;}iSocketClient = socket(AF_INET, SOCK_STREAM, 0);tSocketServerAddr.sin_family = AF_INET;tSocketServerAddr.sin_port = htons(SERVER_PORT); /* host to net, short *///tSocketServerAddr.sin_addr.s_addr = INADDR_ANY;if (0 == inet_aton(argv[1], &tSocketServerAddr.sin_addr)){printf("invalid server_ip\n");return -1;}memset(tSocketServerAddr.sin_zero, 0, 8);iRet = connect(iSocketClient, (const struct sockaddr *)&tSocketServerAddr, sizeof(struct sockaddr)); if (-1 == iRet){printf("connect error!\n");return -1;}while (1){if (fgets(ucSendBuf, 999, stdin)){iSendLen = send(iSocketClient, ucSendBuf, strlen(ucSendBuf), 0);if (iSendLen <= 0){close(iSocketClient);return -1;}}}return 0;
}
fork()
函数返回值
1)在父进程中,fork返回新创建子进程的进程ID;
2)在子进程中,fork返回0;
3)如果出现错误,fork返回一个负值;
操作系统之 fork() 函数详解
什么是僵尸进程?
僵尸进程是当子进程比父进程先结束,而父进程又没有回收子进程,释放子进程占用的资源,此时子进程将成为一个僵尸进程。如果父进程先退出 ,子进程被init接管,子进程退出后init会回收其占用的相关资源
在这里如果没有在server.c中添加signal(SIGCHLD,SIG_IGN);
则会在客户端建立连接又断开连接后产生僵尸进程server
怎么解决僵尸进程问题?
signal(SIGCHLD, SIG_IGN)
2、网络通信–UDP
程序分析
▲UDP用户数据包模式
server.c
:服务器端运行程序
#include <sys/types.h> /* See NOTES */
#include <sys/socket.h>
#include <string.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <unistd.h>
#include <stdio.h>
#include <signal.h>
/* socket* bind* sendto/recvfrom*/
#define SERVER_PORT 8888int main(int argc, char **argv)
{int iSocketServer;int iSocketClient;struct sockaddr_in tSocketServerAddr;struct sockaddr_in tSocketClientAddr;int iRet;int iAddrLen;int iRecvLen;unsigned char ucRecvBuf[1000];//AF_INET:IPV4 SOCK_DGRAM:UDP传输 0:只存在一个协议来支持给定协议族中的特定套接字类型iSocketServer = socket(AF_INET, SOCK_DGRAM, 0);if (-1 == iSocketServer){printf("socket error!\n");return -1;}//设定协议族tSocketServerAddr.sin_family = AF_INET;//主机字节序转换成网络字节序tSocketServerAddr.sin_port = htons(SERVER_PORT); /* host to net, short *///INADDR_ANY:本机上所有的IPtSocketServerAddr.sin_addr.s_addr = INADDR_ANY;memset(tSocketServerAddr.sin_zero, 0, 8);//绑定socket文件描述符和socket addressiRet = bind(iSocketServer, (const struct sockaddr *)&tSocketServerAddr, sizeof(struct sockaddr));if (-1 == iRet){printf("bind error!\n");return -1;}while (1){iAddrLen = sizeof(struct sockaddr);//接收客户端发送的数据并显示iRecvLen = recvfrom(iSocketServer, ucRecvBuf, 999, 0, (struct sockaddr *)&tSocketClientAddr, &iAddrLen);if (iRecvLen > 0){ucRecvBuf[iRecvLen] = '\0';printf("Get Msg From %s : %s\n", inet_ntoa(tSocketClientAddr.sin_addr), ucRecvBuf);}}close(iSocketServer);return 0;
}
client.c
:客户端运行程序,使用./client <IP>
来和服务器建立连接
#include <sys/types.h> /* See NOTES */
#include <sys/socket.h>
#include <string.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <unistd.h>
#include <stdio.h>
/* socket* connect* send/recv*/
#define USECONNECT 0
#define SERVER_PORT 8888int main(int argc, char **argv)
{int iSocketClient;struct sockaddr_in tSocketServerAddr;int iRet;unsigned char ucSendBuf[1000];int iSendLen;int iAddrLen;if (argc != 2){printf("Usage:\n");printf("%s <server_ip>\n", argv[0]);return -1;}iSocketClient = socket(AF_INET, SOCK_DGRAM, 0);tSocketServerAddr.sin_family = AF_INET;tSocketServerAddr.sin_port = htons(SERVER_PORT); /* host to net, short *///tSocketServerAddr.sin_addr.s_addr = INADDR_ANY;if (0 == inet_aton(argv[1], &tSocketServerAddr.sin_addr)){printf("invalid server_ip\n");return -1;}memset(tSocketServerAddr.sin_zero, 0, 8);#if USECONNECTiRet = connect(iSocketClient, (const struct sockaddr *)&tSocketServerAddr, sizeof(struct sockaddr)); if (-1 == iRet){printf("connect error!\n");return -1;}
#endifwhile (1){if (fgets(ucSendBuf, 999, stdin)){#if USECONNECTiSendLen = send(iSocketClient, ucSendBuf, strlen(ucSendBuf), 0);
#elseiAddrLen = sizeof(struct sockaddr);iSendLen = sendto(iSocketClient, ucSendBuf, strlen(ucSendBuf), 0,(const struct sockaddr *)&tSocketServerAddr, iAddrLen);#endifif (iSendLen <= 0){close(iSocketClient);return -1;}}}return 0;
}
参考资料
操作系统之 fork() 函数详解
signal(SIGCHLD, SIG_IGN)
计算机网络模型(TCP五层模型)
【嵌入式Linux】嵌入式Linux应用开发基础知识之网络通信相关推荐
- 【嵌入式Linux】嵌入式Linux驱动开发基础知识之Pinctrl子系统和GPIO子系统的使用
文章目录 前言 1.Pinctrl子系统 1.1.为什么有Pinctrl子系统 1.2.重要的概念 1.3.代码中怎么引用pinctrl 2.GPIO子系统 2.1.为什么有GPIO子系统 2.2.在 ...
- 【嵌入式Linux】嵌入式Linux驱动开发基础知识之按键驱动框架
文章目录 前言 1.APP怎么读取按键值 1.1.查询方式 1.2.休眠-唤醒方式 1.3.poll方式 1.3.异步通知方式 1.5. 驱动程序提供能力,不提供策略 2.按键驱动程序框架--查询方式 ...
- 【嵌入式Linux】嵌入式Linux驱动开发基础知识之LED模板驱动程序的改造:设备树
文章目录 前言 1.驱动的三种编写方法 2.怎么使用设备树写驱动程序 2.1.设备树节点要与platform_driver能匹配 2.2.修改platform_driver的源码 3.实验和调试技巧 ...
- 【嵌入式Linux】嵌入式Linux驱动开发基础知识之设备树模型
文章目录 前言 1.设备树的作用 2.设备树的语法 2.1.设备树的逻辑图和dts文件.dtb文件 2.1.1.1Devicetree格式 1DTS文件的格式 node的格式 properties的格 ...
- 【嵌入式Linux】嵌入式Linux驱动开发基础知识之总线设备驱动模型
文章目录 前言 1.驱动编写的三种方法 1.1.传统写法 1.2.总线驱动模型 1.3.设备树驱动模型 2.Linux实现分离:Bus/Dev/Drv模型 2.1.Bus/Dev/Drv模型 2.2. ...
- 【嵌入式Linux】嵌入式Linux驱动开发基础知识之驱动设计的思想:面向对象/分层/分离
文章目录 前言 1.分离设计 驱动程序分析---程序分层 通用驱动程序---面向对象 个性化驱动程序---分离 APP 程序分析 前言 韦东山嵌入式Linux驱动开发基础知识学习笔记 文章中大多内容来 ...
- 【嵌入式Linux】嵌入式Linux驱动开发基础知识之LED驱动框架--面向对象、分层设计思想
文章目录 前言 1.LED驱动程序框架 1.1.对于LED驱动,我们想要什么样的接口? 1.2.LED驱动要怎么写,才能支持多个板子?分层写 1.3.程序分析 驱动程序 应用程序 Makefile 1 ...
- 【嵌入式Linux】嵌入式Linux驱动开发基础知识之第一个驱动
文章目录 前言 1.Hello驱动 1.1.APP打开的文件在内核中如何表示? 1.2.打开字符设备节点时,内核中也有对应的struct file 1.3.如何编写驱动程序? 1.4.驱动程序代码 1 ...
- 【嵌入式Linux】嵌入式Linux应用开发基础知识之I2C应用编程和SMBus协议及AP3216C应用编程
文章目录 前言 1.IIC协议和SMBUS协议 1.1.IIC协议 1.1.1.硬件框架 1.1.2.软件框架 1.1.3.读写数据格式 1.1.4.硬件结构--在硬件上是如何实现双向传输 1.2.S ...
最新文章
- 理解YOLOv2训练过程中输出参数含义
- VR+监狱,分分钟让犯罪分子重新做人
- ubuntu装双系统win7和linux,Ubuntu下安装WIn7(双系统)
- C语言学习之求S=a+aa+aaa+... +aa.....aa之值,其中a是一个数字,n表示a的位数.
- c++中堆、栈内存分配概念示例讲解
- javascript 核心概念(1)-数据类型
- docx文档怎么排列图片_“胶水语言”办公自动化Word篇——使用Python编辑和读取Word文档
- 机器学习入门|线性回归(二)
- [Matlab] 二进制蝙蝠算法用于解决背包问题
- UltraISO9.3.0.2610中文绿色注册版
- JAVA之进制转换(全)
- 鄂尔多斯固体废物智慧化管理平台设备和功能概况
- Python exe Fatal error detected
- TriangleCount三角形计数
- idea-2017破解教程
- PPT画图(或排版)后保存为高清图片(可自定义分辨率)
- 基于PHP开发的云平台网络课堂教学学习互动平台设计
- ffmpeg视频转动图gif和Webp
- 输入关键字的爬虫方法(运行环境python3)
- 算术运算符:取余(取模)%
热门文章
- POJ 2240 Arbitrage(SPFA判正环)
- python tkinter treeview 高亮_满满的成就感~如何用python让你的想法拥有可操作性?(一)...
- java 本年第一天_JAVA获取本周 本月 本年 第一天和最后一天
- 按大小排序php,php中按大小进行排序的函数有哪些
- 推荐系统学习(一)推荐系统分类与基本流程
- matlab错误使用builtin,MATLAB环境下运行MATLAB函数时发生异常
- 触发更新机制_王者荣耀1.14更新:11名英雄调整,韩信加强,鲁班大师重做
- 第四单元和课程总结:简单的架构设计意识
- ArchLinux安装Gnome桌面
- Halcon 和 C# 联合编程 - 如何使用开源项目 ViewROI