1.流式套接字网络编程的函数:
- socket(int af,int type,int protocol):af:一个地址描述符,目前仅支持AF_INET格式;type:指定套接字的类型;protocol:指定要使用的特定的传输协议
- bind():三个参数分别为:调用套接字socket()反返回的描述符;地址参数;地址结构的大小
- listen():指明监听队列长度
unix 上面 listen(sockfd,5) 5是指未完成握手已完成握手队列客户端个数总和不超过,Linux中 listen(sockfd,5) 5是指已完成三次握手总数不超过5
- accept():已绑定并且监听的套接字;被声明为一个指向socketaddr结构的指针;地址结构的长度
accept会提取出监听套接字的等待队列中的第一个连接请求,创建一个新的套接字,并返回指向该套接字的文件描述符,新建的套接字不再监听状态,原来所监听的套接字也不受影响
- recv():已连接套接字的描述符;用于接收数据的缓冲区;接收缓冲区的长度;指定的调用方式(返回值是实际接受的字节总数)
- send():已连接套接字的描述符;指向要发送的字节序列;发送的字节数;指定的调用方式(返回值是实际发送的字节总数)
- connect():四个参数分别为:调用套接字socket()反返回的描述符;被声明为一个指向socketaddr结构的指针;地址结构的长度
2.流式套接字网络编程注意:
(1)send仅仅是把buff中的数据拷贝到套接字s的发送缓冲区的剩余空间中;recv也是把套接字s的接收缓冲区中的数据拷贝到buff中;
(2)协议接收到的数据大于buff的长度时,这种情况下会多次调用recv才能把套接字s的接收缓冲区中的数据拷贝完;当send中发送的数据长度大于发送缓冲区的长度时,函数返回SOCKET_ERROR
(3)调用connect函数将会激发TCP/IP的三次握手过程,而且仅在连接建立成功或出错时返回,
(4)如何解决connect在连接时不阻塞住:设置一个超时时间,超过设置的事件之后返回失败
(5)当客户端close后,虽然程序大都已经要结束但是,状态并没有随着程序的结束很快结束,而是缓慢结束,连接慢慢断开,刚结束时端口任然在(程序结束并不代表连接已经完全断开)也就是在close时激发四次挥手
(6)发送端执行的写操作次数和接收端执行的读的次数之间没有任何数量关系,这就是字节流的概念:应用程序对数据的发送和接收是没有边界限制的。
(7)recv函数的返回值:
①大于0代表接收到数据,如果小于等于0时则分两种情况
②等于0时代表对方客户端关闭,唯一判断对方关闭的方法就是当recv返回值为0的时候与管道相似,写端返回0读端关闭
③小于零则recv函数调用发生错误
(8)当客户端1与服务器连接没有退出在等待输入时,客户端2可以与服务器端连接,但是服务器端不会返回,而是处于阻塞状态,因为还处于前客户端1的recv中等待客户端1发送数据,等待客户端1的退出,只有当别的客户端退出时该客户端的数据才会被接收,在此之前都只是连接将数据放在了监听队列中。
3.连接过程中可能出现的问题:
(1)场景一:正常的回射客户端和服务器通信,发送数据一切正常。
(2)场景二:服务器未启动时
由于服务器端未启动,客户端请求连接失败。因为正常情况下先启动服务器,服务器端会处于监听状态,当发现有请求链接时将该客户端放入监听队列中,等待接收之后客户端发送数据。
(3)场景三:服务器进程崩溃
模拟场景:通过在运行过程中直接关闭服务器端的方式来实现假设的服务器进程崩溃。
实验抓包结果:在这个场景下,服务端进程发送FIN给客户端连接套接字,客户端收到后发送ack给服务端,如果此时客户端往服务端写数据,服务端将回复RST终止连接。
(4)场景四:客户端进程崩溃
模拟场景:关闭客户端进程
实验抓包结果:仍然正常断开连接,但是服务端会有错误返回
(5)场景五:服务器主机崩溃或网络紊乱
模拟场景:拔掉客户端的网线
实验抓包结果:客户端会持续重传,持续一段时间后仍未收到确认则放弃。
(6)场景六:服务器主机崩溃后重启
模拟场景:拔掉服务器端网线之后重启
实验抓包结果:如果客户端与服务器端连接成功,拔掉网线,重新运行服务器端,再插好网线,不能继续连接,因为客户端没有收到断开消息,以为自己和服务器端还在连接,但是服务器端重新运行IP地址已经变化。如果客户端继续给服务器端发送数据则会出现send错误,此时客户端会收到服务器端的RST。
4.RST包
RST包是用来释放Tcp的连接机制,当在Tcp正常是通过三次握手建立连接四次挥手断开连接。但是有时候会有一些意外情况发生就像此次实验中的场景三场景五和场景六。这种情况会导致无法通过四次挥手正常断开,导致这个Tcp链接一直存在占用系统的部分资源。所以当服务器端异常断开时客户端就会接受到RST包。
5.粘包问题
(1)在数据收发过程中涉及到的缓冲区:
①数据在发送过程中主要涉及到两个缓冲区,一个是应用 程序发送缓冲区,即调用send函数时由用户申请并填充的缓冲区,这个缓冲区保存了用户即将使用协议栈发送的TCP数据;另外一个是TCP套接字的发送缓冲区,这个缓冲区中保存了TCP协议尚未发送的数据和已发送但未得到确认的数据。数据发送涉及两个层次的操作:从应用程序发送缓冲区拷贝数据到TCP套接字的发送缓冲区,以及从TCP套接字的发送缓冲区中将数据发送到网络中
②数据接收在实施时也涉及两个缓冲区,一个是TCP套接字的接收缓冲区,在这个缓冲区中保存了TCP协议从网络中接收到的与该套接字相关的数据,另外的应用程序接收缓冲区即调用recv函数时由用户分配的缓冲区,这个缓冲区用于保存从TCP套接字的接收缓冲区收到并提交给应用程序的网络数据,接收数据也分两个层次,即从网络到TCP套接字的接收缓冲区,和从TCP套接字的接收缓冲区到应用程序的接收缓冲区中
recv和send函数仅仅是copy数据,真正的接收数据是通过底层协议来完成的,recv和send只是从TCP套接字的接收/发送缓冲区中将数据复制到应用程序的接收/发送缓冲区
(2)TCP产生粘包的原因:TCP是字节流是无边界的,而udp是消息、数据报,是有边界的。从而当流式套接字发送数据时如果两次send一次recv时,由于字节流的原因就会出现两次send数据粘在一起。
(3)由于在网络中收发数据收到主机、网络状况等众多因素的影响,有可能出现:一,一次接收一次大于无法接受完全部数据;二,接收函数的调用结果有很多种。
(4)解决办法:报头加上报体长度。