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    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. 发送数据

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

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

ReentrantLock源码分析、LockSuppor、ReentrantReadWriteLock、锁优化的方法

ReentrantLock类图 我们看一下重入锁ReentrantLock类关系图&#xff0c;它是实现了Lock接口的类。NonfairSync和FairSync都继承 自抽象类Sync&#xff0c;在ReentrantLock中有非公平锁NonfairSync和公平锁FairSync的实现。 在重入锁ReentrantLock类关系图中&#xff0c;我们可以…

Rust-获取随机数练习案例

文章目录 前言一、取官网示例猜数字游戏玩一玩cargo checkTOML文件 二、完整代码总结 前言 Rust学习系列-获取随机数练习案例&#xff0c;基于cargo 进行案例练习&#xff0c;过程中会使用cargo check&#xff1b; cargo run&#xff1b;等命名&#xff0c;同时了解基础的let …

flask_django_python五金电商网络营销的可视化分析研究

前面部分完成了系统需求分析&#xff0c;了解到新闻数据业务方面的需求&#xff0c;系统主要分为用户管理、五金信息管理、在线留言、系统管理等功能。销的可视化研究&#xff0c;并对这些数据进行处理&#xff0c; 然后对这些数据进行可视化分析和统计。 Python 爬虫技术目前来…

linux免密登录的实现

ssh免密登录使用方便&#xff0c;关键没有了口令验证反倒规避了暴力破解或者被探测的风险。配置得当&#xff0c;使用ssh免密登录更加安全。在生产环境中应用和数据库服务器之间互相设置后使用方便&#xff0c;并且在第三方人员配置使用时不用告知对方密码。 第一步、ssh登录发…

如何在HA智能家居系统中添加HACS集成并实现异地控制家中苹果与小米设备

文章目录 基本条件一、下载HACS源码二、添加HACS集成三、绑定米家设备 ​ 上文介绍了如何实现群晖Docker部署HomeAssistant&#xff0c;通过内网穿透在户外控制家庭中枢。本文将介绍如何安装HACS插件商店&#xff0c;将米家&#xff0c;果家设备接入 Home Assistant。 基本条件…

第十三篇【传奇开心果系列】Python的OpenCV库技术点案例示例:光流估计

传奇开心果短博文系列 系列短博文目录Python的OpenCV库技术点案例示例:光流估计短博文目录前言一、光流估计介绍二、Lucas-Kanade光流介绍和示例代码三、Horn-Schunck光流介绍和示例代码四、cv::calcOpticalFlowPyrLK()函数实现光流估计介绍和示例代码五、光流估计用于运动分析…

Express框架介绍—node.js

Express—Node.js 官网传送门(opens new window) 基于 Node.js 平台&#xff0c;快速、开放、极简的 Web 开发框架 Express 是用于快速创建服务器的第三方模块。 Express 初体验 基本使用 安装 Express&#xff1a; npm install express创建服务器&#xff0c;监听客户端请…

瑞萨RA6M3开发实践指南-UART实践

1.背景说明 本文是参考瑞萨RA6M3开发实践指南文章教程&#xff0c;基于瑞萨HMI-Board BSP :1.1.1 版本 RT-Thread 5.0.1 版本操作步骤进行记录&#xff0c;整理成的文档。 1.1 本章内容 使用RT-Thread Studio创建开发板的程序&#xff0c;编写UART的程序&#xff0c;实现串口…

跟着pink老师前端入门教程-day19

一、移动WEB开发之流式布局 1、 移动端基础 1.1 浏览器现状 PC端常见浏览器&#xff1a;360浏览器、谷歌浏览器、火狐浏览器、QQ浏览器、百度浏览器、搜狗浏览器、IE浏览器。 移动端常见浏览器&#xff1a;UC浏览器&#xff0c;QQ浏览器&#xff0c;欧朋浏览器&#xff0…

Yolo v8 进行对象数量统计示例

Yolo v8 进行对象数量统计示例 示例代码 from ultralytics import YOLO from ultralytics.solutions import object_counter import cv2def object_count_test():# 权重文件&#xff0c;可替换为自己训练的权重文件model YOLO("yolov8n.pt")# results model.trai…

【码农新闻】 用HTTPS,还能被查出浏览记录吗 常用且好用的在线工具......

目录 【码农新闻】 用HTTPS&#xff0c;还能被查出浏览记录吗 常用且好用的在线工具...... 用HTTPS&#xff0c;还能被查出浏览记录吗常用且好用的在线工具尤雨溪 文章所属专区 码农新闻 欢迎各位编程大佬&#xff0c;技术达人&#xff0c;以及对编程充满热情的朋友们&#xf…

锁优化的方法

减少锁持有时间 减少锁粒度 将大对象拆分成小对象&#xff0c;增加并行度&#xff0c;降低锁竞争。ConcurrentHashMap允许多个线程同 时进入 锁分离 根据功能进行锁分离ReadWriteLock在读多写少时&#xff0c;可以提高性能。 锁消除 锁消除是发生在编译器级别的一种锁优化…

C语言数组练习以及场景练习题

写了那么久的知识点梳理&#xff0c;今天来写点自己觉得不错的练习题来分享&#xff0c;顺便来巩固自己的知识点&#xff0c;和加强题型的解决方法的记忆。今天给大家带来的有数组的找数字题目&#xff0c;以及场景找凶手的题目&#xff0c;下面让我们来看看今天的第一道题目。…

一文带你读懂编码和解码

编码和解码 编码&#xff1a;将字符转换为对应的二进制序列的过程叫做字符编码。 解码&#xff1a;将二进制序列转换为对应的字符的过程叫做字符解码。 py文件的创建&#xff1a; 文本编辑器在内容没有保存前&#xff0c;内容以编辑器默认编码形式保存在内存中。pycharm默认…

我要成为嵌入式高手之2月4、5日Linux高编第二天!!

读写函数接口 1、fgetc 语法&#xff1a; 功能&#xff1a;从流中获取一个字符 练习1&#xff1a;编写程序统计文件的行数 #include <stdio.h>int main(void) {FILE *fp NULL;char ch 0;int row 0;fp fopen("file.txt","r");if (NULL fp){pe…

5 分钟让你了解什么是搜索引擎

文章目录 搜索引擎概述基于业务模式分类垂直搜索&#xff08;垂搜&#xff09;通用搜索&#xff08;通搜&#xff09;本地搜索引擎 基于技术实现分类基于关键词的搜索引擎&#xff08;Keyword-based Search Engine&#xff09;语义搜索引擎&#xff08;Semantic Search Engine&…

好用的大学生教材搜题软件?帮助大学生解决问题的实用搜题工具 #知识分享#知识分享#经验分享

对于大学生来说&#xff0c;每天面对各式各样的学习任务和问题&#xff0c;寻找合适的学习资源和工具成了我们的迫切需求。幸运的是&#xff0c;现如今有许多高效且实用的日常搜题和学习软件可以满足我们的需求&#xff0c;助力我们取得更好的学习成果。 1.Forest专注森林 Fo…

力扣:42. 接雨水 84.柱状图中最大的矩形(单调栈,双指针)

这两道题解题思路类似&#xff0c;一个是单调递增栈&#xff0c;一个是单调递减栈。本篇博客给出暴力&#xff0c;双指针和单调栈解法。 42. 接雨水 题目&#xff1a; 给定 n 个非负整数表示每个宽度为 1 的柱子的高度图&#xff0c;计算按此排列的柱子&#xff0c;下雨之后…

CIFS(Samba)服务的使用

理论部分 概念&#xff1a; 通用互联网文件系统CIFS使用的是公共的或者开放的SMB协议版本。SMB是在会话层和表示层以及小部分应用层上的 协议&#xff0c;使用了NetBIOS的应用程序接口API。该协议在局域网上用于服务器文件访问和打印。它使用客户/服务器模式&#xff0c;客 户…

ffmpeg的使用,安装,抽帧,加水印,截图,生成gif,格式转换,抓屏等

实际使用中总结的关于ffmpeg对视频的处理的记录文档 具体信息&#xff1a; http://ffmpeg.org/download.html 官网下载ffmpeg 关于ffmpeg的安装详细步骤和说明 装ffmpeg 方式,Linux和windows下的 http://bbs.csdn.net/topics/390519382 php 调用ffmpeg , http://bbs.csdn.net/t…