到底什么是Socket

到底什么是Socket,第1张

本系列文章前面那些主要讲解的是计算机网络的理论基础,但对于即时通讯IM这方面的应用层开发者来说,跟计算机网络打道的其实是各种API接口。

本篇文章就来聊一下网络应用程序员最熟悉的Socket这个东西,抛开生涩的计算机网络理论,从应用层的角度来理解到底什么是Socket。

对于 Socket 的认识,本文将从以下几个方面着手介绍:

1) Socket 是什么;

2) Socket 是如何创建的;

3) Socket 是如何连接的;

4) Socket 是如何收发数据的;

5) Socket 是如何断开连接的;

6) Socket 套接字的删除等。

特别说明: 本文中提到的“Socket”、“网络套接字”、“套接字”,如无特殊指明,指的都是同一个东西哦。

Socket 是什么

一个数据包经由应用程序产生,进入到协议栈中进行各种报文头的包装,然后 *** 作系统调用网卡驱动程序指挥硬件,把数据发送到对端主机。

我们大家知道,协议栈其实是位于 *** 作系统中的一些协议的堆叠,这些协议包括 TCP、UDP、ARP、ICMP、IP等。即时通讯开发可以找蔚可云开发。

通常某个协议的设计都是为了解决特定问题的,比如:

1) TCP 的设计就负责安全可靠的传输数据;

2) UDP 设计就是报文小,传输效率高;

3) ARP 的设计是能够通过 IP 地址查询物理(Mac)地址;

4) ICMP 的设计目的是返回错误报文给主机;

5) IP 设计的目的是为了实现大规模主机的互联互通。

应用程序比如浏览器、电子邮件、文件传输服务器等产生的数据,会通过传输层协议进行传输。而应用程序是不会和传输层直接建立联系的,而是有一个能够连接应用层和传输层之间的套件,这个套件就是 Socket 。

应用程序的下面: 就是 *** 作系统内部, *** 作系统内部包括协议栈,协议栈是一系列协议的堆叠。

*** 作系统下面: 就是网卡驱动程序,网卡驱动程序负责控制网卡硬件,驱动程序驱动网卡硬件完成收发工作。

在 *** 作系统内部有一块用于存放控制信息的存储空间,这块存储空间记录了用于控制通信的控制信息。其实这些控制信息就是 Socket 的实体,或者说存放控制信息的内存空间就是Socket的实体。

这里大家有可能不太清楚所以然,所以我用了一下 netstat 命令来给大伙看一下Socket是啥玩意。

Socket 是如何创建的

通过上节的讲解,现在你可能对 Socket 有了一个基本的认识,先喝口水,休息一下,让我们继续探究 Socket。

现在我有个问题, Socket 是如何创建的呢?

Socket 是和应用程序一起创建的。

应用程序中有一个 socket 组件,在应用程序启动时,会调用 socket 申请创建Socket,协议栈会根据应用程序的申请创建Socket:首先分配一个Socket所需的内存空间,这一步相当于是为控制信息准备一个容器,但只有容器并没有实际作用,所以你还需要向容器中放入控制信息;如果你不申请创建Socket所需要的内存空间,你创建的控制信息也没有地方存放,所以分配内存空间,放入控制信息缺一不可。至此Socket的创建就已经完成了。

Socket创建完成后,会返回一个Socket描述符给应用程序,这个描述符相当于是区分不同Socket的号码牌。根据这个描述符,应用程序在委托协议栈收发数据时就需要提供这个描述符。

Socket 是如何连接的

Socket创建完成后,最终还是为数据收发服务的。但是,在数据收发之前,还需要进行一步“连接”(术语就是 connect),建立连接有一整套过程。

实际上这个“连接”是应用程序通过 TCP/IP 协议标准从一个主机通过网络介质传输到另一个主机的过程。

Socket刚刚创建完成后,还没有数据,也不知道通信对象。

在这种状态下: 即使你让客户端应用程序委托协议栈发送数据,它也不知道发送到哪里。所以浏览器需要根据网址来查询服务器的 IP 地址,查询到目标主机后,再把目标主机的 IP 告诉协议栈。至此,客户端这边就准备好了。

在服务器上: 与客户端一样也需要创建Socket,但是同样的它也不知道通信对象是谁,所以我们需要让客户端向服务器告知客户端的必要信息: IP 地址和端口号 。

现在通信双方建立连接的必要信息已经具备,可以开始“连接”过程了。

首先: 客户端应用程序需要调用 Socket 库中的connect方法,提供 socket 描述符和服务器 IP 地址、端口号。

以下是connect的伪码调用:

1connect(<描述符>、<服务器IP地址和端口号>)

这些信息会传递给协议栈中的 TCP 模块,TCP 模块会对请求报文进行封装,再传递给 IP 模块,进行 IP 报文头的封装,然后传递给物理层,进行帧头封装。

之后通过网络介质传递给服务器,服务器上会对帧头、IP 模块、TCP 模块的报文头进行解析,从而找到对应的Socket。

Socket收到请求后,会写入相应的信息,并且把状态改为正在连接。

请求过程完成后: 服务器的 TCP 模块会返回响应,这个过程和客户端是一样的

Socket 是如何收发数据的

当控制流程上节中的连接过程回到应用程序之后,接下来就会直接进入数据收发阶段。

数据收发 *** 作是从应用程序调用 write 将要发送的数据交给协议栈开始的,协议栈收到数据之后执行发送 *** 作。

协议栈不会关心应用程序传输过来的是什么数据,因为这些数据最终都会转换为二进制序列,协议栈在收到数据之后并不会马上把数据发送出去,而是会将数据放在发送缓冲区,再等待应用程序发送下一条数据。

为什么收到数据包不会直接发送出去,而是放在缓冲区中呢?

因为只要一旦收到数据就会发送,就有可能发送大量的小数据包,导致网络效率下降(所以协议栈需要将数据积攒到一定数量才能将其发送出去)。

至于协议栈会向缓冲区放多少数据,这个不同版本和种类的 *** 作系统有不同的说法。

本文提出了 IBM JSSE(Java Secure Socket Extension Java 安全套接字扩展)的配置问题 探讨了密钥库和信任库 并且对于如何在 IBM WebSphere Application Server 环境下处理这些重要的 JSSE 元素提出了的建议 引言 Java 安全套接字扩展(Java Secure Socket Extension JSSE)是将低级编程接口封装到安全套接字层(Secure Socket Layer SSL)协议及其相应的标准传输层安全性(Transport Layer Security TLS)协议中的 Java 标准 IBM JSSE 是 JSSE 框架的 Java 实现 它支持 SSL V 和 V 以及 TLS V 将 JSSE 这样架构以便其能够提供两套接口 一套被称为服务提供方接口(Service Provider Interface SPI) 而另一套是应用程序编程接口(Application Programming Interface API) 那些提供特定实现的功能插件使用提供的程序接口(本质上 是接口中的插件) 通常 应用程序开发人员仅处理 API 他们可以编写可移植的代码 该代码仅依赖于标准的公共 API 中公布的方法 IBM JSSE 实现也包括 IBM JSSE 加密提供方 重要的是 开发人员应该遵循最佳的编程实践来启用应用程序的可移植性 只要没有将提供应用程序的特定信息的用法嵌入或强制编码到应用程序中 JSSE API 就可以进行移植 IBM 没有声明与其它 JSSE 提供方的互 *** 作性 IBM 开发实验室没有执行任何正式的测试 分离 API 和 SPI 接口的目的在于保护来源于程序提供者的应用程序 以便达到可移植性 但每个程序提供者所提供的功能可能不必与其它提供的功能相匹配 IBM JSSE 包括了 IBM 的提供方 而其他供应商拥有自己的提供方 当使用 WebSphere Application Server 时 例如 我们重在 IBM 自己的提供方 因此 应用程序代码假设任何特殊的提供方都是不可移植的 一个公共实例是显式地装载了 sun 类的应用程序代码 由于 sun 不是 JSSE(或者对于那种情况是 J SE)的一部分 所以这样的代码是不可移植的 当您开发您的代码时 应该尽量避免程序提供者所特有的依赖 我们此处的实例说明了这种方法 简化 JSSE 编程很大程度上是由于高级别的抽象 它提供了关于标准套接字的编程接口 这使得在两个希望使用 TCP/IP 协议上的传输层安全性来进行消息传递的终端之间建立网络连接变得非常容易 由 JSSE 提供的安全 是由传输层消息完整性 可靠性(加密) 服务器验证 以及可选的客户端验证组成 在本文中 我们提出了 IBM JSSE 的配置问题 探讨了密钥库和信任库 并且推荐了在 WebSphere Application Server 环境下处理这些重要的 JSSE 元素的方法 随后 我们给出了 JSSE 编程模型并且说明当访问 >

摘要: docker , linux

一般都是用root用户启动和 *** 作docker,当是普通用户运行容器启动项目时报错没有权限

docker守护进程后台启动时,需要读取Unix套接字 /var/run/dockersock ,这个文件root所有,docker用户组可 *** 作,因此普通非docker组的用户没有权限访问

类似的MySQL客户端也可以使用socket进行连接,文件在/var/run/mysqld/mysqldsock

默认是777权限,如果改成770,则非root用户或者非mysql组用户也将无法连接MySQL

退出root用户,普通用户无法报错无法通过socket连接

本质上还是使用root运行docker,只是在启动的时候可以以root用户启动docker,为了避免每次启动需要输入密码,需要给普通用户sudo权限以及可以免密码方式登录。

在/etc/sudoers文件中设置免密码

此时再使用sudo运行docker即可,在其他shell脚本中docker run前面增加sudo

如果不使用sudo则无权限 *** 作docker

docker安装之后默认会创建docker组,docker组拥有读取套接字权限,因此将该普通用户加入docker组,该组下所有用户有访问unix套接字权限,最后刷新用户的初始组即可。

先查看是否有docker用户,如果没有需要手动增加

如果/var/run/dockersock的用户组不是docker而是root需要使用 chgrp 修改一下

将普通用户添加到docker组

此时查看test用户所在的组

发现还是没有docker组,使用 newgrp 刷新以下用户的初始组

此时再次查看用户的组以已经出现docker

然后直接以用户 *** 作docker即可

或者不使用newgrp直接重新登录即可

gpasswd是linux下组管理工具,用户添加用户到组和从组中删除用户,必须是sudo执行

测试删除和添加test用户于docker组

此时退出终端重新登录则test的docker组消失,再添加进来

添加之后在当前终端不能立刻生效,需要使用newgrp将新增加的组添加到用户组的集合中刷新,立即生效

以后退出登录后新登录进来用户的用户组都会更新生效

Docker 提供了一个与 Docker 守护进程交互的 API (称为Docker Engine API),我们可以使用官方提供的 Go 语言的 SDK 进行构建和扩展 Docker 应用程序和解决方案。

转自:>

本文通过实验,帮助大家认识docker swarm中的overlay和docker_gwbridge网络。

先建立两台物理机组成的docker swarm网络(方法可见 《docker swarm(一): 入门,搭建一个简单的swarm集群》 ):

创建一个overlay网络。

当前建立的docker相关的网络有:

这里关注两个网络:

我们知道,docker是基于namespace,划分了网络空间。这里先准备一段脚本,由于在各个namespece中,执行对应的网络命令。

它可以查看有哪些namespace:

还可以在指定的namespace下执行命令:

第二个工具,find_linkssh

这个脚本可以根据ifindex查找接口所在的namespace。

以下,我们通过实验,了解一下overlay网络与docker_gwbridge网络。

我们现在在两个nodes上都创建容器:

在容器的环境下,查看一下网络连接:

我们发现,除了回环口外,还有两个接口。1020002/16即是容器busybox在overlay_test网络上的接口的IP地址。1721803/16是容器busybox在docker_gwbridge网络上的接口的IP地址。

到目前为止,我们看到的容器网络是这样的。我们只看到了网络地址,还不知道它们间的报文是如何交互的。(1921681542是宿主机的网关)

我们尝试从容器内跟踪访问外部IP的路由

可见,流量经过1721801,然后访问到宿主机网关上。

接下来,我们尝试解析出内部网络连接。上面我们已经得知,从容器内部的视角,1721803所在的接口为:61: eth1@if62。我们可以理解为,此接口的ifindex为61,通过veth连接到ifindex为62的接口上。

我们查找看看62接口的namespace是:

居然没有显示。这就说明62接口是在宿主机的主namespace中的。我们在宿主机上看看:

可见,62接口的master是docker_gwbridge。也就是说,62接口被桥接到docker_gwbridge中。

南北向流量在经过宿主机出口时,还做了NAT转换

于是,南北向的流量走向就很清晰了。我们的网络拓扑可以更新为:

东西向流量即容器与容器间的流量。我们先测试一下容器间的连通性。

接下来探索这个流量是怎么走的。我们再看一下容器中的网络配置。

1020002所在的接口为,59: eth0@if60。即本接口ifindex为59,连接到ifindex为60的接口上。我们查询一下60接口所在的namespaec。

可见60接口处于1-hxyiridl2b这一namespace中。

在这个namespace中,有一个vxlan出口。docker overlsy就是通过overlay隧道与其它容器通信的。

两个容器虽然是通过vxlan隧道通信,但容器内部却不感知。它们只能看到两个容器处于同一个二层网络中。由vxlan接口将二层报文封装在UDP报文的payload中,发到对端,再由对端的vxlan接口解封装。

我们查看一下namespace 1-hxyiridl2b中的arp地址表:

我们可以看到,远端node中的容器IP 1020004,有体现在本端的arp地址表中。即是通过查找此表,得到对端的二层地址。

我们再来看看,vxlan报文的出口在哪里:

这可以理解为VxLAN的VTEP表,即根据MAC地址,查找出VxLAN报文应该封装的外层IP,是192168154136

我们可以画出东西向流量的完整的拓扑了:

我们还是从计算机的网络层说起,主要是分为7个层分别是物理层,数据链路层,网络层,传输层,会话层,表示层,应用层。

数据之间的交互主要在传输层这一块。通常用到的底层协议有TCP和UDP这两种协议。通过中间层SOCKET协议,进行包装,再往上就是我们经常用到的>

>

上面这个就是我们网站的>

同时我们的实时聊天软件,比如今日头条的聊天软件就是通过TCP,SOCKET来进行通信的,这种是面向连接的长链接方式,双向通信。响应指定封包协议和解包协议,通过socket的处理,去监听两端的端口,分别获取各自的数据,和发送各自的数据。实现双向通信。具体过程如下:

>客户端步骤

1创建套接字

2向服务器发送连接请求(connect)

3通信(send/recv)

4关闭套接字

>服务器端步骤

1创建用于监听的套接字(socket)

2将套接字绑定到本地地址和端口上(bind)

3将套接字设为监听模式(listen)

4等待客户请求(accept),此处要不断的调用accept

5通信(send/receive),完成后返回4

6关闭套接字(closesocket)

谢谢阅读,欢迎关注。

MessageBox(指明主窗口,提示信息,d出窗口标题,按键类型<MB_OK指确定按钮>)

MessageBoxA用ASIIC编码,MessageBox和MessageBoxW用Unicode编码。

socket()函数错误返回INVALID_SOCKET;connet()函数返回int,0为连接正常。

iterator泛型指针可指向任意的类型,如:

map<string,string>::iterator iter

map为一对一的键值对容器<Key,Value>,Key不能重复

sprintf(内存单元,"%d"<%s等>,长度)函数格式化输出到内存中的一块单元

初始化char数组的一个方法,如下表示将每个元素初始化为/0

char buffer[length];

memset(buffer,0,length);

atoi(char数组)函数将char数组转换成int

send()、recv()函数发送和接受套接字

以上就是关于到底什么是Socket全部的内容,包括:到底什么是Socket、在 WAS 中使用 Java 安全套接字扩展(图)、Docker:非root用户启动 *** 作docker等相关内容解答,如果想了解更多相关内容,可以关注我们,你们的支持是我们更新的动力!

欢迎分享,转载请注明来源:内存溢出

原文地址: https://outofmemory.cn/web/9805387.html

(0)
打赏 微信扫一扫 微信扫一扫 支付宝扫一扫 支付宝扫一扫
上一篇 2023-05-02
下一篇 2023-05-02

发表评论

登录后才能评论

评论列表(0条)

保存