本地进程间通信(二)--套接字socket

2023-05-16

目录

一、什么是Socket? 

二、socket通信流程

Server端

一、创建socket

二、命名socket。

三、绑定

四、监听

五、关闭

Client端

一、创建socket

二、connect

三、发送数据

四、关闭socket


一、什么是Socket? 

套接字除了可以实现网络间不同主机间的通信外,还可以实现同一主机的不同进程间的通信,且建立的通信是双向的通信。本文主要介绍本地进程间socket通信

我们知道两个进程如果需要进行通讯最基本的一个前提能能够唯一的标示一个进程,在本地进程通讯中我们可以使用PID来唯一标示一个进程,但PID只在本地唯一,网络中的两个进程PID冲突几率很大,这时候我们需要另辟它径了,我们知道IP层的ip地址可以唯一标示主机,而TCP层协议和端口号可以唯一标示主机的一个进程,这样我们可以利用ip地址+协议+端口号唯一标示网络中的一个进程。

socket API原本是为网络通讯设计的,可以用于在网络上传送数据,换言之,可实现不同机器上的进程通信过程。但后来在socket的框架上发展出一种IPC机制(IPC:即进程间通信),就是UNIX Domain Socket。虽然网络socket也可用于同一台主机的进程间通讯(通过loopback地址127.0.0.1)。但是UNIX Domain Socket用于IPC更有效率:不需要经过网络协议栈,不需要打包拆包、计算校验和、维护序号和应答等,只是将应用层数据从一个进程拷贝到另一个进程。这是因为,IPC机制本质上是可靠的通讯,而网络协议是为不可靠的通讯设计的。

UNIX Domain Socket也提供面向流和面向数据包两种API接口,类似于TCP和UDP,但是面向消息的UNIX Domain Socket也是可靠的,消息既不会丢失也不会顺序错乱。

UNIX Domain Socket是全双工的,API接口语义丰富,相比其它IPC机制有明显的优越性,目前已成为使用最广泛的IPC机制,比如X Window服务器和GUI程序之间就是通过UNIX Domain Socket通讯的。

使用UNIX Domain Socket的过程和网络socket十分相似,也要先调用socket()创建一个socket文件描述符,address family指定为AF_UNIX,type可以选择SOCK_DGRAMSOCK_STREAM,protocol参数仍然指定为0即可。

UNIX Domain Socket与网络socket编程最明显的不同在于地址格式不同,用结构体sockaddr_un表示(网络socket通信用别的结构体 sockaddr_in),网络编程的socket地址是IP地址加端口号,而UNIX Domain Socket的地址是一个socket类型的文件在文件系统中的路径,这个socket文件由bind()调用创建,如果调用bind()时该文件已存在,则bind()错误返回。

二、socket通信流程

Server端

一、创建socket

创建socket,类型为AF_LOCAL或AF_UNIX,表示用于进程通信。创建套接字需要使用 socket 系统调用,其原型如下:

int socket(int domain, int type, int protocol);

  • domain 参数指定协议族,对于本地套接字来说,其值须被置为 AF_UNIX 枚举值;
  • type 参数指定套接字类型,protocol 参数指定具体协议;type 参数可被设置为 SOCK_STREAM(流式套接字)或 SOCK_DGRAM(数据报式套接字)。对于本地套接字来说,流式套接字(SOCK_STREAM)是一个有顺序的、可靠的双向字节流,相当于在本地进程之间建立起一条数据通道;数据报式套接字(SOCK_DGRAM)相当于单纯的发送消息,在进程通信过程中,理论上可能会有信息丢失、复制或者不按先后次序到达的情况,但由于其在本地通信,不通过外界网络,这些情况出现的概率很小。
  • protocol 字段应被设置为 0;
  • 其返回值为生成的套接字描述符。

socket结构体:

struct socket   
{   
    socket_state              state;   
    unsigned long             flags;   
    const struct proto_ops    *ops;   
    struct fasync_struct      *fasync_list;   
    struct file               *file;   
    struct sock               *sk;   
    wait_queue_head_t         wait;   
    short                     type;   
};

由此,我们清楚了,socket结构体不仅仅记录了本地的IP和端口号,还记录了目的IP和端口。

二、命名socket

这一步对本地进程间通信非常重要,SOCK_STREAM 式本地套接字的通信双方均需要具有本地地址,其中服务器端的本地地址需要明确指定,指定方法是使用 struct sockaddr_un 类型的变量。

struct sockaddr_un {
    sa_family_t     sun_family;     /* AF_UNIX */

    char    sun_path[UNIX_PATH_MAX];        /* 路径名 */
};

这里面有一个很关键的东西,socket进程通信命名方式有两种

  • 普通命名,socket会根据此命名创建一个同名的socket文件,客户端连接的时候通过读取该socket文件连接到socket服务端。这种方式的弊端是服务端必须对socket文件的路径具备写权限,客户端必须知道socket文件路径,且必须对该路径有读权限。
//name the server socket   
server_addr.sun_family = AF_UNIX;  
strcpy(server_addr.sun_path,"/tmp/UNIX.domain");  
server_len = sizeof(struct sockaddr_un);  
client_len = server_len;  
  • 抽象命名空间,这种方式不需要创建socket文件,只需要命名一个全局名字,即可让客户端根据此名字进行连接。后者的实现过程与前者的差别是,后者在对地址结构成员sun_path数组赋值的时候,必须把第一个字节置0,即sun_path[0] =

//name the socket  
server_addr.sun_family = AF_UNIX;  
strcpy(server_addr.sun_path, SERVER_NAME);  
server_addr.sun_path[0]=0;  
server_len = strlen(SERVER_NAME)  + offsetof(struct sockaddr_un, sun_path);  

三、绑定

绑定要使用 bind 系统调用,把一个地址族中的特定地址赋给socket。例如对应AF_INET、AF_INET6就是把一个ipv4或ipv6地址和端口号组合赋给socket。网络编程的socket地址是IP地址加端口号,而本地进程间通信是一个socket类型的文件在文件系统中的路径,这个socket文件由bind()调用创建,如果调用bind()时该文件已存在,则bind()错误返回。其原形如下:
int bind(int socket, const struct sockaddr_un* address, size_t address_len);

int server_sockfd = socket(AF_UNIX,SOCK_STREAM,0);
bind(server_sockfd, (struct sockaddr_un *)&server_address, sizeof(sockaddr_un));

四、监听

服务器端套接字创建完毕并赋予本地地址值后,需要进行监听,等待客户端连接并处理请求,监听使用 listen 系统调用,接受客户端连接使用accept系统调用,它们的原形如下:

int listen(int socket, int backlog);

int accept(int socket, struct sockaddr_un*address, size_t *address_len);
和下面的接口相同
SOCKET accept(SOCKET s, struct sockaddr FAR *addr, int FAR *addrlen);
  • socket 表示服务器端的套接字描述符,即socket()函数返回值;backlog 表示排队连接队列的长度(若有多个客户端同时连接,则需要进行排队);
  • address 表示当前连接客户端的本地地址,该参数为输出参数,是客户端传递过来的关于自身的信息
  • address_len 表示当前连接客户端本地地址的字节长度,这个参数既是输入参数,又是输出参数。实现监听、接受和处理的代码如下:

accept函数主要用于服务器端,一般位于listen函数之后,默认会阻塞进程,直到有一个客户请求连接,建立好连接后,它返回的一个新的套接字 socketfd_new此后,服务器端即可使用这个新的套接字socketfd_new与该客户端进行通信,而原来的sockfd 则继续用于监听其他客户端的连接请求。新建立的套接字不在监听状态,原来所监听的套接字也不受该系统调用的影响。

备注:新建立的套接字准备发送send()和接收数据recv()。

至此,我的困惑产生了,这个新的套接字 socketfd_new 与监听套接字sockfd 是什么关系?它所代表的socket对象包含了哪些信息?socketfd_new 是否占用了新的端口与客户端通信?当客户端发送数据过来的时候,究竟是与哪一个socket对象通信呢?

客户端发送过来的数据可以分为2种,一种是连接请求,一种是已经建立好连接后的数据传输。

 由于TCP/IP协议栈是维护着一个接收和发送缓冲区的。在接收到来自客户端的数据包后,服务器端的TCP/IP协议栈应该会做如下处理:如果收到的是请求连接的数据包,则传给监听着连接请求端口的socetfd套接字,进行accept处理;如果是已经建立过连接后的客户端数据包,则将数据放入接收缓冲区。这样,当服务器端需要读取指定客户端的数据时,则可以利用socketfd_new 套接字通过recv或者read函数到缓冲区里面去取指定的数据(因为socketfd_new代表的socket对象记录了客户端IP和端口,因此可以鉴别)。

#define MAX_CONNECTION_NUMBER 10
int server_client_length, server_client_sockfd;
struct sockaddr_un server_client_address;
listen(server_sockfd, MAX_CONNECTION_NUMBER);
while(1)
{
    // ...... (some process code)
    server_client_length = sizeof(server_client_address);
    server_client_sockfd = accept(server_sockfd, (struct sockaddr*)&server_client_address, &server_client_length);
    // ...... (some process code)
}

read()、write()等函数    

万事具备只欠东风,至此服务器与客户已经建立好连接了。可以调用网络I/O进行读写操作了,I/O操作有下面几组:

  • read()/write()
  • recv()/send()
  • readv()/writev()
  • recvmsg()/sendmsg()
  • recvfrom()/sendto()

我推荐使用recvmsg()/sendmsg()函数,这两个函数是最通用的I/O函数

五、关闭

在服务器与客户端建立连接之后,会进行一些读写操作,完成了读写操作就要关闭相应的socket描述字,好比操作完打开的文件要调用fclose关闭打开的文件。

int close(int socket);

Client端

一、创建socket

这一步同server端,获取client端socket的描述字。client和server的socket创建一般是先server端创建,再client端创建。

二、connect

客户端套接字创建完毕并赋予本地地址值后,需要连接到服务器端进行通信,让服务器端为其提供处理服务。对于 SOCK_STREAM 类型的流式套接字,需要客户端与服务器之间进行连接方可使用。连接成功后,就可以利用这个socketfd描述符使用send/recv函数收发数据了。连接要使用 connect 系统调用,其原形为

int connect(int socket, const struct sockaddr_un*address, size_t address_len);
  • socket为客户端的套接字描述符
  • address表示当前客户端的本地地址,和server端是一样的数据内容,本地文件路径也是同一个,是一个 struct sockaddr_un 类型的变量
  • address_len 表示本地地址的字节长度

三、发送数据

send()

为什么send函数仅仅传入sockfd就可以知道服务器的ip和端口号?

其实,socket的结构体我们已经很清楚了,sockfd 描述符所描述的socket对象不仅包含了本地IP和端口,同时也包含了服务器的IP和端口,这样,才能使得send函数只需要传入sockfd 即可知道该把数据发向什么地方。而代码中,目的IP和端口只是在connect函数中出现过,因此,肯定是connect函数在成功建立连接后,将目的IP和端口写入了sockfd 描述符所描述的socket对象中。

四、关闭socket

这一步同server端

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

本地进程间通信(二)--套接字socket 的相关文章

  • 用户标签体系的意义及设计方法

    我们这次重点谈一下用户标签 对于市场层面 xff0c 用户标签能帮助我们什么 xff1f 1 完善数据仓 之前我们讲过 xff0c 企业或市场要有自己的数据仓来进行线索的存储与培育 xff0c 用户标签就是存在于此 xff0c 我们希望用户
  • 如何设计数据埋点方案?知道这2步就行了

    数据埋点是什么 xff1f 数据埋点是数据产品经理 数据运营以及数据分析师 xff0c 基于业务需求 xff08 例如 xff1a CPC点击付费广告中统计每一个广告位的点击次数 xff09 xff0c 产品需求 xff08 例如 xff1
  • 什么是UTM参数?这些你知道吗

    现在移动互联网发展比较迅速 xff0c 而且现在很多人都在做公众号 xff0c 公众号也要有自己的特色 xff0c 这样才能给自己的产品带来利益 现在也有很多的人关注APP运营 xff0c APP运营工作中的每一步都会讲求ROI xff08
  • 用户触达方式及用户触达渠道选择

    任何用户运营过程总离不开用户触达渠道的连接 可以说 xff0c 触达渠道的组合选择 xff0c 是与你最终运营效果直接挂钩的 xff0c 用户触达方式的选择直接影响了你运营的结果 如何做精准的用户触达 如何选择不同的用户触达方式 如何最大限
  • 用户行为分析之渠道分析、转化分析、留存分析

    数据分析脱离不了业务 xff0c 不同的业务所关注的数据不同 xff0c 比如互联网 快消等 xff0c 行业不同 xff0c 关注的数据点也不同 在互联网行业普遍产品的数据分析中 xff0c 我认为用户行为分析最重要的三个点是渠道分析 转
  • 通过用户分级实现精细化运营

    10年前 xff0c pc互联网时代 xff0c 当你浏览百度的网页 xff0c 你会普遍看到各种插件推广 弹窗广告等等 xff0c 这些弹窗就好似牛皮癣一样 xff0c 想关掉都不行 用户体验极其不好 xff0c 这是一个 卖方 占绝对优
  • 如何进行流失用户召回?做到这三步!

    如果按照每天渠道投放获客1000名 xff0c 次日留存率40 来算 xff0c 每天会有60 的用户 xff0c 第二天就再也不打开我们的APP xff0c 最终成为了流失用户 平均每日损失几百到数万元不等 虽然相比动辄几百万到几千万的融
  • Spring使用到的设计模式

    Spring涉及到的设计模式 简单工厂模式工厂模式单例模式适配器装饰器模式 Decortor代理模式观察者模式策略模式模板模式 简单工厂模式 一个工厂类根据传入的参数 xff0c 动态决定创建哪一个类 public abstract cla
  • 路由协议的优先级

    对于相同的目的地 xff0c 不同的路由协议 xff08 包括静态路由 xff09 可能会发现不同的路由 xff0c 但这些路由并不都是最优的 事实上 xff0c 在某一时刻 xff0c 到某一目的地的当前路由仅能由唯一的路由协议来决定 为
  • 自己动手写操作系统 将引导程序成功写入优盘启动电脑

    原文 xff1a http freesoftman iteye com blog 629598 输入命令 xff1a nasm boot asm o boot bin 一会儿就生成了一个镜像文件boot bin 该文件就是我所谓的操作系统了
  • 关于C语言等高级语言能不能直接控制硬件的问题

    关于C语言等高级语言能不能直接控制硬件的问题 xff0c 我认为C语言等高级语言不能直接控制硬件 这里谈论的问题本质是 xff0c C语言等高级语言能不能直接对硬件进行编程 我认为 xff0c 不能 众所周知 xff0c 计算机之初的程序员
  • scanf函数输入字符 %c之前要有空格分析

    问题描述如下 xff1a test c int main void int n 61 0 char c while 1 scanf 34 c 34 amp c printf 34 c d n 34 c 43 43 i return 0 这段
  • Linux0.11内核 进程睡眠和唤醒

    当进程等待资源或者事件时 xff0c 就进入睡眠状态 有两种睡眠态 xff0c 不可中断睡眠态 xff08 TASK UNINTERRUPTIBLE xff09 和可中断睡眠态 xff08 TASK INTERRUPTIBLE xff09
  • ubuntu linux 触控板失灵的解决方案

    这几天研究内核的模块机制 xff0c 接触到了一些关于模块的操作命令 xff0c 比如lsmod命令可以列出内核中已经安装的模块 xff0c insmod命令可以安装一个指定的模块 xff0c rmmod可以删除一个指定的模块 也是处于好奇
  • Linux 安装远程桌面并设置添加分辨率

    本来想用本地的kali linux来远程登陆centos的服务器 xff0c 在远程服务器安装VM xff0c 再VM里安装Windows虚拟机 xff0c 用作工作娱乐需要 xff0c 尼玛八颗八核至强CPU xff0c 128G内存 x
  • 将数据库文件导入mysql并输出为txt文件

    大致上MySQL数据库备份可以采用两种方式 xff1a 一种就是直接导出sql语句或者易于导入的其他格式的sql存储文件 xff0c 使用sql语句或者一些可视化客户端导出 xff0c 这种方法非常简单 xff0c 无需赘述 xff1b 另
  • golang gorilla/mux设置静态目录

    发现网上都是类似下面的代码 96 96 96 s 61 34 Users golang golang 34 http Handle 34 static 34 http StripPrefix 34 static 34 http FileSe
  • ios系统removeCachedResponseForRequest无效的替代方案

    相信你能找到我这篇博客 xff0c 肯定是对URLCache缓存有了深刻的理解 xff0c 并且被ios系统api removeCachedResponse ForRequest使用起来并不能删除指定的缓存所困惑 其实也可以自己想办法来模拟
  • DHCPv6报文介绍

    摘自HUAWEI官网 DHCPv6报文格式如图11 2所示 图11 2 DHCPv6的报文格式 表11 1 DHCPv6报文中各个字段的含义 字段 长度 含义 msg type 1字节 表示报文的类型 xff0c 取值为1 xff5e 13
  • vnc服务器的搭建

    vnc服务的概述 xff1a VNC Virtual Network Computing 虚拟网络计算机的缩写 xff0c 主要是完成图形界面的远程控制使用 一个vnc系统是由客户端 服务器端和一个协议组成 服务器是分享其屏幕 xff0c

随机推荐

  • openwrt配置wifi桥接上级AP,再作为ap路由(可实现ip透传,例如远距离图像传输)

    第一步 上级ap配置为 接入点AP xff08 WDS xff09 xff0c 例如无人机的飞机端作为wds ap a xff0c 无线概况里点击修改 b xff0c ESSID改为你想要的名字 xff0c 要选择固定信道 xff08 非常
  • 菜鸟学Linux命令:ssh命令

    转载自品略图书馆 http www pinlue com article 2020 04 1003 1210139769049 html 1 查看SSH客户端版本 有的时候需要确认一下SSH客户端及其相应的版本号 使用ssh V命令可以得到
  • STM32串口发送数据

    串口通信经常作为开发调试的工具 xff0c 所以先介绍下串口通信 串口通讯 Serial Communication 是一种设备间非常常用的串行通讯方式 xff0c 因为它简单便捷 xff0c 大部分电子设备都支持该通讯方式 xff0c 电
  • npm ERR! code EINTEGRITY 解决方案

    报错信息 xff1a Error sha1 HsihLT8VutOkAReGpzpIZJY2twQ 61 integrity checksum failed when using sha1 wanted sha1 HsihLT8VutOkA
  • VScode搭建C/C++开发环境

    目录 1 VScode是什么 xff1f 2 VScode的下载和安装 2 1下载和安装 下载 xff1a 安装 xff1a 2 2环境的介绍 环境介绍 xff1a 安装中文版插件 xff1a 3 VScode配置C C 43 43 开发环
  • 从0开始跑通VINS FUSION(KITTI数据集)

    背景 xff1a VINS FUSION是香港科技大学在VINS MONO后做的推出的多功能版 xff0c 有双目的数据 xff0c 还有和GPS的融合 作为一个SLAM小白 xff0c 记录一下整个的跑通过程 代码连接 xff1a htt
  • ubuntu关于aptitude和apt-get

    起初GNU Linux系统中只有 tar gz 用户 必须自己编译他们想使用的每一个程序 在Debian出现之後 xff0c 人们认为有必要在系统 中添加一种机 制用来管理 安装在计算机上的软件包 人们将这套系统称为dpkg 至此着名的 p
  • C语言链表的简单编写

    代码分为3个部分 xff0c test c head h list c list c封装的函数 include 34 head h 34 创建一个空链表 Linklist list creat 申请一断空间 Linklist L L 61
  • java中a=a++;a=a+1;a+=1执行过程分析

    本文章内容前提是a数据类型为int 当a数据类型为int时 xff0c 执行a 61 a 43 43 后 xff0c a的数值不会变 xff1b 执行a 61 a 43 1后 xff0c 数值加1 xff1b 执行a 43 61 1后 xf
  • 【VPN(虚拟专用网)攻略大全】

    在 VPN 出现之前 xff0c 企业分支之间的数据传输只能依靠现有物理网络 xff08 例如 Internet xff09 由于 Internet 中存在多种不安全因素 xff0c 报文容易被网络中的黑客窃取或篡改 xff0c 最终造成数
  • Linux 如何检测硬盘坏道?

    在 Mac 和 Windows 下检测硬盘坏道有专门的工具 xff0c 或自带 或三方的都挺好用 xff0c 但是如何在 Linux 下检测硬盘坏道呢 xff1f 首先 xff0c 用 lsblk 命令查看下待检测硬盘的名字 xff1a 然
  • 图论-路径优化算法总结

    知乎主页 https www zhihu com people shuang shou cha dai 53 目录 1 xff1a Dijkstra算法 1 1 xff1a 算法思想 1 2 xff1a 算法步骤 1 3 xff1a 代码演
  • uORB发布订阅实例

    PX4SITL仿真 uORB实例 飞控串口读取外部传感器数据 xff1a 飞控开启一个进程读取外部传感器数据 xff0c 发布一个uORB主题 xff1b 另一个进程订阅前一个进程发布的主题 xff0c 订阅到的主题通过mavlink消息发
  • PX4仿真环境搭建

    PX4 SITL Simulation 前提准备 xff1a Ubuntu16 04 LTS 安装ROS kinetic 题外话 xff1a 如果连的是有IPV6的校园网 xff0c 在update时可能会访问IPV6地址出错 xff0c
  • PX4-Gazebo仿真学习笔记

    PX4 Gazebo仿真 xff1a http bbs amovauto com forum php mod 61 viewthread amp tid 61 486 amp extra 61 page 3D1 Simulator仿真器 x
  • C语言strtok函数

    1 strtok 语法 include lt string h gt char strtok char str const char delimiters 参数 xff1a str xff0c 待分割的字符串 xff08 c string
  • 终于把大数据类产品全流程解释清楚了

    你点开这文章 xff0c 说明你清晰知道了数据才是一切的基础 人工智能 机器学习 大数据等应用的基础都是基于这样的一个流程 xff0c 只是说运用领域不同 xff0c 那么偏重点不同 本文从数据采集到数据报告 xff0c 详细说明了大数据运
  • 关于slam

    什么是SLAM 机器人在未知环境中 xff0c 要实现智能化需要完成三个任务 xff0c 第一个是定位 Localization xff0c 第二个是建图 Mapping xff0c 第三个则是随后的路径规划 Navigation 之前地平
  • Linux(Ubuntu系统)同网段SSH连接不上,网络能ping通

    问题描述 测试以下命令同样连接不上 span class token function ssh span localhost 问题原因 Ubuntu系统自带 openssh client xff0c 但是没有自带 openssh serve
  • 本地进程间通信(二)--套接字socket

    目录 一 什么是Socket xff1f 二 socket通信流程 Server端 一 创建socket 二 命名socket 三 绑定 四 监听 五 关闭 Client端 一 创建socket 二 connect 三 发送数据 四 关闭s