Socket

介绍

Socket实质就是基础网络结构中,对TCP/IP协议族加的一层抽象(API),介于网络层与运输层之间,方便开发人员快捷地使用TCP/IP来进行网络部分的开发。

大致结构

工作原理

流程图解

网络进程之间的通信

  • 既然要进行通信,那么就得明确通信主体对象,必须有发出,和接收的目标。在计算机本地进程之间的通信,是将进程的PID值作为唯一标识来区分不同进程,进而通信。
  • 而作为网络不同主体不同进程之间的通信,也就必须要有唯一的标识来区分,不然就无法按图索骥,找到正确的接收主体,和发送主体。

TCP/IP协议族的网络传输结构中,网络层中的IP地址可以唯一标识网络中的主机,而在传输层的协议+端口则可以唯一标识主机中的每个应用程序(进程),这样通过三元组(IP+协议+端口)就可以唯一标识不同主机的不同进程了。(目前网络中使用TCP/IP协议族的程序基本都是采用socket接口,所以socket目前是网络编程通用基础。)

提炼:

  • IP地址(唯一标识网络层的主机)
  • 协议 + 端口 (唯一标识主机中的进程)

Socket详解

设计思路:

Socket的设计起源于Unix,而Unix/Linux基本哲学之一就是“一切皆文件”,什么是文件?文件应该就是支持open(打开)、read/write(读写)、close(关闭)等操作的数据集合。所以Socket其实也可以抽象化为这么一个特殊的文件,支持打开、关闭、读写等操作。

基本操作:
  1. socket(domain, type, protocol)
    该函数对应于open操作,用于创建一个socket描述符(socket descriptor),唯一标识这个socket,通过这个描述符就能对它进行一些其他操作。
    @param:
  • domain:协议域,决定了socket的地址类型,在通信中就必须采用对应的地址。
  • type:指定了socket的类型。
  • protocol:指定使用的协议。(TCP、UDP等传输协议)
    注:type和protocol并不能随意组合,当protocol为0时,则自动选择type类型对应的默认协议。
    当调用socket创建描述符后,它存在于协议族空间,是没有具体地址的。只有调用bind()函数才绑定一个端口,又或是当调用connect()、listen()时系统会自动随机分配一个端口。
  1. bind(sockfd, addr, addrlen)
    该函数用于把一个地址族中的特定地址赋予socket(eg:ip+端口)。通常服务器在启动的时候就会调用它来绑定一个公开的地址(ip地址+端口号),用于提供服务,客户端都通过该地址来连接服务器,而客户端不需要调用该函数,因为其地址(ip+端口)是在调用connect()函数连接服务器时,由系统自动分配的。
    @param:
  • sockfd:socket描述字,是通过socket()函数创建的,唯一标识socket,也就是要绑定地址的目标对象。
  • addr:一个指向需要绑定给sockfd对象协议地址的指针(struct sockaddr*),结构多变,根据地址协议族(domain)的不同而不同。
  • addrlen:对应地址的长度。
  1. listen(sockfd, backlog)
    服务器持有,在服务器为socket描述字bind()一个端口后,调用该函数来监听这个socket,用于在客户端发送connect请求后,接收请求,建立连接。通过socket()函数创建的socket默认为主动类型,listen函数会将其变为被动类型,可以等待客户端的连接请求。
    @param:
  • sockfd:要监听的socket描述字,同上。
  • backlog:对应socket可以排队的最大连接个数。
  1. connect(sockfd, addr, addrlen)
    客户端持有,通过调用该函数发出连接请求,建立与TCP服务器的连接。
    @param:
  • sockfd:socket描述字,同上。
  • addr: 服务器的socket地址指针。
  • addrlen:socket地址的长度。
  1. accept(sockfd, addr, addrlen)
    TCP服务器在调用listen()函数对socket进行监听后,在收到TCP客户端发送来的connect连接请求时,就会调用该函数来接受请求,建立了连接,之后就可以正常进行网络数据的收发(类似于文件的read/write操作)
    @param:
  • sockfd:服务器的socket描述字,同上。
  • addr:socket地址指针,用于返回客户端的协议地址。
  • addrlen:协议地址的长度。

如果accept成功,那么其返回值为由内核自动生成的一个全新描述字,代表与返回客户端的TCP连接。

注:accept的第一个参数为服务器的socket描述字,是服务器开始调用socket()函数生成的,称为监听socket描述字;而accept函数返回的是已连接的socket描述字。一个服务器通常通常仅仅只创建一个监听socket描述字,它在该服务器的生命周期内一直存在。内核为每个由服务器进程接受的客户连接创建了一个已连接socket描述字,当服务器完成了对某个客户的服务,相应的已连接socket描述字就被关闭。

  1. read()、write()等函数
    网络I/O操作有下面几组:
  • read()/write()
  • recv()/send()
  • readv()/writev()
  • recvmsg()/sendmsg()
  • recvfrom()/sendto()
    推荐使用recvmsg()/sendmsg()函数,为通用的I/O函数,实际可以将上述其他函数都替换成这两个函数。
sendmsg(sockfd, msg, flags);

recvmsg(sockfd, msg, flags);

read函数是负责从fd中读取内容.当读成功时,read返回实际所读的字节数,如果返回的值是0表示已经读到文件的结束了,小于0表示出现了错误。如果错误为EINTR说明读是由中断引起的,如果是ECONNREST表示网络连接出了问题。

write函数将buf中的nbytes字节内容写入文件描述符fd.成功时返回写的字节数。失败时返回-1,并设置errno变量。
在网络程序中,当我们向套接字文件描述符写时有两种可能性:
(1). write的返回值大于0,表示写了部分或者是全部的数据。
(2). write的返回的值小于0,此时出现了错误。我们要根据错误类型来处理。如果错误为EINTR表示在写的时候出现了中断错误。如果为EPIPE表示 网络连接出现了问题(对方已经关闭了连接)。

  1. close(sockfd)
    在客户端与服务器建立连接,并且完成了所需要的读写操作后,需要调用该函数来关闭对应的socket描述字,就如同打开文件操作后,必须关闭对应文件。
    @param:
    sockfd:socket描述字,同上。

注:
close一个TCP socket的缺省行为时把该socket标记为以关闭,然后立即返回到调用进程。该描述字不能再由调用进程使用,也就是说不能再作为read或write的第一个参数。
close操作只是使相应socket描述字的引用计数-1,只有当引用计数为0的时候,才会触发TCP客户端向服务器发送终止连接请求。

socket中TCP三次握手建立连接详解

大致流程:
  1. 客户端向服务器发送一个SYN J
  2. 服务器向客户端响应一个SYN K,并对SYN J进行确认ACK J+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返回结果,至此三次握手完毕,连接建立。

总结:客户端的connect在三次握手的第二次返回,而服务器端的accept在三次握手的第三次返回。

socket中TCP的四次挥手释放连接详解

四次握手释放连接图示

图示过程:

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

每个方向都有一个FIN和ACK。

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 204,732评论 6 478
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 87,496评论 2 381
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 151,264评论 0 338
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 54,807评论 1 277
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 63,806评论 5 368
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,675评论 1 281
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 38,029评论 3 399
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,683评论 0 258
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 41,704评论 1 299
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,666评论 2 321
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,773评论 1 332
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,413评论 4 321
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 39,016评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,978评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,204评论 1 260
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 45,083评论 2 350
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,503评论 2 343

推荐阅读更多精彩内容

  • 网络中进程之间如何通信 为了方便大家获取源代码,可以移步这里,GitHub源代码 进程通信的概念最初来源于单机系统...
    batbattle阅读 14,150评论 1 5
  • 一、网络各个协议:TCP/IP、SOCKET、HTTP等 网络七层由下往上分别为物理层、数据链路层、网络层、传输层...
    杯水救车薪阅读 2,258评论 0 17
  • Socket原理 1.什么是TCP/IP、UDP? 2.Socket在哪里呢? 3.Socket是什么呢? 4.你...
    Yong_bcf4阅读 187评论 0 0
  • 什么是TCP/IP、UDP? TCP/IP(Transmission Control Protocol/Inter...
    Zb_c474阅读 266评论 0 0
  • 1 Socket API函数 WinSock的实现方式是利用Windows的动态链接库实现的,所以如果在Windo...
    Veahow阅读 1,961评论 0 0