socket的深入理解

1、IP数据包的格式
包含的信息:
版本、首部长度、总长度
标识、标志、偏移量(这些在分片时会用到)
生存时间(8位,最大255,表示在因特网中最多经过的路由器的数值为255,当为1时只能在局域网中传播)、协议(标明ICMP、IGMP、TCP、UDP等)、首部校验和
源地址、目的地址
2 UDP数据报的格式
源端口号、目的端口号、长度、校验和
3 TCP
源端口、目的端口、{数据偏移,选项(MSS)}长度、检验和
序号、确认号、6个控制位(ACK、FIN、SYN、URG、PSH、RET)
窗口(接收窗口,接收方允许发送方发送的数据量)


解释一个名词:MSS(最大报文段长度)数据段的最大长度,不包括首部长度,,默认是536,加上20字节的头部,256
4 TCP的连接和释放过程

客户机A开始处于CLOSED(关闭状态)
服务器开B始CLOSED,后进入listen(收听)状态,等待客户连接请求
A向B发送SYN=1,A的序列号为seq=x的连接请求报文段,不携带数据,但消耗一个序列号
此时A进入到SYN-SENT(同步已发送)状态

B收到后,向A发送确认信号,SYN=1,ACK=1,ack=x+1,seq=y,不携带数据,但消耗一个序列号
此时B进入到SYN-RCVD(同步收到)状态

A收到后,还要给B发送确认(ACK=1,ack=y+1,seq=x+1),不携带数据不消耗,携带数据消耗序列号
A进入到ESTABLISHED(已建立连接状态)

B收到确认后进入(ESTABLISHED)
这里有一个问题:
为什么A还要向B发送一个确认信号

防止已经失效的A的连接请求又发送到B,B以为A要建立连接,就一直等待A发数据,但A没有这样的请求,就不会理B的确认信号,这样导致B资源浪费

TCP连接的释放
A主动关闭TCP连接,A发送连接释放报文,FIN=1,seq=u,不携带数据也消耗序列号
A进入到FIN-WAIT1(终止等待1)

B收到后向A发出确认,ACK=1,seq=w,ack=u+1
B进入到CLOSE-WAIT(关闭等待)
A收到确认后进入FIN-WAIT2(终止等待2)


此时TCP连接处于半关闭
A已经没有数据发送了,但是B发送数据A任然要接收
B发送完数据后
B发送释放连接数据报,FIN=1、ACK=1,ack=u+1,seq=w(B必须重复上次发送过的确认信号),此时B进入到(LAST-ACK)状态
A向B发出确认信号(ACK=1,ack=w+1,seq=u+1),A进入到TIME-WAIT(时间等待)
B收到后CLOSED
A经过2MSL(最长报文段寿命)也结束

这里问题
1 为什么要设置2MSL
1》
为了保证A发送的最后一个ACK可以到达B,ACK可能丢失,B收不到就会超时重传FIN+ACK,A能在2MSL收到这个重传的信号,重新发出ACK启动计时器
2》
防止已失效的报文段出现在本连接中,2MSL所有报文段都会消失


————————————————————————————————————————————————————————————————————————————————————

套接字SOCKET

大体流程:
服务器:调用函数socket创建一个套接字,函数bind将这个套接字与服务器的公认地址绑定,
listen将这个套接字转换成倾听套接字,然后调用accept来等待接受客户机的请求
客户机:调用函数socket创建一个套接字,调用connect与服务器建立连接
最后二者之间通过读写套接字来通信

具体:

socket:参数:协议簇(AF_INET)Internet(TCP/IP)
类型:SOCKET_STREAM
SOCKET_DGRAM
协议:0,默认协议

linux系统中套接字的操作主要是:在内核中创建一个套接字数据结构,然后返回一个套接字描述符标志这个套接字数据结构,这个结构中包含连接的各种信息,对方的地址,TCP状态,发送和接收缓存区

函数bind将本地地址与套接字绑定在一起
服务器和客户机都可以调用函数bind来绑定套接字地址,但一般是服务器调用函数bind来绑定自己的公认端口,一般不指定IP,表示愿意接收来自任何网络接口的客户机连接,意思是有多个网络接口的机器,来自任意一个网络接口的数据都可以接收。

客户机不用指定自己的套接字地址的端口号,当客户机调用函数connect进行TCP连接,系统会自动为他分配一个未用的端口号的,一般不要指定特定的端口号

listen
将一个套接字转为倾听套接字

由于socket创建的套接字是主动套接字,可以用它来进行主动连接,但是不能接受连接请求,而服务器的套接字必须能接受客户机的请求,listen将主动套接字转换成一个被动套接字

其中还包括一个重要的参数,请求队列的长度,backlog表示这个套接字能够接受的最大数目的未接收的连接(已经完成三次握手,但还没有被应用程接收处理)

accept
函数accept从倾听套接字的完成连接队列中接收一个连接
由于倾听套接字是专为接收客户机连接请求,完成三次握手而用的,所以TCP协议不能使用倾听套接字的标志描述这个连接,
意思就是返回一个新的套接字描述符,来标志这个连接,与客户进行通信


connect
指定与服务器信息相关的socket
客户机不用指定自己的套接字地址的端口号,当客户机调用函数connect进行TCP连接,系统会自动为他分配一个未用的端口号的,一般不要指定特定的端口号
1024-5000之间

close
调用了函数close进程将不能访问这个套接字,但是不表示TCP协议删除了这个套接字,TCP将继续使用这个套接字,将尚未发送的数据传递到对方,然后发送fin数据段,执行关闭,之后才删除这个套接字


read write
里想说明下缓存区

从网络上读、写的数据操作是由TCP协议在内核中完成的,然后TCP套接的缓存区,从内核中接收数据放在自己里面,read,write则从套接字的缓存区中,将数据拷贝到用户缓存区

这里buff的参数也是用户缓存区的参数

readline一次读取一个字符,检测这个字符是否有回车符,如果是,返回,读取了一行
read是系统调用,每次执行需从内核拷贝到用户缓存区,一次拷贝一个效率低的很
为了提高效率,read_line调用函数get_char来读取一个字符,由函数get_char从内核读取数据
get_char调用函数read一次从内存读取一块数据,保存在静态缓存区中,read——line调用getchar读取一个字符时,检查静态缓存区,没有在从内存读


UDP连接
服务器首先调用函数socket建立一个数据报类型的套接字,调用bind绑定端口,然后调用recvfrom接收UDP客户机的数据

 

recvfrom
可以再参数中获得发送者的地址
sendto
可以再参数中指定接收者的地址

因为UDP是非面向连接的,所以系统不再套接字结构中记录接收者的地址信息,需要在每次调用发送函数sendto时指定接收方的地址
接收数据包时,如果需要知道发送者的地址,可以再接收函数recvfrom中提供空间,由内核来填充,不需要,则这个参数置0即可


UDP协议没有为udp套接字设置发送缓冲区,函数sendto将数据从用户缓冲区拷贝到系统缓冲区,也可以说UDP缓冲区只要一个缓冲区大小,这个大小用来限制可以发送的最大UDP数据报的大小
但是有接收缓冲区队列

UDP允许接收空数据报,此时函数recvfrom的返回值为0
TCP中读操作返回0,表示读到了文件结束符,表示对方结束发送了

服务器是循环服务器
UDP服务器与客户机没有固定的连接,UDP服务器能够交替的处理多个客户机的请求,前后两次循环处理的可以使来自不同客户机的请求,一个UDP客户机崩溃,不会照成服务器服务失效
TCP客户机可以独占服务器,服务器只能处理完一个客户机的请求,在处理下一个,当一个客户机主机崩溃时,可能照成服务器的服务失效


服务器无法获得自己的IP(除非绑定时,设置本地IP)
客户机不用建立连接
应用程序首次调用sendto时,udp协议为之分配一个自由端口,这个端口号在整个通信过程中都不变,不存在本地IP,这个地址在IP协议发送数据报时,根据路由情况选择,然后填充到UDP数据报的首部,所以数据报们,使用相同的端口,但IP可能不同


客户机可以接收来自任何主机的数据报,只要这个主机知道他的本地端口号,所以客户机要检查发送过来的数据报的发送者,只接受服务器的

 

 

 

 

  • 0
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值