仔细讲解socket(转载https://www.zybuluo.com/phper/note/47110)
老实讲,到目前为止,我对socket一无所知,真的。我就现学现卖用过nodejs平台的socket.io搭建过一套高可用实时性的网页聊天系统,其他,就真的只是听过它。
今天就来仔仔细细的学一下,socket是什么?它能干什么?
什么是socket
socket,我们先仅仅看这个英文单词的中文翻译,它翻译成:"孔"或者"插座"
,擦,能不能稍微取个高雅点的名字!怎么会是这个东西呢?这个留在后面,卖个关子,你会发现真的它就是个插座
。
既然socket就是插座,一般插座是长这样的:
我们从图片中可以看到,它上面插了各种各样电器的插头,所有的电器都靠这个插座来供电和通讯。
所以插座就成了一个统一的接口,统一给所有的电器通电,所有的电器不需要了解电的原理,电的传输,电的各种。只要把电器的插头插上去就可以通电工作使用了。
不知道插座这样子解释好不好懂,反正我懂了,你不懂拉鸡巴倒!
回到网络上的socket,同样,和真实的插座一样,它也是提供了一个统一的通讯接口,将底层的TCP/IP给封装起来。需要通讯的进程,不需要了解TCP/IP是怎么传输的,你只要用socket提供的插口,你就能通上电,就能将消息发出去!
socket,第一,它简化了开发者的工作量,因为协议众多,进程众多,全部自己去搞通讯底层是很效率低的。第二,统一了接口,使得不同原理的进程可以通过一个统一的socket进行通讯,比如德国人和中国人统一用英语就能友好沟通了。
socket 定义
上面罗嗦了这么多,或许对socket用了一定的了解,那就用官方的定义来说说什么是socket:
Socket是应用层与TCP/IP协议族通信的中间软件抽象层,它是一组接口。在设计模式中,Socket其实就是一个门面模式,它把复杂的TCP/IP协议族隐藏在Socket接口后面,对用户来说,一组简单的接口就是全部,让Socket去组织数据,以符合指定的协议。
恩。你先看插座的例子,再来看这句蛋疼的官方解释,我擦,居然能看懂了。
什么是TCP/IP
上面讲到socket其实不是什么协议,只是一个数据封装,它封装了TCP/IP的各种协议,然后提供接口的方式给用户进程使用。那么什么是TCP/IP呢?
我擦,这他妈越扯越远啊。麻痹说TCP/IP就要说网络7层协议。收不回了啊!
不管了这么多了。7层网络不懂得请自动去复习。先来看看TCP/IP的关系,以及他们在7层模型中的位置:
结合上面的这张图,再装逼看一下官方定义:
TCP/IP(Transmission Control Protocol/Internet Protocol)即传输控制协议/网间协议,是一个工业标准的协议集,它是为广域网(WANs)设计的。是一种网络通信协议,它规范了网络上的所有通信设备,尤其是一个主机与另一个主机之间的数据往来格式以及传送方式
你会理解:它横跨传输层和网络层,是专门用来传递和发送消息的的协议簇集合。所有的进程都是通过他们来完成消息的发送和接口。
所以,我们下定义:所有的消息发送,消息获取,数据接收,数据获取,那么都需要用到TCP/IP。
好。TCP/IP你知道了干嘛的了,由于它比较复杂,且各用户通讯起来比较麻烦,所以专家发明了socket, socket封装了蛋疼的TCP/IP各种晦涩难懂的各种协议,所以socket就应该在用户和TCP/IP之间:
通过上面的图就一目了然了。对不对!反正,我是了然了。
哎。马丹不容易了。终于将socket给圆清楚了。
socket 如何使用
我们平时都会打电话的吧。打电话就是一个非常好的理解和掌握socket的场景,我们想一想打电话是不是这样:我想给周杰伦打电话,好久不见了。于是我先拨号,杰伦听到电话铃声后提起电话,这时我和杰伦就建立起了连接,就可以讲话了。等瞎比比结束,挂断电话结束此次通话。
用socket的图样式给画一下,就是这样:
通过上面的一个例子,我们大致知道了socket大致的使用过程,它分为服务器端和客户端。先从服务器端说起。服务器端先初始化Socket,然后与端口绑定(bind),对端口进行监听(listen),调用accept阻塞,等待客户端连接。在这时如果有个客户端初始化一个Socket,然后连接服务器(connect),如果连接成功,这时客户端与服务器端的连接就建立了。客户端发送数据请求,服务器端接收请求并处理请求,然后把回应数据发送给客户端,客户端读取数据,最后关闭连接,一次交互结束。
这就是socket的使用过程!其实想想真的是和电话通讯一模一样。因为socket是对TCP/IP的封装,所以也会有三次握手的影子在。
socket 封装了哪些接口
上面我们大致知道了socket是怎么使用了,各种初始化啊,监听啊什么的。每个语言平台都有不一样的函数,但是都是基于socket封装的接口的基础上进行修改的。所以也是用到了socket提供的接口。
我们大致来看下PHP语言平台下的socket相关的接口函数有哪些
socket_accept() 接受一个Socket连接
socket_bind() 把socket绑定在一个IP地址和端口上
socket_clear_error() 清除socket的错误或者最后的错误代码
socket_close() 关闭一个socket资源
socket_connect() 开始一个socket连接
socket_create_listen() 在指定端口打开一个socket监听
socket_create_pair() 产生一对没有区别的socket到一个数组里
socket_create() 产生一个socket,相当于产生一个socket的数据结构
socket_get_option() 获取socket选项
socket_getpeername() 获取远程类似主机的ip地址
socket_getsockname() 获取本地socket的ip地址
socket_iovec_add() 添加一个新的向量到一个分散/聚合的数组
socket_iovec_alloc() 这个函数创建一个能够发送接收读写的iovec数据结构
socket_iovec_delete() 删除一个已经分配的iovec
socket_iovec_fetch() 返回指定的iovec资源的数据
socket_iovec_free() 释放一个iovec资源
socket_iovec_set() 设置iovec的数据新值
socket_last_error() 获取当前socket的最后错误代码
socket_listen() 监听由指定socket的所有连接
socket_read() 读取指定长度的数据
socket_readv() 读取从分散/聚合数组过来的数据
socket_recv() 从socket里结束数据到缓存
socket_recvfrom() 接受数据从指定的socket,如果没有指定则默认当前socket
socket_recvmsg() 从iovec里接受消息
socket_select() 多路选择
socket_send() 这个函数发送数据到已连接的socket
socket_sendmsg() 发送消息到socket
socket_sendto() 发送消息到指定地址的socket
socket_set_block() 在socket里设置为块模式
socket_set_nonblock() socket里设置为非块模式
socket_set_option() 设置socket选项
socket_shutdown() 这个函数允许你关闭读、写、或者指定的socket
socket_strerror() 返回指定错误号的详细错误
socket_write() 写数据到socket缓存
socket_writev() 写数据到分散/聚合数组
socket 的使用场景
既然socket是封装了底层的TCP/IP,TCP/IP干的又是通讯的活儿。所以,socket就特别是适合做通讯应用、有客户机和服务器模式的通讯等应用。
1. 聊天室,多人聊天。
2. 实时性比较高的消息推送。
3. 客户端与服务器之间通信。
socket 举例说明
说了那么多,也解释了那么多,直接用几个例子来看看socket是怎么工作的。用上诉PHP封装的各种函数接口来完成例子。
这个例子来自于PHP手册,有服务器端口和客户端
直接上代码吧:
<?php
//socket 服务器端
/*
+-------------------------------
* @创建socket server整个过程
+-------------------------------
* @socket_create
* @socket_bind
* @socket_listen
* @socket_accept
* @socket_read
* @socket_write
* @socket_close
+--------------------------------
*/
//设置不超时并打印所以错误
error_reporting(0);
set_time_limit(0);
//检测php是否支持socket
if (!extension_loaded('sockets')) {
die('The sockets extension is not loaded.');
//需要打开扩展:extension=php_sockets.dll
}
//server的地址和端口
$address = "127.0.0.1";
$port = "10000";
//创建socket链接
$mysock = socket_create(AF_INET, SOCK_STREAM, SOL_TCP) or die("Could not create socket\n");
//绑定地址和端口号
socket_bind($mysock, $address, $port) or die("Could not bind tosocket\n");
//监听
socket_listen($mysock, 5) or die("Could not set up socket listener\n");;
echo "Server started, accepting connections...\n";
//Socket来处理通信。这里会阻塞等待
$client = socket_accept($mysock) or die("Could not accept incomingconnection\n");
//发到客户端
$msg ="congratulations! you success!\n";
socket_write($client, $msg, strlen($msg));
echo "send to client: $msg\n";
//接收客户端的消息
$buf = socket_read($client, 8192);
echo "recvice from client: $buf\n";
//关闭
echo "Closing sockets...";
socket_close($client);
socket_close($mysock);
<?php
//socket 客户端
/*
+-------------------------------
* @client链接socket过程
+-------------------------------
* @socket_create
* @socket_connect
* @socket_write
* @socket_read
* @socket_close
+--------------------------------
*/
//设置不超时并打印所以错误
error_reporting(0);
set_time_limit(0);
//地址和端口号
$address = "127.0.0.1";
$port = 10000;
//创建socket链接
$socket = socket_create(AF_INET, SOCK_STREAM, SOL_TCP);
if ($socket === false) {
echo "socket_create() failed: reason: " . socket_strerror(socket_last_error()) . "\n";
die;
} else {
echo "socket successfully created.\n";
}
//连接到地址和端口号
echo "Attempting to connect to '$address' on port '$port'...\n";
$result = socket_connect($socket, $address, $port);
if ($result === false) {
echo "socket_connect() failed.\nReason: ($result) " . socket_strerror(socket_last_error($socket)) . "\n";
die;
} else {
echo "successfully connected to $address.\n";
}
//发给 server
$msg ="hello,I'm client\n";
socket_write($socket, $msg, strlen($msg));
echo "send to server: $msg\n";
//接收 server的消息
$buf = socket_read($socket, 8192);
echo "recvice from server: $buf\n";
echo "Closing socket...";
socket_close($socket);
先打开一个cmd运行 php server.php
就会阻塞掉,等待客户端:
D:\wamp\www\testphp\socket>php server.php
server started, accepting connections...
再打开一个cmd 运行 php client.php
然后分别看client端和server端:
client端:
D:\wamp\www\testphp\socket>php client.php
socket successfully created.
Attempting to connect to '127.0.0.1' on port '10000'...
successfully connected to 127.0.0.1.
send to server: hello,I'm client
recvice from server: congratulations! you success!
Closing socket...
server端:
D:\wamp\www\testphp\socket>php server.php
Server started, accepting connections...
send to client: congratulations! you success!
recvice from client: hello,I'm client
Closing sockets...
我们就能清楚的看到里面的通讯过程了。很好理解。
仔细讲解socket(转载https://www.zybuluo.com/phper/note/47110)的更多相关文章
- Emacs 入门(https://www.zybuluo.com/eqyun/note/40788)
下载地址 基本操作(C=Ctrl, M=Alt) C-f 向右移动一个字符 C-b 向左移动一个字符 C-n 移动到下一行 C-p 移动到上一行 M-f 向右移动一个词[对中文是移动到下一个标点符号] ...
- ICEM rpl文件简要讲解【转载】
转载自:http://blog.sina.com.cn/s/blog_90affd9801016xti.html 很多人问ICEM的rpl怎样录制的问题,为什么CFX调用时老是报错,这里开个帖子简单讲 ...
- Mui本地打包笔记(一)使用AndroidStudio运行项目 转载 https://blog.csdn.net/baidu_32377671/article/details/79632411
转载 https://blog.csdn.net/baidu_32377671/article/details/79632411 使用AndroidStudio运行HBuilder本地打包的Mui项目 ...
- Redis全方位讲解--主从复制(转载)
前言 前面介绍了redis持久化和容灾备份,这篇会介绍redis主从复制和redis持久化在主从复制中的一些应用.因为本人没有那么多服务器或机器,所以这里主要介绍下如何在docker容器中搭建主从复制 ...
- GJM :异步Socket [转载]
原帖地址:http://blog.csdn.net/awinye/article/details/537264 原文作者:Awinye 目录(?)[-] 转载请原作者联系 Overview of So ...
- 转载 https协议和http协议的区别
转载原地址: http://aajs800.blog.51cto.com/519255/109555 什么是HTTPS: HTTPS(Secure Hypertext Transfer Protoco ...
- HTTPS 基本流程 转载 https://zhuanlan.zhihu.com/p/27395037
协议 1.HTTP 协议(HyperText Transfer Protocol,超文本传输协议):是客户端浏览器或其他程序与Web服务器之间的应用层通信协议 . 2.HTTPS 协议(HyperTe ...
- Cascade R-CNN论文讲解(转载)
转载链接:https://blog.csdn.net/qq_21949357/article/details/80046867 论文思想:为了解决IOU设置带来的最终的AP值,作者引入了cascade ...
- 爬虫出现Forbidden by robots.txt(转载 https://blog.csdn.net/zzk1995/article/details/51628205)
先说结论,关闭scrapy自带的ROBOTSTXT_OBEY功能,在setting找到这个变量,设置为False即可解决. 使用scrapy爬取淘宝页面的时候,在提交http请求时出现debug信息F ...
随机推荐
- [转载] Dubbo实现RPC调用使用入门
转载自http://shiyanjun.cn/archives/341.html 使用Dubbo进行远程调用实现服务交互,它支持多种协议,如Hessian.HTTP.RMI.Memcached.Red ...
- Python之uuid模块
UUID是128位的全局唯一标识符,通常由32字节的字符串表示. 它可以保证时间和空间的唯一性,也称为GUID,全称为: UUID —— Universally Unique IDentifier P ...
- pt-log-player
简介 pt-log-player是MySQL日志回放工具,在pt2.4中被去除,由percona-playback取代. 在2.1中还是保留,如果想使用的话,需要下载2.1版本的. 使用方法 pt-l ...
- Vue之彻底理解自定义组件的v-model
最近在学习vue,今天看到自定义事件的表单输入组件,纠结了一会会然后恍然大悟...官方教程写得不是很详细,所以我决定总结一下. v-model语法糖 v-model实现了表单输入的双向绑定,我们一般是 ...
- [读书笔记]javascript语言精粹'
人比较笨,以前只做项目,案例,然而一些javascript的很多理论不知道该怎么描述,所以最近开启一波读书之旅: 标识符 1.定义 标识符以字母开头,可能后面跟上一个或多个字母.数字或者下划线. 2. ...
- a标签嵌套解决方案
在实际网页布局之中,我们有时候需要一整块点击区域中间还要有部分按钮点击,也就是需要a标签嵌套a标签,如下: <!-- a标签进行嵌套的时候 --><a href="#hao ...
- 学习MySQL(上)
具体实例 1.PHP 服务器组件 对于初学者建议使用集成的服务器组件,它已经包含了 PHP.Apache.Mysql 等服务,免去了开发人员将时间花费在繁琐的配置环境过程. Window 系统可以使用 ...
- Service使用详解
Service是Android系统中的四大组件之一,主要有两个应用场景:后台运行和跨进程访问.Service可以在后台执行长时间运行操作而不提供用户界面,除非系统必须回收内存资源,否则系统不会停止或销 ...
- StringUtils工具类常用方法汇总2(截取、去除空白、包含、查询索引)
在上一篇中总结了StringUtils工具类在判断字符串为空,大小写转换,移除字符或字符序列,替换,反转,切割合并等方面的方法,这次再汇总一下其它常用的方法. 一.截取 StringUtils ...
- Swarm 如何存储数据?- 每天5分钟玩转 Docker 容器技术(103)
service 的容器副本会 scale up/down,会 failover,会在不同的主机上创建和销毁,这就引出一个问题,如果 service 有要管理的数据,那么这些数据应该如何存放呢? 选项一 ...