首先对于访问上篇博文(【网络基础-计算机字节序】)的同学们表示感谢,对于第一篇博文就有1k左右的浏览量“零号”还是很开心的。以后也会争取给大家发布更有价值的,通俗易懂的博文。“零号‘’是开心了,但是“壹号”同学就没有这么顺利,他又面试失利了,他上篇博文搞定了“网络套接字”的问题,但这次又败在了对TCP套接口编程的理解上,此篇博文我们就说一说TCP套接口编程到底有哪些难搞的地方,有哪些坑容易被问到。照例,先列出失败的问题:
面试官问题1:TCP客户端与服务器端的创建过程您了解吗?
面试官问题2:可以谈谈您对于每个函数的理解吗?
面试官问题3:可以说一说您对listen以及accept函数的理解吗?
首先,先来了解一下TCP套接口编程的过程。如图1(图片来自UNIX网络编程-卷一):
图1
从上图可以看出,客户与服务器的通信流程为:
服务器端:
- 调用socket创建套接字描述字
- 调用bind绑定服务ip和端口号
- 调用listen将主动连接套接字改为被动连接套接字
- 调用accept等待客户端连接
- 有客户连接后:
- read读取客户发送来的数据
- 处理用户请求
- write给客户发送回复信息
- 处理完成后,调用close关闭accept返回的已连接套接字
- 有客户连接后:
客户端:
- 调用socket创建套接字描述字
- 调用connect请求连接服务器
- 连接成功后:
- write发送请求
- read接收服务器的应答
- 进行业务处理
- 处理完成后,调用close关闭socket创建的套接字描述字
- 连接成功后:
服务器端在通信过程中执行的接口分别为,socket,bind,listen,accept,read,write,close;客户端在通信过程中分别调用的接口为socket,connect,write,read,close。
下面我们来详细说一说通信过程中用到的这些接口及其功能:
socket:创建套接口描述字(套接字)
头文件:#include <sys/socket.h>
int socket(int family,int type,int protocol);
返回值:成功:非负描述字,失败:-1
参数说明:
family:协议簇选项,当前套接口的协议类型。图2解释了不同值代表的意义
type:常用类型,TCP一般为字节流套接口,UDP一般为数据报套接口,如下图3
protocol:协议号,通常设置为0,但在原始套接口上可能会有不同。
图2
图3
family&type组合成的协议类型如下图4,从图中我们可以看出TCP都是字节流型的报文,UDP都是数据报类型的报文:
图4
connect:客户端用来建立与服务器的连接
头文件:#include <sys/socket.h>
int connect(int sockfd,const struct sockaddr *servaddr,socklen_t addrlen);
返回值:成功:0 错误:-1
参数说明:
sockfd:套接口描述字,客户端socket函数创建的套接字
servaddr:套接口地址结构指针,其内部必须包含服务器的IP地址和端口号
addrlen:套接口地址结构大小
延伸:在TCP连接过程中,connect函数激发TCP的三路握手过程,且仅在连接建立成功或出错时才返回,返回的错误可能有以下几种情况:
- tcp客户没有收到SYN分节的响应,则返回ETIMEDOUT。
- 客户接受到RST响应,则表明该服务器主机在我们指定的端口上没有进程与之连接。
- 如果某客户发出的SYN在中间的路由器上引发了一个目的地不可达ICMP错误。客户保存此消息,并按一定的时间间隔连续发出SYN。若在规定时间后仍未收到响应