前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >你想知道的Socket,统统打包给你~

你想知道的Socket,统统打包给你~

作者头像
软测小生
发布2019-07-05 11:07:23
4770
发布2019-07-05 11:07:23
举报
文章被收录于专栏:软测小生软测小生
前言

测试过程中,你一定遇到不少网络通信的情况,最常见的如网络语音通信、文本传输、微信QQ聊天、浏览器访问等等,这些都涉及到网络进程间通信,然而这些进程间是如何通信的呢?你一定听开发同学提过很多次socket这个东西,没错,一切都是靠Socket实现的。它为何如此神奇?下面小编做个科普,帮你揭开Socket的神秘面纱~

1. 网络进程间通信

要了解Socket首先要熟悉网络进程通信的原理,一个完整的网络应用程序包括客户端和服务器两个部分。网络间通信需要由两个进程组成,并且只能用同一种协议,也就是说,不能在通信的一端使用TCP协议,而另一端则用UDP协议。 在TCP/IP协议中,两个因特网主机通过两个路由器和对应的层连接。各主机上的应用通过一些数据通道相互执行读取操作,如下图所示:

实现网络间通信,要解决一个首要问题是-如何唯一标识一个进程,在网络上,通常利用ip地址+协议+端口号唯一标示网络中的一个进程。IP层的ip地址可以唯一标示主机,而TCP层协议和端口号可以唯一标示主机的一个进程,这样它们就可以利用Socket进行通信了。

2. Socket套接字

网络中的进程是通过Socket来通信的,那么Socket是什么呢?Socket是一个进程间通信终结点,它是Socket应用程序用来在网络上发送或接收数据包的对象,是应用层与TCP/IP协议族通信的中间软件抽象层,它是一组接口。 如下图所示,在设计模式中,Socket其实就是一个门面模式,它把复杂的TCP/IP协议族隐藏在Socket接口后面,对用户来说,一组简单的接口就是全部,让Socket去组织数据,以符合指定的协议。

Socket的使用类型主要有两种: (1)流套接字(streamsocket):基于 TCP协议,采用流的方式提供可靠的字节流服务; (2)数据报套接字(datagramsocket):基于 UDP协议,采用数据报文提供数据打包发送的服务。

3. Socket通信流程

Socket起源于UNIX,在Unix一切皆文件哲学的思想下,Socket是一种"打开—读/写—关闭"模式的实现,服务器和客户端各自维护一个"文件",在建立连接打开后,可以向自己文件写入内容供对方读取或者读取对方内容,通讯结束时关闭文件。以使用TCP协议通讯的Socket为例,其交互流程大概是这样子的:

(1)服务器根据地址类型(ipv4,ipv6)、socket类型、协议创建socket; (2)服务器为socket绑定ip地址和端口号; (3)服务器socket监听端口号请求,随时准备接收客户端发来的连接,这时候服务器的socket并没有被打开; (4)客户端创建socket; (5)客户端打开socket,根据服务器ip地址和端口号试图连接服务器socket; (6)服务器socket接收到客户端socket请求,被动打开,开始接收客户端请求,直到客户端返回连接信息。这时候socket进入阻塞状态,所谓阻塞即accept()方法一直到客户端返回连接信息后才返回,开始接收下一个客户端谅解请求; (7)客户端连接成功,向服务器发送连接状态信息; (8)服务器accept方法返回,连接成功; (9)客户端向socket写入信息; (10)服务器读取信息; (11)客户端关闭; (12)服务器端关闭。 以上,一次socket通信流程的交互结束。

4. 代码实现

(1)创建一个socket:socket() int socket(int domain, int type, int protocol); - domain:与socket通信的domain。 - type:socket类型,SOCK_STREAM(TCP),SOCK_DGRAM(UDP)。 - protocol:通常指定为0,在RAW_SOCKET中为IPPROTO_RAW。 return: 新创建socket的文件描述符。 (2)将socket绑定到地址:bind() int bind(int sockfd, const struct sockaddr* addr, socklen_t addrlen); - sockfd:在socket()调用取得的文件描述符。 - addr:要socket绑定到的地址。 - addrlen:制定了地址结构的大小。 return:-1为绑定失败。 (3)监听接入连接:listen() int listen(int sockfd, int backlog); - sockfd:socket文件描述符。 - backlog:限制未决连接的数量(在调用accept()前收到connect()的连接)。 return: -1为监听失败。 (4)接受连接:accept() int accept(int sockfd, struct sockaddr *addr, socklen_t *addrlen); - sockfd:socket文件描述符。 - addr:对端socket的地址结构。 - addrlen:对端socket地址结构的长度。 return:和对端连接的文件描述符。 当调用accept()时,会创建一个新的socket,并且由这个新创建的socket来与执行connect()的对等socket进行连接。 (5)连接到对等socket:connect() int connect(int sockfd, const struct sockaddr *addr, socklen_t addrlen); - sockfd:socket文件描述符。 - addr:要连接到socket的地址。 - addrlen:地址结构的长度。 (6)连接终止:close() 终止一个流socket的连接,如果多个文件描述符引用了一个socket,那么所有描述符被关闭后才会终止(若调用shutdown()则可以强制关闭socket上的信道)。

5. Socket中TCP的三次握手建立连接详解

TCP建立连接要进行“三次握手”,即交换三个分组。大致流程如下: 1)客户端向服务器发送一个SYN J; 2)服务器向客户端响应一个SYN K,并对SYN J进行确认ACKJ+1; 3)客户端再想服务器发一个确认ACK K+1。

当客户端调用connect时,触发了连接请求,向服务器发送了SYN J包,这时connect进入阻塞状态;服务器监听到连接请求,即收到SYN J包,调用accept函数接收请求向客户端发送SYN K ,ACK J+1,这时accept进入阻塞状态;客户端收到服务器的SYN K ,ACK J+1之后,这时connect返回,并对SYN K进行确认;服务器收到ACK K+1时,accept返回,至此三次握手完毕,连接建立。

6. Socket中TCP的四次握手释放连接

Socket中四次握手释放连接的过程,请看下图:

大致流程为: 1)某个应用进程首先调用close主动关闭连接,这时TCP发送一个FIN M; 2)另一端接收到FIN M之后,执行被动关闭,对这个FIN进行确认。它的接收也作为文件结束符传递给应用进程,因为FIN的接收意味着应用进程在相应的连接上再也接收不到额外数据; 3)一段时间之后,接收到文件结束符的应用进程调用close关闭它的Socket。这导致它的TCP也发送一个FIN N; 4)接收到这个FIN的源发送端TCP对它进行确认。

结束语

基于Socket的知识科普就先进行到这里,希望你能够对它的工作原理有个概念性的掌握,不会在开发沟通过程中一脸懵~因为Socket在网络中的应用非常广,无论是语音、文字、图片甚至文件的网络传输,都是其用武之地,待小编深入学习之后,将针对涉及Socket方面的测试做一次专门的分享,敬请期待~

本文参与 腾讯云自媒体分享计划,分享自微信公众号。
原始发表:2018-11-03,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 软测小生 微信公众号,前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体分享计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档