浅谈网络九-你真的知道Socket是什么吗?

  • 时间:2018-12-25 22:38 作者:Lucien可还行 来源:Lucien可还行 阅读:650
  • 扫一扫,手机访问
摘要:Socket 一说起来一定都并不陌生,大概一说出来所有人的第一反应就是,这是个做端到端长连接通信的。一点问题没有,很对。但是假如要是有人问起,基于UDP的Socket和基于TCP的Socket有什么区别?一个Socket的连接都经历了什么?监听Socket和真正Socket传输是一个Socket吗?

Socket 一说起来一定都并不陌生,大概一说出来所有人的第一反应就是,这是个做端到端长连接通信的。一点问题没有,很对。但是假如要是有人问起,基于UDP的Socket和基于TCP的Socket有什么区别?一个Socket的连接都经历了什么?监听Socket和真正Socket传输是一个Socket吗?Socket编程都要设置啥参数?等等的一系列问题。假如这些问题你能够做到胸有成竹,大概这边文章对你也没啥用处。假如想要理解下的可以接着往下看。

建立Socket需要设置很多参数?

并不是的,其实学习它并不需要记住很多乱七八糟意义的参数,由于Socket 编程进行的是端到端的通信,往往意识不到中间经过多少局域网,多少路由,,因此能够设置的参数,也只能是端到端协议之上网络层和传输层的。

在网络层,Socket 函数需要指定究竟是 IPv4 还是 IPv6,分别对应设置为 AF_INET 和 AF_INET6。另外,还要指定究竟是 TCP 还是 UDP。TCP 协议是基于数据流的,所以设置为 SOCK_STREAM,而 UDP 是基于数据报的,因此设置为 SOCK_DGRAM。

监听Socket和真正Socket传输是一个Socket吗?

上面讲到了,Socket会分为是基于TCP的还是基于UDP的。

对于TCP而言,首先说明,监听和传输并不是一个Socket。为什么呢?那就要先说明下基于TCP的Socket的连接过程。

TCP 的服务端要先监听一个端口,一般是先调用 bind 函数,给这个 Socket 赋予一个 IP 地址和端口。当服务端有了 IP 和端口号,即可以调用 listen 函数进行监听。在 TCP 的状态里面,有一个 listen 状态,当调用这个函数之后,服务端就进入了这个状态,这个时候用户端即可以发起连接了。在内核中,为每个 Socket 维护两个队列。一个是已经建立了连接的队列,这时候连接三次握手已经完毕,处于 established 状态;一个是还没有完全建立连接的队列,这个时候三次握手还没完成,处于 syn_rcvd 的状态。接下来,服务端调用 accept 函数,拿出一个已经完成的连接进行解决。假如还没有完成,就要等着。在服务端等待的时候,用户端可以通过 connect 函数发起连接。先在参数中指明要连接的 IP 地址和端口号,而后开始发起三次握手。内核会给用户端分配一个临时的端口。一旦握手成功,服务端的 accept 就会返回另一个 Socket。

对于 UDP 来讲,过程有些不一样。UDP 是没有连接的,所以不需要三次握手,也就不需要调用 listen 和 connect,但是,UDP 的的交互依然需要 IP 和端口号,因此也需要 bind。UDP 是没有维护连接状态的,因此不需要每对连接建立一组 Socket,而是只需有一个 Socket,就能够和多个用户端通信。也正是由于没有连接状态,每次通信的时候,都调用 sendto 和 recvfrom,都可以传入 IP 地址和端口。

基于TCP和基于UDP的Socket连接过程是怎么的?

图一.连接过程

上面基本详情了Socket的连接过程,不过需要注意的是以下几点:

1.TCP的服务端要先监听一个端口,一般是先调用 bind 函数,给这个 Socket 赋予一个 IP 地址和端口。为什么需要端口呢?要知道,你写的是一个应用程序,当一个网络包来的时候,内核要通过 TCP 头里面的这个端口,来找到你这个应用程序,把包给你。

2.基于TCP的Scoket为什么要 IP 地址呢?有时候,一台机器会有多个网卡,也就会有多个 IP 地址,你可以选择监听所有的网卡,也可以选择监听一个网卡,这样,只有发给这个网卡的包,才会给你。

3.说 TCP 的 Socket 在 Linux 中就是以文件的形式存在的。除此之外,还存在文件形容符。写入和读出,也是通过文件形容符。

有限的服务器资源如何接更多的连接?

首先没事下为什么要考虑这个问题?答案很简单,就是如何在有限的资源内支持更多的连接。

一般来说,服务器通常固定在某个本地端口上监听,等待用户端的连接请求。因而,服务端端 TCP 连接四元组中只有对端 IP, 也就是用户端的 IP 和对端的端口,也即用户端的端口是可变的,因而,最大 TCP 连接数 = 用户端 IP 数×用户端端口数。对 IPv4,用户端的 IP 数最多为 2 的 32 次方,用户端的端口数最多为 2 的 16 次方,也就是服务端单机最大 TCP 连接数,约为 2 的 48 次方。

当然,服务端最大并发 TCP 连接数远不能达到理论上限。首先主要是文件形容符限制,按照上面的原理,Socket 都是文件,所以首先要通过 ulimit 配置文件形容符的数目;另一个限制是内存,按上面的数据结构,每个 TCP 连接都要占用肯定内存,操作系统是有限的。

这里我提出一个现在我个人觉得最好的一种方式:基于消息的IO多路复用。

所谓的多路复用浅显的类比一个例子就是,一个项目组照看多个项目,每个项目组都应该有个项目进度墙,将自己组看的项目列在那里,一旦某个项目有了进展,就派人去盯一下。这个“项目进度墙”,是指一个文件形容符集合 fd_set ,因为 Socket 是文件形容符,所以某个线程盯的所有的 Socket,都会被存放在里面。

假如有了改变,就会触发事件进行通知,从而进行解决。能完成这件事情的函数叫 epoll,它在内核中的实现不是通过轮询的方式,而是通过注册 callback 函数的方式,当某个文件形容符发送变化的时候,就会主动通知。

图二.监听示例

如图所示,假设进程打开了 Socket m, n, x 等多个文件形容符,现在需要通过 epoll 来监听能否这些 Socket 都有事件发生。其中 epoll_create 创立一个 epoll 对象,也是一个文件,也对应一个文件形容符,同样也对应着打开文件列表中的一项。在这项里面有一个红黑树,在红黑树里,要保存这个 epoll 要监听的所有 Socket。

当 epoll_ctl 增加一个 Socket 的时候,其实是加入这个红黑树,同时红黑树里面的节点指向一个结构,将这个结构挂在被监听的 Socket 的事件列表中。当一个 Socket 来了一个事件的时候,可以从这个列表中得到 epoll 对象,并调用 call back 通知它。

这种通知方式使得监听的 Socket 数据添加的时候,效率不会大幅度降低,能够同时监听的 Socket 的数目也非常的多了。上限就为系统定义的、进程打开的最大文件形容符个数。因此,epoll 被称为处理 C10K 问题的利器。

  • 全部评论(0)
最新发布的资讯信息
【系统环境|】2FA验证器 验证码如何登录(2024-04-01 20:18)
【系统环境|】怎么做才能建设好外贸网站?(2023-12-20 10:05)
【系统环境|软件环境】梦幻仙域游戏攻略(2023-12-19 10:02)
【系统环境|软件环境】梦幻仙域游戏攻略(2023-12-19 10:02)
【系统环境|】卡帕部落揭秘潮玩新宠,探究玩法(2023-12-14 09:45)
【系统环境|数据库】 潮玩宇宙游戏道具收集方法(2023-12-12 16:13)
【系统环境|】如何开发搭建卡帕部落模式源码(2023-12-12 10:44)
【系统环境|】遥遥领先!青否数字人直播系统5.0发布,支持真人接管实时驱动!(2023-10-12 17:31)
【系统环境|服务器应用】克隆自己的数字人形象需要几步?(2023-09-20 17:13)
【系统环境|】Tiktok登录教程(2023-02-13 14:17)
血鸟云
手机二维码手机访问领取大礼包
返回顶部