转自:
https://blog.csdn.net/pashanhu6402/article/details/96428887
https://blog.csdn.net/noricky/article/details/82626188
http://www.360doc.com/content/20/0218/14/99071_892916049.shtml
1.网络进程中的通信
同一主机上,不同进程可用进程号(process ID)唯一标识,通过管道、命名管道、消息队列、共享内存、信号量等方式进行通信,那么网络中的不同主机如何通信?
网络层的“ip地址”可以唯一标识网络中的主机,而传输层的“协议+端口”可以唯一标识主机中的应用程序(进程)。这样利用三元组(ip地址,协议,端口)就可以标识网络的进程了,网络中的进程通信就可以利用这个标志与其它进程进行交互。
2.socket所在层次
负责在用户进程和TCP运输层之间通信,相当于封装了TCP/UDP为库函数,用户直接调用就可以。
即它是一组接口。在设计模式中,Socket其实就是一个门面模式,它把复杂的TCP/IP协议族隐藏在Socket接口后面。
3.套接字描述符
- 套接字描述符也就是一个文件描述符,就是一个整数;我们最熟悉的句柄是0、1、2三个,0是标准输入,1是标准输出,2是标准错误输出。0、1、2是整数表示的,对应的FILE *结构的表示就是stdin、stdout、stderr。
- 当应用程序要为因特网通信而创建一个套接字(socket)时,操作系统就返回一个小整数作为描述符(descriptor)来标识这个套接字。
- 然后,应用程序以该描述符作为传递参数,通过调用函数来完成某种操作(例如通过网络传送数据或接收输入的数据)。
在许多操作系统中,套接字描述符和其他I/O描述符是集成在一起的,所以应用程序可以对文件进行套接字I/O或I/O读/写操作:
每个进程PCB中都保存指向文件描述符的指针,文件描述符中存储着进程打开的文件,每个文件描述符都和一个文件绑定,可以通过函数进行IO操作。
- 精确地讲,系统为每个运行的进程维护一张单独的文件描述符表。
- 当进程打开一个文件时,系统把一个指向此文件内部数据结构的指针写入文件描述符表,并把该表的索引值返回给调用者 。
- 应用程序只需记住这个描述符,并在以后操作该文件时使用它。
- 操作系统把该描述符作为索引访问进程描述符表,通过指针找到保存该文件所有的信息的数据结构。
套接字数据结构:
套接字API里有个函数socket,它就是用来创建一个套接字。
文件指针是个结构体类型,其中包含文件描述符,文件描述符作为索引,可以在文件描述符表中找到指向文件的指针。
4.socket通信过程
socket():
通常服务器在启动的时候都会绑定一个众所周知的地址(如ip地址+端口号),用于提供服务,客户就可以通过它来接连服务器,客户端通过这个端口填入connect()函数形参;
而客户端就不用指定,有系统自动分配一个端口号和自身的ip地址组合。这就是为什么通常服务器端在listen之前会调用bind(),而客户端就不会调用,而是在connect()时由系统随机生成一个。
accept():
accept默认会阻塞进程,直到有一个客户连接建立后返回,它返回的是一个新可用的套接字,这个套接字是连接套接字。
此时我们需要区分两种套接字,
- 监听套接字: 监听套接字正如accept的参数sockfd,它是监听套接字,在调用listen函数之后,是服务器开始调用socket()函数生成的,称为监听socket描述字(监听套接字)
- 连接套接字:一个套接字会从主动连接的套接字变身为一个监听套接字;而accept函数返回的是已连接socket描述字(一个连接套接字),它代表着一个网络已经存在的点点连接。
两种不同的socket,分工不同。
连接套接字socketfd_new 并没有占用新的端口与客户端通信,依然使用的是与监听套接字socketfd一样的端口号。
可以通过Read()/write()等函数从连接套接字中读写数据。那么socket是如何实现数据在两个主机之间发送的呢?
Linux内核组成图
由上述两张图片可以看出,read/write()等函数也是封装了更底层的协议驱动程序,当写入socket文件时,在某个时机通过在TCP/IP协议驱动程序封装,再在以太网卡驱动程序中封装为以太网帧,然后通过硬件网线或者无线网络电磁波发送,具体的数据传输肯定都是以比特流在物理层传输的,socket只是负责上层的工作,具体的传输是交给其他层去完成,我们只负责调用函数就行了。
///具体:
作者:水止云起
链接:https://www.jianshu.com/p/8c1f37361a89
来源:简书
著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。
那么什么时候文件描述符是可读的、可写的?
(可读,已经通过以太网接收到了数据,上层应用程序读;可写,上层应用程序想发送数据给另一方,socket文件描述符是否能写?写好了就通过以太网传给对方。)
通过上面可以发现,socket有内核接收缓冲区、发送缓冲区,并不都是直接写到文件里的。那么有个疑问,接收缓冲区的内容有没有写入过socket中?
见下一篇博客。