什么是LINUX,【嵌入式Linux】嵌入式Linux应用开发基础知识之网络通信

 2023-09-25 阅读 27 评论 0

摘要:文章目录前言1、网络通信--TCP1.1、常用概念辨析1.2、程序分析2、网络通信--UDP程序分析参考资料 前言 韦东山嵌入式Linux应用开发基础知识学习笔记 文章中大多内容来自韦东山老师的文档,还有部分个人根据自己需求补充的内容 视频教程地址: https://www.bilibi

文章目录

  • 前言
  • 1、网络通信--TCP
    • 1.1、常用概念辨析
    • 1.2、程序分析
  • 2、网络通信--UDP
    • 程序分析
  • 参考资料

前言

韦东山嵌入式Linux应用开发基础知识学习笔记
文章中大多内容来自韦东山老师的文档,还有部分个人根据自己需求补充的内容

视频教程地址: https://www.bilibili.com/video/BV1kk4y117Tu

1、网络通信–TCP

1.1、常用概念辨析

什么是LINUX?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;
}

做嵌入式不如java?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五层模型)

版权声明:本站所有资料均为网友推荐收集整理而来,仅供学习和研究交流使用。

原文链接:https://hbdhgg.com/1/94354.html

发表评论:

本站为非赢利网站,部分文章来源或改编自互联网及其他公众平台,主要目的在于分享信息,版权归原作者所有,内容仅供读者参考,如有侵权请联系我们删除!

Copyright © 2022 匯編語言學習筆記 Inc. 保留所有权利。

底部版权信息