Linux应用开发---网络通信

Linux应用开发—网络通信

1 网络通信概述

  Linux下的网络编程,我们一般称为 socket 编程,socket 是内核向应用层提供的一套网络编程接口,我们可以基于socket接口开发自己的网络相关应用程序。

1.1 socket 简介

  套接字(socket)是Linux下的一种进程间通信机制(socket IPC),使用 socket IPC 可以使得在不同主机上的应用程序之间进行通信(网络通信),也可以是同一台主机上的不同应用程序。socket IPC 通常使用客户端-服务器这种模式完成通信,多个客户端可以同时连接到服务器中,与服务器完成数据交互。
  内核向应用层提供了 socket 接口,我们只需要调用 socket 接口开发我们的应用程序即可。socket 是应用层与 TCP/IP 协议通信的中间软件抽象层,它是一组接口,它把复杂的 TCP/IP 协议隐藏在接口后面。因此,我们无需深入理解 TCP/UDP 等复杂的 TCP/IP 协议,socket 已经为我们封装好了,我们只需要遵循 socket 的规定去编程,写出的程序自然遵循 TCP/UDP 标准。

1.2 IP 和 端口

所有的数据传输,都要包含三个元素:源、目的和长度。
在这里插入图片描述

在网络通信中我们使用 “IP 和 端口” 来表示源和目的。

1.3 网络传输中的 2 个对象:server 和 client

  我们访问网站时会涉及到2个对象:网站服务器和浏览器。网站服务器平时安静地呆着,浏览器主动发起数据请求。网站服务器、浏览器可以抽象为 2 个软件的概念:server 程序、client 程序。
在这里插入图片描述

1.4 计算机网络体系结构

计算机网络体系结构分为3种:OSI体系结构(七层),TCP/IP体系结构(四层),五层体系结构。

  • OSI体系结构:概念清楚,理论也比较完整,但是它既复杂又不实用。
  • TCP/IP体系结构:TCP/IP是一个四层体系结构,得到了广泛的运用。
  • 五层体系结构:为了方便学习,折中OSI体系结构和TCP/IP体系结构,综合二者的优点,这样既简洁,又能将概念讲清楚。
    请添加图片描述

TCP/IP与OSI最大的不同在于:OSI是一个理论上的网络通信模型,而TCP/IP则是实际运行的网络协议。

1.4.1 五层网络体系结构概述
  1. 应用层:它是体系结构中的最高层,直接为用户的应用进程(例如电子邮件、文件传输和终端仿真)提供服务。在因特网中的应用层协议很多,如支持万维网应用的 HTTP 协议,支持电子邮件的 SMTP 协议,支持文件传送的 FTP 协议,DNS,POP3,SNMP,Telnet 等等。

  2. 运输层:负责向两个主机中进程之间的通信提供服务。运输层主要使用以下两种协议:

    • 传输控制协议 TCP:面向连接的,数据传输的单位是报文段,能够提供可靠的交付。
    • 用户数据包协议 UDP:无连接的,数据传输的单位是用户数据报,不保证提供可靠的交付,只能提供“尽最大努力交付”。
  3. 网络层:负责将被称为数据包(datagram)的网络层分组从一台主机移动到另一台主机。

  4. 链路层:因特网的网络层通过源和目的地之间的一系列路由器路由数据报。

  5. 物理层:在物理层上所传数据的单位是比特。物理层的任务就是透明地传送比特流。

我们并不需要具体理解这些层,我们只需要使用“运输层”编写应用程序。使用“运输层”时,可以选择 TCP 协议,也可以选择 UDP 协议。

1.4.2 TCP 和 UDP 区别
  1. TCP是面向连接的协议,而UDP是无连接的协议。
  2. TCP提供可靠的数据传输,UDP则不提供可靠性保证。
  3. TCP提供了可靠性保证,它的数据传输速度相对较慢。UDP没有额外的操作,所以传输速度相对较快。
1.4.3 为何存在UDP协议

  既然 TCP 可以提供可靠的数据服务,而 UDP 却不提供,那我们是否可以只用 TCP 呢?
  答案是否定的,举个例子:视频通话时,使用 UDP,偶尔的丢包、偶尔的花屏时可以忍受的;如果使用 TCP,每个数据包都要确保可靠传输,当它出错时就重传,这会导致后续的数据包被阻滞,视频效果反而不好。

1.4.4 TCP/UDP 网络通信交互图

在这里插入图片描述

在这里插入图片描述

2 TCP实现

2.1 服务端

#include <sys/types.h> 
#include <sys/socket.h>
#include <stdio.h>
#include <string.h>
#include <unistd.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <signal.h>#define SERVERPORT 8888
#define BACKLOG    10int main(int argc,char* argv[])
{int iSocketServer;int iSocketClient;struct sockaddr_in tSocketServerAddr;struct sockaddr_in tSocketClientAddr;int iRet;int iAddrLen;int iClientNum = -1;int iRecvLen;unsigned char ucRecvBuf[1000];signal(SIGCHLD,SIG_IGN); //解决僵尸进程问题iSocketServer = socket(AF_INET,SOCK_STREAM,0); //打开套接字if(iSocketServer == -1){printf("socket error!\n");return -1;}memset(&tSocketServerAddr, 0x0, sizeof(struct sockaddr_in)); //清零//填充变量tSocketServerAddr.sin_family = AF_INET;tSocketServerAddr.sin_addr.s_addr = htonl(INADDR_ANY);tSocketServerAddr.sin_port = htons(SERVERPORT);//将地址与套接字进行关联、绑定iRet = bind(iSocketServer,(const struct sockaddr *)&tSocketServerAddr,sizeof(struct sockaddr));if(iRet == -1){printf("bind error!\n");return -1;}iRet = listen(iSocketServer,BACKLOG); //监听客户端连接if(iRet == -1){printf("listen error!\n");return -1;}while (1){iAddrLen = sizeof(struct sockaddr);iSocketClient = accept(iSocketServer,(struct sockaddr *)&tSocketClientAddr,&iAddrLen); //接受连接if(iSocketClient != -1){iClientNum++;printf("Get connect from client %d : %s\n",iClientNum,inet_ntoa(tSocketClientAddr.sin_addr));if(!fork()){/********子进程源码**********/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;
}

2.2客户端

#include <sys/types.h> 
#include <sys/socket.h>
#include <stdio.h>
#include <string.h>
#include <unistd.h>
#include <netinet/in.h>
#include <arpa/inet.h>#define SERVERPORT 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); //打开套接字if(iSocketClient == -1){printf("socket error!\n");return -1;}memset(&tSocketServerAddr, 0x0, sizeof(struct sockaddr_in)); //清零//填充变量tSocketServerAddr.sin_family = AF_INET;tSocketServerAddr.sin_port = htons(SERVERPORT);if (0 == inet_aton(argv[1], &tSocketServerAddr.sin_addr)){printf("invalid server_ip\n");return -1;}iRet = connect(iSocketClient,(const struct sockaddr *)&tSocketServerAddr,sizeof(struct sockaddr)); //连接服务器if(iRet == -1){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;}}}close(iSocketClient); //关闭套接字return 0;
}

2.3 实验

  1. 编译代码:
gcc -o server ./server.c
gcc -o client ./client.c

在这里插入图片描述

  1. 运行服务端:
./server

在这里插入图片描述

  1. 查看本机可用ip:
ifconfig

在这里插入图片描述

  1. 运行客户端
./client 192.168.217.128

在这里插入图片描述
并且可以看到服务端连接到客户端。
在这里插入图片描述

  1. 发送数据

在这里插入图片描述
在服务器端显示接收到的内容。
在这里插入图片描述

3 UDP实现

3.1 服务端

#include <sys/types.h> 
#include <sys/socket.h>
#include <stdio.h>
#include <string.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <unistd.h>#define SERVERPORT 8888int main(int argc,char* argv[])
{int iSocketServer;struct sockaddr_in tSocketServerAddr;struct sockaddr_in tSocketClientAddr;int iRet;int iAddrLen;int iRecvLen;unsigned char ucRecvBuf[1000];iSocketServer = socket(AF_INET, SOCK_DGRAM, 0);//打开套接字if (iSocketServer == -1){printf("socket error!\n");return -1;}memset(&tSocketServerAddr, 0x0, sizeof(struct sockaddr_in)); //清零//填充变量tSocketServerAddr.sin_family = AF_INET;tSocketServerAddr.sin_addr.s_addr = htonl(INADDR_ANY);tSocketServerAddr.sin_port = htons(SERVERPORT);//将地址与套接字进行关联、绑定iRet = bind(iSocketServer,(const struct sockaddr *)&tSocketServerAddr,sizeof(struct sockaddr));if(iRet == -1){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;
}

3.2 客户端

#include <sys/types.h> 
#include <sys/socket.h>
#include <stdio.h>
#include <string.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <unistd.h>#define SERVERPORT 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_DGRAM, 0); //打开套接字if (iSocketClient == -1){printf("socket error!\n");return -1;}memset(&tSocketServerAddr, 0x0, sizeof(struct sockaddr_in)); //清零//填充变量tSocketServerAddr.sin_family = AF_INET;tSocketServerAddr.sin_port = htons(SERVERPORT);if (0 == inet_aton(argv[1], &tSocketServerAddr.sin_addr)){printf("invalid server_ip\n");return -1;}iRet = connect(iSocketClient,(const struct sockaddr *)&tSocketServerAddr,sizeof(struct sockaddr)); //连接服务器if(iRet == -1){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;}}}close(iSocketClient);return 0;
}

3.3 实验

  1. 编译代码:
gcc -o server ./server.c
gcc -o client ./client.c

在这里插入图片描述

  1. 运行服务端
./server

在这里插入图片描述

  1. 运行客户端
./client 192.168.217.128

在这里插入图片描述

  1. 发送数据

在这里插入图片描述
在服务器端显示接收到的内容。
在这里插入图片描述

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/675408.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

Jenkins升级后,构建任务配置界面重复错位

最近我把公司的Jenkins服务升级到了最新版本&#xff0c;升级完成后&#xff0c;点了一下构建任务&#xff0c;发现能够构建成功&#xff0c;就以为顺利完成升级了&#xff0c;下班走了&#xff0c;结果第二天&#xff0c;进入构建任务配置界面发现&#xff0c;界面一团乱麻&am…

LabVIEW热电偶自动校准系统

设计并实现一套基于LabVIEW平台的工业热电偶自动校准系统&#xff0c;通过自动化技术提高校准效率和精度&#xff0c;降低人力成本&#xff0c;确保温度测量的准确性和可靠性。 工业生产过程中&#xff0c;温度的准确测量对产品质量控制至关重要。传统的热电偶校准方式依赖人工…

[Java][算法 双指针]Day 02---LeetCode 热题 100---04~07

LeetCode 热题 100---04~07 第一题&#xff1a;移动零 思路 找到每一个为0的元素 然后移到数组的最后 但是需要注意的是 要在给定的数组原地进行修改 并且其他非零元素的相对顺序不能改变 我们采用双指针法 定义两个指针i和j i和j一开始分别都在0索引位置 然后判断j所…

tab 切换类交互功能实现

tab切换类交互&#xff1a; 记录激活项&#xff08;整个对象/id/index)动态类型控制 下面以一个地址 tab 切换业务功能为例&#xff1a; <div class"text item" :class"{active : activeAddress.id item.id}" click"switchAddress(item)"…

v-if 和v-for的联合规则及示例

第073个 查看专栏目录: VUE ------ element UI 专栏目标 在vue和element UI联合技术栈的操控下&#xff0c;本专栏提供行之有效的源代码示例和信息点介绍&#xff0c;做到灵活运用。 提供vue2的一些基本操作&#xff1a;安装、引用&#xff0c;模板使用&#xff0c;computed&a…

《游戏引擎架构》 -- 学习2

声明&#xff0c;定义&#xff0c;以及链接规范 翻译单元 声明与定义 链接规范 C/C 内存布局 可执行映像 程序堆栈 动态分配的堆 对象的内存布局 kilobyte 和 kibibyte 流水线缓存以及优化 未完待续。。。

SQL注入(SQL Injection)从注入到拖库 —— 简单的手工注入实战指南精讲

基本SQL注入步骤&#xff1a; 识别目标&#xff1a;确定目标网站或应用程序存在潜在的SQL注入漏洞。收集信息&#xff1a;通过查看页面源代码、URL参数和可能的错误信息等&#xff0c;搜集与注入有关的信息。判断注入点&#xff1a;确定可以注入的位置&#xff0c;比如输入框、…

【网工】华为设备命令学习(Telnet)

本次实验AR3为我们实际中远程的路由&#xff0c;AR4模拟我们的设备&#xff0c;最终实现Telnet的远程控制路由&#xff01; 本次笔记主要记录Telnet技术实现原理&#xff0c;后续再补充具体配置代码。 Telnet协议是TCP/IP协议族中的一员&#xff0c;是Internet远程登录服务的…

基于微信小程序的新生报到系统的研究与实现,附源码

博主介绍&#xff1a;✌程序员徐师兄、7年大厂程序员经历。全网粉丝12w、csdn博客专家、掘金/华为云/阿里云/InfoQ等平台优质作者、专注于Java技术领域和毕业项目实战✌ &#x1f345;文末获取源码联系&#x1f345; &#x1f447;&#x1f3fb; 精彩专栏推荐订阅&#x1f447;…

前端实现支付跳转以及回跳

// 支付地址 const baseURL http://pcapi-xiaotuxian-front-devtest.itheima.net/ const backURL http://127.0.0.1:5173/paycallback const redirectUrl encodeURIComponent(backURL) const payUrl ${baseURL}pay/aliPay?orderId${route.query.id}&redirect${redirec…

【精选】java初识多态 子类继承父类

&#x1f36c; 博主介绍&#x1f468;‍&#x1f393; 博主介绍&#xff1a;大家好&#xff0c;我是 hacker-routing &#xff0c;很高兴认识大家~ ✨主攻领域&#xff1a;【渗透领域】【应急响应】 【python】 【VulnHub靶场复现】【面试分析】 &#x1f389;点赞➕评论➕收藏…

github拉取项目,pycharm配置远程服务器环境

拉取项目 从github上拉取项目到pycharmpycharm右下角选择远程服务器上的环境 2.1. 如图 2.2. 输入远程服务器的host&#xff0c;port&#xff0c;username&#xff0c;password连接 2.3. 选择服务器上的环境 链接第3点 注&#xff1a;如果服务器上环境不存在&#xff0c;先创建…

vue3-内置组件-Teleport

Teleport <Teleport> 是一个内置组件&#xff0c;它可以将一个组件内部的一部分模板“传送”到该组件的 DOM 结构外层的位置去。 基本用法 有时我们可能会遇到这样的场景&#xff1a;一个组件模板的一部分在逻辑上从属于该组件&#xff0c;但从整个应用视图的角度来看…

基于Linux操作系统的Docker容器安装MySQL随笔

1、在Linux上安装Docker容器 cd /etc/yum.repos.d/ curl -O https://download.docker.com/linux/centos/docker-ce.repo sed -i s/$releasever/8/g docker-ce.repo yum install -y docker-ce 2、修改Docker默认镜像仓库&#xff0c;然后启动Docker容器 sudo mkdir -p /etc/do…

yolov8自制数据训练集

目录 1.YOLOv8是啥 2.系统环境 3.安装labelimg 3.1安装 3.2启动 labelimg 4.自制分类图片 4.1 YOLO数据集要求 4.2 图片保存目录 4.3 利用labelimg进行标注 4.4 存储图片 4.5 标注文件 5.数据集训练 5.1yaml文件 5.2训练命令 5.3查看训练过程 5.3.1启动tensorb…

实例分割论文阅读之:FCN:《Fully Convolutional Networks for Semantica Segmentation》

论文地址:https://openaccess.thecvf.com/content_cvpr_2015/papers/Long_Fully_Convolutional_Networks_2015_CVPR_paper.pdf 代码链接&#xff1a;https://github.com/pytorch/vision 摘要 卷积网络是强大的视觉模型&#xff0c;可以产生特征层次结构。我们证明&#xff0c…

Qt网络编程-TCP与UDP

网络基础 TCP与UDP基础 关于TCP与UDP的基础这里就不过多介绍了&#xff0c;具体可以查看对应百度百科介绍&#xff1a; TCP&#xff08;传输控制协议&#xff09;_百度百科 (baidu.com) UDP_百度百科 (baidu.com) 需要知道这两者的区别&#xff1a; 可靠性&#xff1a; TC…

Java面向对象 方法的重写

目录 重写重写的规则实例创建Person类创建Student类测试 重载和重写的区别 重写 发生在子类和父类中&#xff0c;当子类对父类提供的方法不满意的时候&#xff0c;要对父类的方法进行重写。 重写的规则 子类的方法名字和父类必须一致&#xff0c;参数列表&#xff08;个数&…

15章-Python编程:从入门到实践

第15章生成数据 数据可视化指的是通过可视化表示来探索数据&#xff0c;它与数据挖掘数紧密相关&#xff0c;而数据挖掘指的是使用代码来探索数据集的规律和关联。 数据集可以是用一行代码就能表示的小型数字列表&#xff0c;也可以是数以吉字节的数据。漂亮地呈现数据关乎的并…

C++:二叉搜索树模拟实现(KV模型)

C&#xff1a;二叉搜索树模拟实现&#xff08;KV模型&#xff09; 前言模拟实现KV模型1. 节点封装2、前置工作&#xff08;默认构造、拷贝构造、赋值重载、析构函数等&#xff09;2. 数据插入&#xff08;递归和非递归版本&#xff09;3、数据删除&#xff08;递归和非递归版本…