【转】 简单理解Socket

题外话

前几天和朋友聊天,朋友问我怎么最近不写博客了,一个是因为最近在忙着公司使用的一些控件的开发,浏览器兼容性搞死人;但主要是因为这段时间一直在看html5的东西,看到web socket时觉得很有意思,动手写几个demo,但web socket需要特定的服务器支持,由于标准制定工作还没完成,所以没有多少主流的服务器支持,自己在网上下载了几个实现,包括php的、C#的、甚至Node.js的,但一个是协议变化比较大,很多代码已经过时了,再就是有一些支持最新的标准,但是我想稍微改造一下,看人家源代码的时候云里雾里,看看别人的代码行数也不多,决定自己实现一个。

悲剧由此开始,虽然哥们儿国内非知名工科大学毕业,但好歹也是科班CS出身,但大学得过且过,什么TCP/IP协议,什么socket了都没概念。为了做出一个简单的支持广播的websocket server,在网上找了很多相关代码,左抄一句,右抄一句,弄了一个星期竟然还是漏洞百出,调试不起来,只好从头来过了,先补一些基本知识,然后再一步步根据原理实现,今天终于实现了绝大部分功能,由此真的感受到了,搞计算机必须得有理论指导实践,否则只能像个没头苍蝇到处乱撞。

TCP/IP

要想理解socket首先得熟悉一下TCP/IP协议族, TCP/IP(Transmission Control Protocol/Internet Protocol)即传输控制协议/网间协议,定义了主机如何连入因特网及数据如何再它们之间传输的标准,

从字面意思来看TCP/IP是TCP和IP协议的合称,但实际上TCP/IP协议是指因特网整个TCP/IP协议族。不同于ISO模型的七个分层,TCP/IP协议参考模型把所有的TCP/IP系列协议归类到四个抽象层中

应用层:TFTP,HTTP,SNMP,FTP,SMTP,DNS,Telnet 等等

传输层:TCP,UDP

网络层:IP,ICMP,OSPF,EIGRP,IGMP

数据链路层:SLIP,CSLIP,PPP,MTU

每一抽象层建立在低一层提供的服务上,并且为高一层提供服务,看起来大概是这样子的

                        

估计有兴趣打开此文的同学都对此有一定了解了,加上我也是一知半解,所以就不详细解释,有兴趣同学可以上网上搜一下资料

维基百科 

百度百科

在TCP/IP协议中两个因特网主机通过两个路由器和对应的层连接。各主机上的应用通过一些数据通道相互执行读取操作

 

socket

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

能够唯一标示网络中的进程后,它们就可以利用socket进行通信了,什么是socket呢?我们经常把socket翻译为套接字,socket是在应用层和传输层之间的一个抽象层,它把TCP/IP层复杂的操作抽象为几个简单的接口供应用层调用已实现进程在网络中通信。

socket起源于UNIX,在Unix一切皆文件哲学的思想下,socket是一种"打开—读/写—关闭"模式的实现,服务器和客户端各自维护一个"文件",在建立连接打开后,可以向自己文件写入内容供对方读取或者读取对方内容,通讯结束时关闭文件。

socket通信流程

socket是"打开—读/写—关闭"模式的实现,以使用TCP协议通讯的socket为例,其交互流程大概是这样子的

服务器根据地址类型(ipv4,ipv6)、socket类型、协议创建socket

服务器为socket绑定ip地址和端口号

服务器socket监听端口号请求,随时准备接收客户端发来的连接,这时候服务器的socket并没有被打开

客户端创建socket

客户端打开socket,根据服务器ip地址和端口号试图连接服务器socket

服务器socket接收到客户端socket请求,被动打开,开始接收客户端请求,直到客户端返回连接信息。这时候socket进入阻塞状态,所谓阻塞即accept()方法一直到客户端返回连接信息后才返回,开始接收下一个客户端谅解请求

客户端连接成功,向服务器发送连接状态信息

服务器accept方法返回,连接成功

客户端向socket写入信息

服务器读取信息

客户端关闭

服务器端关闭

三次握手

在TCP/IP协议中,TCP协议通过三次握手建立一个可靠的连接

第一次握手:客户端尝试连接服务器,向服务器发送syn包(同步序列编号Synchronize Sequence Numbers),syn=j,客户端进入SYN_SEND状态等待服务器确认

第二次握手:服务器接收客户端syn包并确认(ack=j+1),同时向客户端发送一个SYN包(syn=k),即SYN+ACK包,此时服务器进入SYN_RECV状态

第三次握手:第三次握手:客户端收到服务器的SYN+ACK包,向服务器发送确认包ACK(ack=k+1),此包发送完毕,客户端和服务器进入ESTABLISHED状态,完成三次握手

定睛一看,服务器socket与客户端socket建立连接的部分其实就是大名鼎鼎的三次握手

 socket编程API

前面提到socket是"打开—读/写—关闭"模式的实现,简单了解一下socket提供了哪些API供应用程序使用,还是以TCP协议为例,看看Unix下的socket API,其它语言都很类似(PHP甚至名字都几乎一样),这里我就简单解释一下方法作用和参数,具体使用有兴趣同学可以看看博客参考中的链接或者上网搜索

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

根据指定的地址族、数据类型和协议来分配一个socket的描述字及其所用的资源。

domain:协议族,常用的有AF_INET、AF_INET6、AF_LOCAL、AF_ROUTE其中AF_INET代表使用ipv4地址

type:socket类型,常用的socket类型有,SOCK_STREAM、SOCK_DGRAM、SOCK_RAW、SOCK_PACKET、SOCK_SEQPACKET等

protocol:协议。常用的协议有,IPPROTO_TCP、IPPTOTO_UDP、IPPROTO_SCTP、IPPROTO_TIPC等

int bind(int sockfd, const struct sockaddr *addr, socklen_t addrlen);

把一个地址族中的特定地址赋给socket

sockfd:socket描述字,也就是socket引用

addr:要绑定给sockfd的协议地址

addrlen:地址的长度

通常服务器在启动的时候都会绑定一个众所周知的地址(如ip地址+端口号),用于提供服务,客户就可以通过它来接连服务器;而客户端就不用指定,有系统自动分配一个端口号和自身的ip地址组合。这就是为什么通常服务器端在listen之前会调用bind(),而客户端就不会调用,而是在connect()时由系统随机生成一个。

int listen(int sockfd, int backlog);

监听socket

sockfd:要监听的socket描述字

backlog:相应socket可以排队的最大连接个数 

int connect(int sockfd, const struct sockaddr *addr, socklen_t addrlen);

连接某个socket

sockfd:客户端的socket描述字

addr:服务器的socket地址

addrlen:socket地址的长度

int accept(int sockfd, struct sockaddr *addr, socklen_t *addrlen);

 TCP服务器监听到客户端请求之后,调用accept()函数取接收请求

sockfd:服务器的socket描述字

addr:客户端的socket地址

addrlen:socket地址的长度

ssize_t read(int fd, void *buf, size_t count);

读取socket内容

fd:socket描述字

buf:缓冲区

count:缓冲区长度

ssize_t write(int fd, const void *buf, size_t count);

向socket写入内容,其实就是发送内容

fd:socket描述字

buf:缓冲区

count:缓冲区长度

int close(int fd);

socket标记为以关闭 ,使相应socket描述字的引用计数-1,当引用计数为0的时候,触发TCP客户端向服务器发送终止连接请求。

参考

Linux Socket编程(不限Linux)

揭开Socket编程的面纱 

PS. 有同学看完后发现没有demo示例,参考中的示例已经很不错了,我就不班门弄斧了,而且我用C#实现了一个websocket server,接下来的博客中会有介绍。另外由于刚刚实际接触socket,文中谬误较多,还望大家批评指正,文章内容主要参考上面两个博文,图片全部来源于网络,在百度图片搜索得来,无法注明第一源地址,如有版权问题请站内信联系,第一时间处理。

 

转:http://www.cnblogs.com/dolphinX/p/3460545.html

转载于:https://www.cnblogs.com/eleclsc/p/5812060.html

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/372427.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

.NET基础

.NET C# ASP.NET关系:.NET是一个平台,提供程序运行的虚拟机环境和类库。 C#是.Net平台上的一种语言,其他语言还有VB.NET PowerShell等。 ASP.NET是在.NET下的网站开发技术。 安装.NET FrameWork就可以运行。VS集成安装了.NET FrameWork. 控制…

业务活动监视器(BAM)2.0带来的革命

生产兼具精益和企业价值的中间件是一项艰巨的工作。 它要么不存在,要么需要创新的思维(很多),并且需要在实现中反复进行。 业务风险很大,但是如果您做对了,它就会使您领先于其他任何公司。 这就是为什么我们…

oracle销售服务器吗,oracle 服务器 版本

oracle 服务器 版本 内容精选换一换Atlas 800 训练服务器(型号 9010)安装上架、服务器基础参数配置、安装操作系统等操作请参见《Atlas 800 训练服务器 用户指南 (型号9010)》。Atlas 800 训练服务器(型号 9010)适配操作系统如表1所示。请参考表2下载驱动和固件包。Atlas 800 训…

Vue组件间通信:一个例子学会Vue组件-Vue.js学习总结)(转载)

详情请点击 http://www.jianshu.com/p/9ad1ba89a04b转载于:https://www.cnblogs.com/zhongjiang/p/6694459.html

必填字段的自定义JSF验证器

实现EditableValueHolder接口的JSF组件具有两个属性“ required”和“ requiredMessage” –一个标志,指示用户需要输入/选择非空值,以及一个用于验证消息的文本。 我们可以使用它,但是它不够灵活,我们不能直接在视图中&#xff0…

java 转码%2f%_JS和JAVA中常用的编码转码函数

js中escape,encodeURI,encodeURIComponent函数和unescape,decodeURI和decodeURIComponent函数的功能1.escape方法对String对象编码,escape方法返回一个包含了"转义序列"的字符串值。除了ASCII字母和数字,以及这几个符号 *-/._外(共有1052769个字符不会被编…

mybatis 下划线转驼峰配置

一直以来&#xff0c;在sqlmap文件中&#xff0c;对于数据库中的下划线字段转驼峰&#xff0c;我们都是通过resultmap来做的&#xff0c;如下&#xff1a; <resultMap id"ISTableStatistics" type"com.medsoft.perfstat.pojo.ISTableStatistics" > &…

Python练习-迭代器-模拟cat|grep文件

代码如下: 1 # 编辑者&#xff1a;闫龙2 def grep(FindWhat):3 fopen("a.txt","r",encoding"utf8")#以只读的方式打开a.txt文件4 while True:5 try:6 fline next(f).strip()#由于File类型本身就是一个迭代器,所以直…

Spring和JSF集成:转换器

使用任何Web框架时&#xff0c;都不可避免地需要将用户输入的数据从String为其他类型。 尽管Spring和JSF在设计和功能上确实有很大的不同&#xff0c;但它们都具有转换器策略来处理此问题。 让我们从春天开始。 Spring 3引入了一个全新的转换框架&#xff0c;该框架允许将任何类…

nacos配置ap_Nacos 1.0.0 功能预览

本文来自于我的个人主页&#xff1a;Nacos 1.0.0 功能预览&#xff0c;转载请保留链接 ;)Nacos 1.0.0 是正式 GA 的版本&#xff0c;在架构、功能和API设计上进行了全方位的重构和升级&#xff0c;1.0.0版本标志着Nacos的架构已经稳定&#xff0c;API列表最终确定。升级到1.0.0…

poj 2229 Sumsets

题目大意&#xff1a; 一个数由2的幂次数的和构成&#xff0c;问有几种构成方式&#xff1f; 主要是找规律 代码如下 1 #include <cstdio>2 #include <cstring>3 int n;4 #define M 10000000005 int dp[1000002];6 7 int main(int argc, char const *argv[])8 {9 …

html 甘特图_Rplotly|交互式甘特图(Gantt chart)项目管理/学习计划

甘特图(Gantt chart)&#xff0c;又常被称为横道图或者条状图&#xff0c;是现代企业项目管理领域运用最为广泛的一种图示。就是通过条形来显示项目的进度、时间安排等相关情况的。项目管理外&#xff0c;也可以用来管理学习计划。绘制甘特图的工具有很多&#xff0c;本文介绍使…

使您的Spring Security @Secured注释更干燥

最近&#xff0c;Grails用户邮件列表中的一个用户想知道在定义Secured批注时如何减少重复 。 在Java批注中指定属性的规则非常严格&#xff0c;因此我看不到直接执行他所要求的方法的方法。 使用Groovy并没有真正的帮助&#xff0c;因为Groovy类中的注释大部分与Java中的注释几…

阅读《大型网站技术架构》 第三章心得

今天阅读了《大型网站技术架构》 的第三章&#xff0c;这一章主要讲解了大型网站核心架构要素&#xff0c;并且概括的讲解了相应的实现方法。 软件架构除了系统功能需求外&#xff0c;还需要关注性能、可用性、伸缩性、扩展性、安全性。 其中性能是网站的重要指标。优化网站性能…

easyui数据表格重置_数据库三种删除方式

第一种 使用delete 语句特点&#xff1a;delete 属于数据库操纵语言DML&#xff0c;表示删除表中的数据&#xff0c;删除过程是每次从表中删除一行&#xff0c;并把该行删除操作作为事务记录在日志中保存可以配合事件&#xff08;transaction&#xff09;和 回滚&#xff08;ro…

main函数之间的代码操作

全局对象的构造函数会在main函数之前执行。转载于:https://www.cnblogs.com/yingl/p/5817123.html

Windows 自启动总结《转》

开机启动项  【启动项目就是开机的时候系统会在前台或者后台运行的程序】  当Windows&#xff08;操作系统&#xff09;完成登录过程&#xff0c;进程表中出现了很多的进程&#xff01;Windows在启动的时候&#xff0c;自动加载了很多程序。  许多程序的自启动&#xff0…

win10多合一原版系统_微软Win10专业版制作多合一系统安装盘教程

微软Win10怎么制作多合一系统安装盘?和Win10家庭版、win10企业版&#xff0c;win10教育版相比&#xff0c;微软Win10专业版是最受大家喜欢的操作系统&#xff0c;那么在安装Win10操作系统的时候&#xff0c;我们就不得不准备多个不同版本的系统安装盘。可是你知道微软Win10专业…

Oracle Coherence:分布式数据管理

本文介绍如何使用Oracle Coherence提供分布式&#xff08;分区&#xff09;数据管理。 在下面的示例应用程序中&#xff0c;创建了一个名为OTV的新集群&#xff0c;并且在该集群的两个成员之间分配了一个名为user-map的缓存对象。 二手技术&#xff1a; JDK 1.6.0_21 Maven的…

Ajax学习笔记

Ajax 什么是ajax AJAX即“Asynchronous JavaScript and XML”&#xff08;异步的JavaScript与XML技术&#xff09;&#xff0c;指的是一套综合了多项技术的浏览器端网页开发技术。以前&#xff0c;几乎所有的网站都由HTML页面实现&#xff0c;服务器处理每一个用户请求都需要重…