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

news2024/9/20 19:30:57

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    10

int 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 8888

int 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 8888

int 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 8888

int 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.coloradmin.cn/o/1437502.html

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

相关文章

在容器中使用buildah构建镜像

简介 buildah是一个构建OCI标准镜像的工具&#xff0c;可以用来替代docker build 在常见的linux发行版中可直接通过包管理工具安装使用 # centos yum install buildah# ubuntu/debian apt install buildah# alpine apk add buildah其他发行版安装方法详见 github&#xff0c…

RabbitMQ-4.MQ的可靠性

MQ的可靠性 4.MQ的可靠性4.1.数据持久化4.1.1.交换机持久化4.1.2.队列持久化4.1.3.消息持久化 4.2.LazyQueue4.2.1.控制台配置Lazy模式4.2.2.代码配置Lazy模式4.2.3.更新已有队列为lazy模式 4.MQ的可靠性 消息到达MQ以后&#xff0c;如果MQ不能及时保存&#xff0c;也会导致消…

(每日持续更新)jdk api之ObjectInputFilter.FilterInfo基础、应用、实战

博主18年的互联网软件开发经验&#xff0c;从一名程序员小白逐步成为了一名架构师&#xff0c;我想通过平台将经验分享给大家&#xff0c;因此博主每天会在各个大牛网站点赞量超高的博客等寻找该技术栈的资料结合自己的经验&#xff0c;晚上进行用心精简、整理、总结、定稿&…

RabiitMQ延迟队列(死信交换机)

Dead Letter Exchange&#xff08;死信交换机&#xff09; 在MQ中&#xff0c;当消息成为死信&#xff08;Dead message 死掉的信息&#xff09;后&#xff0c;消息中间件可以将其从当前队列发送到另一个队列中&#xff0c;这个队列就是死信队列。而 在RabbitMQ中&#xff0c;由…

dolphinscheduler海豚调度(一)简介快速体验

1、简介 Apache DolphinScheduler 是一个分布式易扩展的可视化DAG工作流任务调度开源系统。适用于企业级场景&#xff0c;提供了一个可视化操作任务、工作流和全生命周期数据处理过程的解决方案。 Apache DolphinScheduler 旨在解决复杂的大数据任务依赖关系&#xff0c;并为应…

Doris中的本地routineload环境,用于开发回归测试用例

----------------2024-2-6-更新-------------- doris的routineload&#xff0c;就是从kafka中加载数据到表&#xff0c;特点是定时、周期性的从kafka取数据。 要想在本地开发测试routine load相关功能&#xff0c;需要配置kafka环境&#xff0c;尤其是需要增加routine load回…

SQL,HQL刷题,尚硅谷

目录 相关表数据&#xff1a; 题目及思路解析&#xff1a; 汇总分析 1、查询编号为“02”的课程的总成绩 2、查询参加考试的学生个数 分组 1、查询各科成绩最高和最低的分&#xff0c;以如下的形式显示&#xff1a;课程号&#xff0c;最高分&#xff0c;最低分 2、查询每门课程…

分享66个行业PPT,总有一款适合您

分享66个行业PPT&#xff0c;总有一款适合您 66个行业PPT下载链接&#xff1a;https://pan.baidu.com/s/1kcUOfR_xtH9CAJC12prcTw?pwd8888 提取码&#xff1a;8888 Python采集代码下载链接&#xff1a;采集代码.zip - 蓝奏云 学习知识费力气&#xff0c;收集整理更不易。知…

ABAP 获取屏幕字段值,field-symbols,assign..TO.. 相关知识实例

ABAP 获取屏幕字段值&#xff0c;field-symbols&#xff0c;assign..TO.. 相关知识实例 以QA32质量放行程序为例子&#xff1a; 由于这个两个值都在结构RQEVA中&#xff0c;为了方便这里获取整个结构值&#xff0c;最后利用指针指向这个程序的这个结构即可获取当前值&#xf…

小红的字符串中值

题目描述: 小红定义一个长度为奇数的字符串的“中值”为中间那个字符。例如"kou"的中值是o。 现在小红拿到了一个字符串&#xff0c;她想知道某个字符是多少个子串的中值。你能帮帮她吗&#xff1f; 输入描述: 输出描述: 一个整数&#xff0c;代表中值为chr的连续子串…

Camunda如何发送邮件及委托代码讲解

&#x1f496;专栏简介 ✔️本专栏将从Camunda(卡蒙达) 7中的关键概念到实现中国式工作流相关功能。 ✔️文章中只包含演示核心代码及测试数据&#xff0c;完整代码可查看作者的开源项目snail-camunda ✔️请给snail-camunda 点颗星吧&#x1f618; &#x1f496;什么是委托…

米贸搜|关于Facebook广告受限:在这些情况下,Meta会限制广告主的广告能力!

如果你被限制了投放广告&#xff0c;那么你会在Facebook上收到通知。 除了审查广告之外&#xff0c;Meta还监控和调查广告主在Meta技术上的行为&#xff0c;在某些情况下&#xff0c;Meta可能会对广告主施加限制&#xff0c;限制广告主的广告能力&#xff0c;这些限制旨在帮助保…

零基础学编程从入门到精通,系统化的编程视频教程上线,中文编程开发语言工具构件之缩放控制面板构件用法

一、前言 零基础学编程从入门到精通&#xff0c;系统化的编程视频教程上线&#xff0c;中文编程开发语言工具构件之缩放控制面板构件用法 编程入门视频教程链接 https://edu.csdn.net/course/detail/39036 编程工具及实例源码文件下载可以点击最下方官网卡片——软件下载—…

鸿蒙OS导入项目报错不能运行 @ohos\hvigor\bin\hvigor.js‘

在自学HarmonyOS时&#xff0c;想在DevEco Studio导入官方示例代码&#xff1a;待办列表&#xff08;ArkTS&#xff09;报错 C:\Users\woods\Downloads\test01\ToDoListArkTS\node_modules\ohos\hvigor\bin\hvigor.js --mode module -p moduleentrydefault -p productdefault …

IDEA上传Gitee出错

问题 今天想通过 IDEA 更下新 gitee 上的代码是发生了这个错误。 解决 在 IDEA 终端输入 git config --system --unset credential.helper原因 在一个大佬那里找到了原因 大概意思是-远端仓库的账号和密码错误&#xff0c;你本地有过账号密码登录记录&#xff0c;但不知道…

板块一 Servlet编程:第一节 HTTP协议理论与服务器请求响应原理 来自【汤米尼克的JAVAEE全套教程专栏】

板块一 Servlet编程&#xff1a;第一节 HTTP协议理论与服务器请求响应原理 一、HTTP特点二、HTTP中的 URL三、两种 HTTP 请求方法&#xff1a;GET 和 POST四、请求响应的底层请求头在服务器中表现响应头在服务器中表现 在上一个板块中我们完成了所有IDEA的基础配置工作&#xf…

【MATLAB】使用梯度提升树在回归预测任务中进行特征选择(深度学习的数据集处理)

1.梯度提升树在神经网络的应用 使用梯度提升树进行特征选择的好处在于可以得到特征的重要性分数&#xff0c;从而识别出对目标变量预测最具影响力的特征。这有助于简化模型并提高其泛化能力&#xff0c;减少过拟合的风险&#xff0c;并且可以加快模型训练和推理速度。此外&…

07-使用Package、Crates、Modules管理项目

上一篇&#xff1a;06-枚举和模式匹配 当你编写大型程序时&#xff0c;组织代码将变得越来越重要。通过对相关功能进行分组并将具有不同功能的代码分开&#xff0c;您可以明确在哪里可以找到实现特定功能的代码&#xff0c;以及在哪里可以改变功能的工作方式。 到目前为止&…

人工智能|深度学习——基于全局注意力的改进YOLOv7-AC的水下场景目标检测系统

代码下载&#xff1a; 基于全局注意力的改进YOLOv7-AC的水下场景目标检测系统.zip资源-CSDN文库 1.研究的背景 水下场景目标检测是水下机器人、水下无人机和水下监控等领域中的重要任务之一。然而&#xff0c;由于水下环境的复杂性和特殊性&#xff0c;水下目标检测面临着许多挑…

有责无权的PM如何管好项目?

一、项目经理的责任和权力分析 项目经理作为项目的责任主体&#xff0c;承担着确保项目顺利完成的重要责任。他们需要确保项目达到预期目标&#xff0c;控制项目进度、成本和质量&#xff0c;并保证项目团队的有效运作。然而&#xff0c;与责任相对应的权力却并不总是与之匹配…