网络编程基础-socket
Posted Jqivin
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了网络编程基础-socket相关的知识,希望对你有一定的参考价值。
一、socket是什么?
socket 的原意是“插座”,在计算机通信领域,socket 被翻译为“套接字”,它是计算机之间进行通信的一种约定或一种方式。通过 socket 这种约定,一台计算机可以接收其他计算机的数据,也可以向其他计算机发送数据。
socket 的典型应用就是 Web 服务器和浏览器
:浏览器获取用户输入的 URL,向服务器发起请求,服务器分析接收到的 URL,将对应的网页内容返回给浏览器,浏览器再经过解析和渲染,就将文字、图片、视频等元素呈现给用户。
Linux中的socket
– 文件描述符
为了表示和区分已经打开的文件,UNIX/Linux 会给每个文件分配一个 ID,这个 ID 就是一个整数,被称为文件描述符(File Descriptor)。例如:
- 通常用 0 来表示标准输入文件(stdin),它对应的硬件设备就是键盘;
- 通常用 1 来表示标准输出文件(stdout),它对应的硬件设备就是显示器。
UNIX/Linux 程序在执行任何形式的 I/O 操作时,都是在读取或者写入一个文件描述符。一个文件描述符只是一个和打开的文件相关联的整数,它的背后可能是一个硬盘上的普通文件、FIFO、管道、终端、键盘、显示器,甚至是一个网络连接。
所以对socket的操作就是对文件的操作;
Windows中的socket
– 文件句柄
二、socket的类型
1.流式套接字(SOCK_STREAM)
(1)概述:
流格式套接字(Stream Sockets)也叫“面向连接的套接字”,在代码中使用 SOCK_STREAM 表示。
SOCK_STREAM 是一种可靠的、双向的通信数据流,数据可以准确无误地到达另一台计算机,如果损坏或丢失,可以重新发送。
(2)特点:
SOCK_STREAM 有以下几个特征:
- 数据在传输过程中不会消失;
- 数据是按照顺序传输的;(相当于一个传送带)
- 数据的发送和接收不是同步的(有的教程也称“不存在数据边界”)。(缓冲区的使用)
(3)为什么能达到高质量的传输呢?
主要原因就是它使用了TCP协议,TCP协议会控制数据按顺序并且没有错误的传送。TCP 用来确保数据的正确性,IP(Internet Protocol,网络协议)用来控制数据如何从源头到达目的地,也就是常说的“路由”。
流格式套接字的内部有一个缓冲区(也就是字符数组),通过 socket 传输的数据将保存到这个缓冲区。接收端在收到数据后并不一定立即读取,只要数据不超过缓冲区的容量,接收端有可能在缓冲区被填满以后一次性地读取,也可能分成好几次读取。
也就是说,不管数据分几次传送过来,接收端只需要根据自己的要求读取,不用非得在数据到达时立即读取。传送端有自己的节奏,接收端也有自己的节奏,它们是不一致的。
2.数据报套接字(SOCK_DGRAM)
(1)概述
数据报格式套接字(Datagram Sockets)也叫“无连接的套接字”,在代码中使用 SOCK_DGRAM 表示。
计算机只管传输数据,不作数据校验,如果数据在传输中损坏,或者没有到达另一台计算机,是没有办法补救的。也就是说,数据错了就错了,无法重传。
因为数据报套接字所做的校验工作少,所以在传输效率方面比流格式套接字要高。
(2)特征
- 强调快速传输而非传输顺序;
- 传输的数据可能丢失也可能损毁;
- 限制每次传输的数据大小;
- 数据的发送和接收是同步的(有的教程也称“存在数据边界”)。
数据报套接字是一种不可靠的、不按顺序传递的、以追求速度为目的的套接字。
数据报套接字也使用 IP 协议作路由,但是它不使用 TCP 协议,而是使用 UDP 协议(User Datagram Protocol,用户数据报协议)。
QQ 视频聊天和语音聊天就使用 SOCK_DGRAM来传输数据,因为首先要保证通信的效率,尽量减小延迟,而数据的正确性是次要的,即使丢失很小的一部分数据,视频和音频也可以正常解析,最多出现噪点或杂音,不会对通信质量有实质的影响。
三、面向连接和无连接的套接字的区别
不管是哪种数据传输方式,都得通过整个 Internet 网络的物理线路将数据传输过去,从这个层面理解,所有的 socket 都是有物理连接的呀,为什么还有无连接的 socket 呢?这里的连接指的是“虚电路的连接”;
就比如说上面的图,从发送端H1到接收端H6公有很多条路径可以选择,
数据报的传输路径是路由器根据算法来计算出来的,算法会考虑很多因素,比如网络的拥堵状况、下一个路由器是否忙碌等。
无连接的套接字
对于无连接的套接字,每个数据包可以选择不同的路径,比如第一个数据包选择路径④,第二个数据包选择路
径①,第三个数据包选择路径②……当然,它们也可以选择相同的路径,那也只不过是巧合而已。
每个数据包之间都是独立的,各走各的路,谁也不影响谁,除了迷路的或者发生意外的数据包,最后都能到达H6。但是,到达的顺序是不确定的。比如:
-
第一个数据包选择了一条比较长的路径(比如路径⑤),第三个数据包选择了一条比较短的路径(比如
路径①),虽然第一个数据包很早就出发了,但是走的路比较远,最终还是晚于第三个数据包达到。 -
第一个数据包选择了一条比较短的路径(比如路径①),第三个数据包选择了一条比较长的路径(比如
路径⑤),按理说第一个数据包应该先到达,但是非常不幸,第一个数据包走的路比较拥堵,这条路上的数据量非常大,路由器处理得很慢,所以它还是晚于第三个数据包达到了。
还有一些意外情况会发生,比如:
▶ 第一个数据包选择了路径①,但是路由器C突然断电了,那它就到不了 H6 了。
▶ 第三个数据包选择了路径②,虽然路不远,但是太拥堵,以至于它等待的时间太长,路由器把它丢弃
了。
总之,对于无连接的套接字,数据包在传输过程中会发生各种不测,也会发生各种奇迹。H1 只负责把数据包发出,至于它什么时候到达,先到达还是后到达,有没有成功到达,H1 都不管了;H6 也没有选择的权利,只能被动接收,收到什么算什么,爱用不用。
无连接套接字遵循的是「尽最大努力交付」的原则,就是尽力而为,实在做不到了也没办法。无连接套接字提供的没有质量保证的服务。
面向连接的套接字
面向连接的套接字在正式通信之前要先确定一条路径,没有特殊情况的话,以后就固定地使用
这条路径来传递数据包了。当然,路径被破坏的话,比如某个路由器断电了,那么会重新建立路径。
这条路径是由路由器维护
的,路径上的所有路由器都要存储该路径的信息(实际上只需要存储上游和下游的两个路由器的位置就行),所以路由器是有开销的.H1 和 H6 通信完毕后,要断开连接,销毁路径,这个时候路由器也会把之前存储的路径信息擦除。
在很多网络通信教程中,这条预先建立好的路径被称为“虚电路”,就是一条虚拟的通信电路。
为了保证数据包准确、顺序地到达,发送端在发送数据包以后,必须得到接收端的确认才发送下一个数据包;如果数据包发出去了,一段时间以后仍然没有得到接收端的回应,那么发送端会重新再发送一次,直到得到接收端的回应。这样一来,发送端发送的所有数据包都能到达接收端,并且是按照顺序到达的。
发送端发送一个数据包,如何得到接收端的确认呢?很简单,为每一个数据包分配一个 ID,接收端接收到数据包以后,再给发送端返回一个数据包,告诉发送端我接收到了 ID 为 xxx 的数据包。
面向连接的套接字会比无连接的套接字多出很多数据包,因为发送端每发送一个数据包,接收端就会返回一个数据包。此外,建立连接和断开连接的过程也会传递很多数据包。
不但是数量多了,每个数据包也变大了:除了源端口和目的端口,面向连接的套接字还包括序号、确认信号、数据偏移、控制标志(通常说的 URG、ACK、PSH、RST、SYN、FIN)、窗口、校验和、紧急指针、选项等信息;而无连接的套接字则只包含长度和校验和信息。
有连接的数据包比无连接大很多,这意味着更大的负载和更大的带宽。许多即时聊天软件采用 UDP 协议(无连接套接字),与此有莫大的关系。
总结
两种套接字各有优缺点:
无连接套接字传输效率高,但是不可靠,有丢失数据包、捣乱数据的风险;
有连接套接字非常可靠,万无一失,但是传输效率低,耗费资源多。
两种套接字的特点决定了它们的应用场景,有些服务对可靠性要求比较高,必须数据包能够完整无误地送达,那就得选择有连接的套接字(TCP 服务),比如 HTTP、FTP 等;而另一些服务,并不需要那么高的可靠性,效率和实时才是它们所关心的,那就可以选择无连接的套接字(UDP 服务),比如 DNS、即时聊天工具等。
四、socket缓冲区
每个 socket 被创建后,都会分配两个缓冲区,输入缓冲区和输出缓冲区。
write()/send() 并不立即向网络中传输数据,而是先将数据写入缓冲区中,再由TCP协议将数据从缓冲区发送到目标机器。一旦将数据写入到缓冲区,函数就可以成功返回,不管它们有没有到达目标机器,也不管它们何时被发送到网络,这些都是TCP协议负责的事情。
TCP协议独立于 write()/send() 函数,数据有可能刚被写入缓冲区就发送到网络,也可能在缓冲区中不断积压,多次写入的数据被一次性发送到网络,这取决于当时的网络情况、当前线程是否空闲等诸多因素,不由程序员控制。
read()/recv() 函数也是如此,也从输入缓冲区中读取数据,而不是直接从网络中读取。
- I/O缓冲区在每个TCP套接字中单独存在;
- I/O缓冲区在创建套接字时自动生成;
- 即使关闭套接字也会继续传送输出缓冲区中遗留的数据;
- 关闭套接字将丢失输入缓冲区中的数据。
以上是关于网络编程基础-socket的主要内容,如果未能解决你的问题,请参考以下文章