运维都该会的Socket知识!
本篇博客转自赵班长
所有运维都会的Socket知识!!!
原创: 赵班长 新运维社区
什么是Socket?
大家都用电脑上网,当我们访问运维社区https://www.unixhot.com的时候,我们的电脑和运维社区的服务器就会创建一条Socket,我们称之为网络套接字。那么既然是网络通信,肯定是成对的。至少有一个客户端和服务端,我们称之为套接字对。
一个套接字对(socket pair)是一个定义该网络连接的两个端点的五元组,包括:
源IP地址
源端口
目的IP地址
目的端口
类型:TCP or UDP
那么针对于HTTP请求来说,我们知道底层是建立了一条TCP的Socket,那么TCP的套接字对就是一个四元组,因为协议已经确定了:
1.源IP地址、2.源端口、3.目的IP地址、4.目的端口。
客户端的随机端口
为了更直观的认识这个TCP Socket,我们做一个小实验,我这里准备了两台服务器:
角色
IP地址
端口
客户端
192.168.56.11
随机
服务端
192.168.56.12
9999
当客户端192.168.56.11访问192.168.56.12的9999端口的时候,那么会选择一个随机端口来进行通信,那么这个随机端口,到底是从什么范围随机出来了呢,端口总有一个范围不可能无穷多的。
那么对于TCP套接字来说客户端的一个IP地址,到底能有多少个端口呢?由于TCP协议头部使用16位来保存端口号,所以端口的个数最多为65536个,2^16=65536。
没错,是65536个。但是为什么我们经常看到网上说可用端口最大65535个呢,也就是2^16-1个。因为端口号是从0开始算的,0-65535那就是65536个。而0端口是保留端口,无论是TCP还是UDP都是不用使用的,当然这个是标准,那到底能不能监听端口0呢,下面我用一个python脚本,监听本地的端口0来试试。
[root@test ~]# catbind_port_zero.py
!/usr/bin/env python
-- coding: utf-8 --
'''本脚本监听本地的127.0.0.1的端口0,
探索端口0的奥秘'''
import socket
def bind_port_zero():
ss = socket.socket(socket.AF_INET,socket.SOCK_STREAM)
ss.bind(('127.0.0.0', 0))
addr, port = ss.getsockname()
ss.close()
print(addr, port)
bind_port_zero()
执行脚本,看看到底能不能正常监听:
[root@test ~]# pythonbind_port_zero.py
('127.0.0.0', 53692)
[root@test ~]# pythonbind_port_zero.py
('127.0.0.0', 59444)
可以发现,可以正常监听,但是呢并没有监听到端口0。实验证明在Linux下如果在bind的时候指定端口0,那么由系统随机选择一个可用端口来bind。
好的,我们现在知道了端口的范围0-65535,那么作为客户端访问其它服务端的时候,能用多少呢?并不是这个范围都可以用的。那么在Linux下我们可以这么获取本地的随机端口范围:
[root@test ~]# cat/proc/sys/net/ipv4/ip_local_port_range
32768 61000
不要惊讶答案确实是32768到61000,现在你应该明白,别人说的发10万并发进行压力测试代表什么意思了吧。至少默认情况下是无法实现的,读完这句话,是否有启发呢?并不是不能实现哦。
瓶颈真的只有随机端口范围吗?
刚才我们也看了,我们访问其它服务器,作为客户端,我们要使用一个随机端口,32768-61000,貌似也不少,当然你还可以修改它,扩大随机端口范围。例如我们使用Nginx做反向代理负载均衡的时候,用户端和Nginx建立Socket进行通信,Nginx还需要和后端真实服务器也建立Socket进行通信,在高并发的场景下,这个随机端口肯定是一个瓶颈。但是真的只有随机端口范围是瓶颈吗?下面我们使用ab命令来对百度进行一次压力测试。
ab是Apache的性能测试工具,可以模拟并发进行Web性能测试。在CenotOS下,你可以这样来安装:
[root@test ~]# yuminstall -y httpd-devel
按照咱们之前的认识,随机端口61000-32768=28232,那么我实验的机器是一台刚安装的系统,没有什么网络传输,即便有,我们创建2万个套接字对应该是没问题吧。事实真的如此吗?我们用实验来证明:
我们模拟发送2万个请求,2000的并发来测试百度:
[root@test ~]#ab -n 10000 -c 2000 https://www.baidu.com/
This isApacheBench, Version 2.3 <$Revision: 1430300 $>
Copyright 1996Adam Twiss, Zeus Technology Ltd, http://www.zeustech.net/
Licensed to TheApache Software Foundation, http://www.apache.org/
Benchmarkingwww.baidu.com (be patient)
socket: Toomany open files (24)
这不可能,为什么报错了?不要担心,报错我们很容易看懂了socket: Too many open files (24)
,不能打开太多的文件。我们使用ulimit来看看系统资源限制。
[root@test ~]# ulimit -a
core file size (blocks, -c) 0
data seg size (kbytes, -d) unlimited
scheduling priority (-e) 0
file size (blocks, -f) unlimited
pending signals (-i) 31219
max locked memory (kbytes, -l) 64
max memory size (kbytes, -m) unlimited
open files (-n) 1024
(省略部分输出)
没错,默认情况下,当前用户能够打开的文件数量最大是1024,但是这个和我们使用ab测试有什么关系呢?ab测试创建的不是socket吗?如果你不理解,那就要回归本质,想想我们刚刚学习Linux的时候,经常听到的一句Linux的思想“一切皆文件”!谁说socket不是一个文件呢?
我相信你知道怎么做了,你可以使用ulimit –n来修改当前用户、当前session的限制,也可以修改配置文件/etc/security/limits.conf来彻底解决这个问题,这也是进行系统性能调优的必备基础。
创建一条TCP Socket
好的,刚才只是一个小插曲,我们继续探索TCP Socket,光说不练是个棒槌。我们来创建一个套接字对看看:
服务端:
首先,我们在192.168.56.12上使用nc命令,来监听9999端口。
[root@192.168.56.12 ~]#nc -l -4 -p 9999 -k
[root@192.168.56.12 ~]#netstat -ntlp | grep 9999
tcp 0 0 0.0.0.0:9999 0.0.0.0:* LISTEN 26789/n
客户端:
在客户端,同样使用nc命令来连接到服务端的9999端口。
[root@192.168.56.11 ~]#nc 192.168.56.12 9999
好的,现在你可以在客户端上输入任何的语言和服务端愉快的聊天了?不过这不是重点。
查看Socket
我们先来看看客户端的TCPSocket。
[root@192.168.56.11 ~]#netstat -na | grep 9999
tcp 0 0 192.168.56.11:11525 192.168.56.12:9999 ESTABLISHED
服务端的TCP Socket
[root@192.168.56.12 ~]#netstat -na | grep 9999
tcp 0 0 0.0.0.0:9999 0.0.0.0:* LISTEN
tcp 0 0 192.168.56.12:9999 192.168.56.11:11525 ESTABLISHED
我相信你已经真正理解了Socket,剩下的就是无尽的想象,还记得TIME_WAIT吗?如果有大量的TIME_WAIT存在,那么这个套接字对是不释放的,不释放也就代表着占用一个,资源嘛,占用一个就少一个。怎么优化呢?且听下回分解!
不过,如果你真的理解了Socket的概念,你已经有了一个终极解决方案。既然一个TCP Socket是一个四元组,那如果我这台机器有多个IP地址呢?哈哈,这是一句画龙点睛之语,你懂的!
使用伪终端发送数据
最后,留一个小彩蛋,除了使用nc进行数据发送之外,其实Linux还提供了一种称之为伪设备的方式,让我们来体验下/dev下面的tcp伪设备。/dev下面提供了很多的伪设备,比如tcp就可以用来直接进行远程端口的访问。
[root@192.168.56.11 ~]# echo"886" > /dev/tcp/192.168.56.12/9999
赶紧看看服务端有没有收到886。
运维都该会的Socket知识!的更多相关文章
- linux运维需要掌握的基础知识
踏入linux运维工程师这一职业,其实有很多工具技能需要掌握,下面我来给大家一一介绍. 1.shell脚本和另一个脚本语言,shell是运维人员必须具备的,不懂这个连入职都不行,至少也要写出一些系统管 ...
- 论Linux运维的一些基础安全知识和简单办法
不知不觉本人来北京也已经第三个年头了,从一个Linux小小鸟,开始,2012年我参加了第一份工作,其实现在想想其实我是幸运的,本来求学的时候,就没好好的学Linux,我认为有Cisco知识从上wind ...
- Linux运维学习笔记-软硬链接知识总结
文件链接 硬链接,通过索引节点来进行链接 硬链接原理图 硬链接的创建: 直接执行命令“ln 源文件 硬链接文件”,即可完成创建硬链接. 硬链接知识小结: 1.具有相同Inode节点号的多个文件是互 ...
- 77%的Linux运维都不懂的内核问题
前言 之前在实习时,听了 OOM 的分享之后,就对 Linux 内核内存管理充满兴趣,但是这块知识非常庞大,没有一定积累,不敢写下,担心误人子弟,所以经过一个一段时间的积累,对内核内存有一定了解之后, ...
- Linux运维之shell脚本基础知识
1.bash中的算术运算 let运算符 [root@:vg_adn_tidbCkhsTest ~/tidb-bench/sysbench]#echo $i [root@:vg_adn_tidbCkhs ...
- Linux运维学习笔记-网络技术知识体系总结
传统网络知识体系 未来网络SND模型架构
- Linux运维学习笔记-文件权限知识总结
权限总结: 1. 可读r:表示具有读取\阅读文件内容的权限: 2. 可写w:表示具有新增.修改文件内容的权限: a. 若果没有r配合,那么vi编辑文件会提示无法编辑(但可以强制编辑),echo可以重定 ...
- WEB架构师成长之路-架构师都要懂哪些知识 转
Web架构师究竟都要学些什么?具备哪些能力呢?先网上查查架构师的大概的定义,参见架构师修炼之道这篇文章,写的还不错,再查查公司招聘Web架构师的要求. 总结起来大概有下面几点技能要求: 一. 架构师有 ...
- WEB架构师成长之路之三-架构师都要懂哪些知识
Web架构师究竟都要学些什么?具备哪些能力呢?先网上查查架构师的大概的定义,参见架构师修炼之道这篇文章,写的还不错,再查查公司招聘Web架构师的要求. 总结起来大概有下面几点技能要求: 一. 架构师有 ...
随机推荐
- numpy之填充为nan的数据为该列平均值
# coding=utf-8 import numpy as np ''' 填充nan的数据,为该列的平均值 ''' def fill_ndarray(t1): for i in range(t1.s ...
- openstack共享组件--rabbitmq消息队列(1)
一.MQ 全称为 Message Queue, 消息队列( MQ ) 是一种应用程序对应用程序的通信方法.应用程序通过读写出入队列的消息(针对应用程序的数据)来通信,而无需专用连接来链接它们. 消息传 ...
- 监控系统-PMM
Percona Monitoring and Management (PMM)是一款开源的用于管理和监控MySQL和MongoDB性能的开源平台 通过PMM客户端收集到的DB监控数据用第三方软件Gra ...
- HTML <canvas> 学习笔记
Professional JavaScript for Web Developers P552 Basic Usage The <canvas> element requires a ...
- HCL试验六
交换机R1: syssysname R1interface loopback 0ip add 192.168.10.1 24quinterface g0/0ip address 10.1.1.1 30 ...
- URLOS开发基础教程——docker容器的使用方法
URLOS本是基于docker容器运行,在入门URLOS开发之前,我们首先需要掌握docker的相关基础知识,本篇就以docker容器的基本使用方法为例,快速的让大家对docker有一个全面的印象. ...
- 注入之Mysql-Getshell思路
- SolidWorks学习笔记4特征
绘制斜的拉伸效果 一般拉伸方向垂直于草图基准面, 可以实现绘制一条线,作为其拉伸方向 效果如下 简单孔 在菜单中选择“插入”--“特征”---“简单直孔” 选择一个平面放置 设置好孔的直径和深度后,确 ...
- ssh远程连接的故障排查详解
排查故障: 1.两个机器之间是否通畅,看物理网络(网线网卡,IP是不是正确) ping ip -t 来检测物理网络是否通畅 通 不通 不通: 1.客户端到服务器端物理链路有问题 网卡 ,IP , 网 ...
- 【Linux-驱动】将cdev加入到系统中去---cdev_add
在我们已经完成了对cdev结构体的初始化之后,我们需要将这个cdev结构体加入到系统中去,使用函数 cdev_add: /** * cdev_add() 讲一个字符设备加入到系统中去 * @p: 字符 ...