为了账号安全,请及时绑定邮箱和手机立即绑定
1.2 UDP 协议

UDP 是一种不可靠的传输机制,但是它的数据报文比 TCP 小,所以相同数据的传输 UDP 所需的带宽更少,传输速度更快。它不要事先建立连接,知道对方的地址后直接数据包就扔过去,也不保证对方有没有收到。

2.1 TCP 和 UDP

面试官提问: TCP 协议和 UDP 协议有什么区别?有什么共同点?题目解析:相同点:两个协议最大的共同点是都位于 TCP/IP 网络模型的传输层。不同点:我们通过表格的形式对比不同。TCP(Transmission Control Protocol,传输控制协议)UDP(User Datagram Protocol,用户数据报协议)是否连接面向连接无连接传输方式面向字节流:直接以字节流形式传输面向报文:对于应用程序交付的数据,添加首部之后就交付给 IP 层首部格式 20 个字节的固定首部只有 8 个字节是否可靠可靠传输,依靠流量控制和拥塞控制不可靠传输连接对象个数一对一连接支持一对一(点到点),一对多以及多对多传输适用场景要求可靠传输的场景,例如发送邮件和传输文件对可靠性要求低,效率要求高的场景,例如 QQ 的视频通话根据表格中的特点对比我们可以总结得到:TCP 协议面向连接并且可靠,UDP 协议无连接并且不可靠;虽然 UDP 协议不可靠,但是在对数据完整性要求低,对传输速度要求高的场景,可以适用 UDP 协议。

1. TCP 与 UDP

在模型之下,又衍生出两种经典的传输层协议——TCP 和 UDP,我们分别看看这两个协议。

2. 传统 UDP 客户端和服务器建立过程

同样,我们展示了通过 C 语言 Socket API 编写 UDP 客户端和服务器程序的步骤,如下:图中的矩形方框都是 C 函数。对比 TCP 客户端、服务器的建立过程,我们发现 UDP 客户端可以调用 connect 函数,但是并不会去连接服务器,只是和本地接口做绑定;UDP 服务器是没有 listen 和 accept 调用的。对于 UDP 客户端来说,connect 函数的调用是可选的。接下来,我们就探讨一下如何用 Java 语言编写 UDP 客户端和服务器程序。

2.2 TCP 和 UDP 报文

面试官提问: 上述你提到了 UDP 和 TCP 报文,它们的具体结构是怎样的?题目解析:在上个题目中我们总结了 TCP 协议和 UDP 协议的不同点,其中谈到了 TCP 和 UDP 协议首部格式不同,接下来分别画图分析。​ (UDP 报文首部) 如上图可见,UDP 首部只有 8 个字节的数据,包括源端口号、目标端口号、长度以及校验和。源端口号:发送计算机的应用端口;目标端口号:接收端计算机的接收端口,也是占用 16 位 Bit;长度:表示 UDP 报文首部以及携带数据的长度;校验和:校验数据在传输过程中是否损坏。​ (TCP 报文首部)在画完了示意图之后,关于 TCP 报文首部,我们需要解释的字段:序号:对字节流编号,例如本次传输的序号是 100,携带的数据长度是 100 字节,那么下次传输的序号就是 200;确认号:客户端 A 往服务器端 B 发送了一个报文,序号是 100,携带的数据长度是 100 字节,那么 B 往 A 发送的报文中确认号就是 200,表示期望收到的下一个报文的序号。标志位 CWR(Congestion Window Reduce):拥塞窗口减少标志;标志位 ECE(ECN Echo):ECE 标志等于 1 时,通知接收方,表示接收方到这边的网络存在拥塞;标志位 URG(Urgent):本报文是否包含紧急数据,只有当 URG=1 时,"校验和" 后面的 "紧急指针" 字段才有效;标志位 ACK(Acknowledgement):ACK=1 则表示前面发送的确认号是否有效,TCP 连接建立之后,ACK 必须设置为 1;标志位 PSH(Push):PSH 设置为 1 则表示需要将收到的数据立即传输给上层应用,否则先放缓存;标志位 RST(Reset):RST 设置为 1 则表示 TCP 连接出现异常,需要强制断开;标志位 SYN(Synchronize):SYN 设置为 1 则表示希望建立连接;标志位 FIN(Finsish):FIN 设置为 1 则表示数据已经发送完成,可以断开 TCP 连接。上述定义中,序号、确认号以及 ACK、SYN 和 FIN 标志位是我们需要重点关注的部分,因为在 TCP 建立连接和断开连接时会涉及到。

4. Java UDP 客户端

我们创建一个简单的 UDP 客户端程序,代码如下:import java.io.IOException;import java.net.DatagramPacket;import java.net.DatagramSocket;import java.net.InetSocketAddress;import java.net.SocketAddress;public class UDPClient { private static final int PORT = 9002; private static final String DST_HOST = "127.0.0.1"; private static final int RECV_BUFF_LEN = 1500; private static byte[] inBuff = new byte[RECV_BUFF_LEN]; public static void main(String[] args) { // 创建 UDP 客户端 Socket,选择无参构造方法,由系统分配本地端口号和网络接口 try (DatagramSocket udpClient = new DatagramSocket()){ // 构造发送的目标地址,指定目标 IP 和目标端口号 SocketAddress to = new InetSocketAddress(DST_HOST, PORT); while (true){ String req = "Hello Server!"; // 构造发送数据包,需要传入消息内容和目标地址结构 SocketAddress DatagramPacket message = new DatagramPacket(req.getBytes(), req.length(), to); // 发送消息 udpClient.send(message); System.out.println("Send UDP message:" + req + " to server:" + message.getSocketAddress().toString()); // 构造接收消息的数据包,需要传入 byte 数组 DatagramPacket inMessage = new DatagramPacket(inBuff, inBuff.length); // 接收消息 udpClient.receive(inMessage); System.out.println("Recv UDP message:" + new String(inMessage.getData(), 0, inMessage.getLength()) + " from server:" + inMessage.getSocketAddress().toString()); // 每隔 2 秒发送一次消息 try { Thread.sleep(2000); } catch (InterruptedException e) { e.printStackTrace(); } } } catch (IOException e) { e.printStackTrace(); } }}

1.2 UDP 协议

UDP 又叫用户数据包协议,相对于 TCP,它是一种面向无连接的协议,也就是通信双方在交换数据之前无需建立一条专用通道,当然在通信结束前也无需释放通道。这样一来,通信的效率非常高,但缺点是我们无法确定发出去的消息对方是否能够准确收到,所以它是一个轻量不可靠的通信方式。以上的定义描述了二者主要的差异,更多细致的内容可以参考其他资料。

5. Java UDP 服务端

我们创建一个简单的 UDP 服务端程序,代码如下:import java.io.IOException;import java.net.DatagramPacket;import java.net.DatagramSocket;public class UDPServer { private static final int BIND_PORT = 9002; private static final String BIND_HOST = "127.0.0.1"; private static final int RECV_BUFF_LEN = 1500; private static byte[] inBuff = new byte[RECV_BUFF_LEN]; public static void main(String[] args) { // 构造服务器 Socket,绑定到一个固定的端口,监听的 IP 是 0.0.0.0 try (DatagramSocket udpServer = new DatagramSocket(BIND_PORT)) { // 构造接收消息的数据包,需要传入 byte 数组。 // 我们将这条语句放在循环外,不需要每次消息收发都构造此结构 DatagramPacket inMessage = new DatagramPacket(inBuff, inBuff.length); while (true){ // 接收客户端消息 udpServer.receive(inMessage); System.out.println("Recv UDP message:" + new String(inMessage.getData(), 0, inMessage.getLength()) + " from Client:" + inMessage.getSocketAddress().toString()); String rsp = "Hello Client!"; // 构造发送的消息结构 // 注意!!!对于服务器来说,发送的目标地址一定是接收消息时的源地址,所以从 inMessage 结构获取 DatagramPacket message = new DatagramPacket(rsp.getBytes(), rsp.length(), inMessage.getSocketAddress()); // 发送消息 udpServer.send(message); System.out.println("Send UDP message:" + rsp + " to Client:" + message.getSocketAddress().toString()); // 重置接收数据包消息长度,准备接收下一个消息 inMessage.setLength(inBuff.length); } } catch (IOException e) { e.printStackTrace(); } }}

1. 前言

UDP 的英文全称是:User Datagram Protocol,翻译成中文叫用户数据报协议,它是 TCP/IP 协议族中一个非常重要的传输层协议。UDP 是一个无连接的、不可靠的传输层协议,没有丢包重传机制、没有流控机制、没有拥塞控制机制。UDP 不保证数据包的顺序,UDP 传输经常出现乱序,UDP 不对重复包进行过滤。既然 UDP 这么多缺点,我们还有学习的必要吗?其实不然,正是因为 UDP 没有提供复杂的各种保障机制,才使得它具有实时、高效的传输特性。那么 UDP 到底有哪些优势呢?第一,UDP 是面向消息的传输协议,保证数据包的边界,不需要进行消息解析,处理逻辑非常简单。第二,UDP 具有实时、高效的传输特性。第三,协议栈没有对 UDP 进行过多的干预,这给应用层带来了很多便利,应用程序可以根据自己的需要对传输进行控制。比如,自己实现优先级控制、流量控制、可靠性机制等。当然还有其他一些优势,我就不再一一列举。UDP 在音视频会议、VOIP、音视频实时通信等行业有着广泛的应用。为此,我们是非常有必要学好 UDP 的。由于 UDP 相对简单,学习起来也会轻松很多。

1. 前言

UDP 是面向数据报的传输协议。UDP 的包头非常简单,总共占用 8 字节长度,格式如下:+--------------------+--------------------+| 源端口(16 bits) | 目的端口(16 bits) |+--------------------+--------------------+| 包的长度(16 bits) | 检验和(16 bits) |+--------------------+--------------------+源端口号:占用 2 字节长度,用于标识发送端应用程序。目的端口:占用 2 字节长度,用于标识接收端应用程序。包的长度:表示 UDP 数据包的总长度,占用 2 字节长度。包的长度的值是 UDP 包头的长度加上 UDP 包体的长度。 包体最大长度是 65536-8 = 65528 字节。提示:网络层的 IPv4 Header 也包含了 Length 字段,IPv4 Payload 的最大长度是 65536-60 = 65476 字节。如果我们控制 UDP 数据包总长度不超过 65476 字节,UDP Header 其实是不需要 UDP Length 字段的。因为在实际开发中,程序员会保证传给 UDP 的数据长度不超过 MTU 最大限度,所以 UDP Length 字段显得有点儿多余。检验和:占用 2 字节长度。UDP 检验和是用于差错检测的,检验计算包含 UDP 包头和 UDP 包体两部分。从 UDP 的协议格式可以看出,UDP 保证了应用层消息的完整性,比如,UDP 客户端向服务器发送 “Hello Server,I’m client。How are you?”,UDP 客户端发送的是具有一定含义的数据,UDP 服务端收到也是这个完整的消息。不像面向字节流的 TCP 协议,需要应用程序解析消息。为此,UDP 编程会简单很多。

4. tcp/udp 配置初步

Nginx 从 1.9.0 版本开始,新增加了一个 stream 模块,用来实现四层协议的转发、代理或者负载均衡等。这个模块使用和 http 指令块类似。我们同样在之前的配置准备一个 nginx.conf 文件,里面只有一个 stream 的指令块,如下:user root;worker_processes 2;#error_log logs/error.log;#error_log logs/error.log notice;#error_log logs/error.log info;#pid logs/nginx.pid;events { worker_connections 1024;}stream { server { listen 3000; return '3000 server get ip: $remote_addr!\n'; }}上述指令块只有一个 stream 块,监听了 3000 端口。对于 tcp 连接,可以使用 proxy_pass 转发 tcp/udp 协议。也可以直接使用 return 指令返回,这里只是简单返回相应字符串。测试结果在 Windows 下,打开命令窗口,然后输入telnet 180.76.152.113 3000 命令,正常应该会有相应的字符串响应。如果出现下面的错误,需要在Window 中打开 telnet 客户端,具体操作见下图。解决找不到 telnet 命令方法 1在这里选择勾上 Telnet 客户端即可。最后 telent 命令返回结果:

1. 前言

TCP 和 UDP 协议是计算机网络的重要组成协议,两者经常被拿来比较,其中 TCP 协议往往会被面试官深入考察。本节课程将和大家一起学习传输层的 TCP 和 UDP 协议。通过本节课程,你会了解到 TCP 和 UDP 协议的区别,重点是要掌握 TCP 协议的三次握手过程以及三次握手的必要性。

3. Java DatagramSocket 分析

Java 语言抽象了 java.net.DatagramSocket 类,表示一个 UDP Socket,既可以用在客户端,又可以用在服务器端。java.net.DatagramSocket 是一个包装类,对外抽象了一组方法,具体实现是在 java.net.DatagramSocketImpl 类中完成的,它允许用户自定义具体实现。java.net.DatagramSocket 类包含的主要功能如下:创建 UDP Socket,具体就是创建一个 java.net.DatagramSocket 类的对象。将 Socket 绑定到本地接口 IP 地址或者端口,可以调用 java.net.DatagramSocket 类的构造方法或 bind 方法完成。将客户端 UDP Socket 和远端 Socket 做绑定,可以通过 java.net.DatagramSocket 类的 connect 方法完成。提示:UDP 客户端调用 connect 方法,仅仅是将本地 Socket 和远端 Socket 做绑定,并不会有类似 TCP 三次握手的过程。关闭连接,可以调用 java.net.DatagramSocket 类的 close 方法完成。接收数据,可以通过 java.net.DatagramSocket 类的 receive 方法实现数据接收。发送数据,可以通过 java.net.DatagramSocket 类的 send 方法实现数据发送。java.net.Socket 类提供了一组重载的构造方法,方便程序员选择,大体分为四类:无参public DatagramSocket() throws SocketException绑定到任意可用的端口和通配符 IP 地址,比如 IPv4 的 0.0.0.0。一般用作 UDP 客户端 Socket 的创建。传入 port 参数public DatagramSocket(int port) throws SocketException绑定到由 port 指定的端口和通配符 IP 地址,比如 IPv4 的 0.0.0.0。一般用作 UDP 服务端 Socket 的创建。传入指定的 IP 和 Port 参数public DatagramSocket(SocketAddress bindaddr) throws SocketExceptionpublic DatagramSocket(int port, InetAddress laddr) throws SocketException绑定到指定的端口和指定的网络接口。如果你的主机有多个网卡,并且你指向在某个指定的网卡上收发数据,可以用此构造方法。既可以用作 UDP 客户端 Socket,也可以用作 UDP 服务端 Socket。

2. 连接方式

我们知道 TCP 数据发送前要建立连接,UDP 不需要,而 Socket 的连接又有如下区分:

3.3 实现

#!/bin/bash# Description: service check# Auth: kaliarch# Email: kaliarch@163.com# function: sys check# Date: 2020-04-11 14:00# Version: 1.0[ $(id -u) -gt 0 ] && echo "请用root用户执行此脚本!" && exit 1sysversion=$(rpm -q centos-release|cut -d- -f3)line="-------------------------------------------------"[ -d logs ] || mkdir logsservice_check_file="logs/service-`date +%Y%m%d`.txt"# 获取服务信息function get_service_info() { port_listen=$(netstat -lntup|grep -v "Active Internet") kernel_config=$(sysctl -p 2>/dev/null) if [ ${sysversion} -gt 6 ];then service_config=$(systemctl list-unit-files --type=service --state=enabled|grep "enabled") run_service=$(systemctl list-units --type=service --state=running |grep ".service") else service_config=$(/sbin/chkconfig | grep -E ":on|:启用" |column -t) run_service=$(/sbin/service --status-all|grep -E "running") ficat <<EOF服务启动配置:${service_config}${line}运行的服务:${run_service}${line}监听端口:${port_listen}${line}内核参考配置:${kernel_config}EOF}function sys_check() { get_service_info echo ${line}}# 执行主函数将输出重定向到文件中sys_check > ${sys_check_file}# 执行测试[root@xuel-terraform-cvm-0 ~]# bash sys_check.sh[root@xuel-terraform-cvm-0 ~]# cat logs/10.0.1.15-20200329.txt[root@master grep]# cat logs/service-20200411.txt 服务启动配置:auditd.service enabledautovt@.service enabledceph-mon@.service enabledceph-osd@.service enabledchronyd.service enabledcrond.service enableddbus-org.freedesktop.NetworkManager.service enableddbus-org.freedesktop.nm-dispatcher.service enableddocker.service enabledetcd.service enabledgapd.service enabledgetty@.service enabledirqbalance.service enabledkdump.service enabledkubelet.service enabledmicrocode.service enabledNetworkManager-dispatcher.service enabledNetworkManager.service enabledpostfix.service enabledrpcbind.service enabledrsyslog.service enabledsmarteye-server-agent.service enabledsshd.service enabledsystemd-readahead-collect.service enabledsystemd-readahead-drop.service enabledsystemd-readahead-replay.service enabledtuned.service enabled-------------------------------------------------运行的服务:auditd.service loaded active running Security Auditing Serviceceph-mon@master.service loaded active running Ceph cluster monitor daemonceph-osd@0.service loaded active running Ceph object storage daemonchronyd.service loaded active running NTP client/servercrond.service loaded active running Command Schedulerdbus.service loaded active running D-Bus System Message Busdocker.service loaded active running Docker Application Container Engineetcd.service loaded active running etcd docker wrappergapd.service loaded active running guest agent for pitrixgetty@tty1.service loaded active running Getty on tty1gssproxy.service loaded active running GSSAPI Proxy Daemonirqbalance.service loaded active running irqbalance daemonkubelet.service loaded active running Kubernetes Kubelet ServerNetworkManager.service loaded active running Network Managerpolkit.service loaded active running Authorization Managerpostfix.service loaded active running Postfix Mail Transport Agentrpcbind.service loaded active running RPC bind servicersyslog.service loaded active running System Logging Servicesmarteye-server-agent.service loaded active running The Smarteye Monitoring of serversshd.service loaded active running OpenSSH server daemonsystemd-journald.service loaded active running Journal Servicesystemd-logind.service loaded active running Login Servicesystemd-udevd.service loaded active running udev Kernel Device Managertuned.service loaded active running Dynamic System Tuning Daemon-------------------------------------------------监听端口:Proto Recv-Q Send-Q Local Address Foreign Address State PID/Program name tcp 0 0 127.0.0.1:9099 0.0.0.0:* LISTEN 10444/calico-node tcp 0 0 172.16.60.2:2379 0.0.0.0:* LISTEN 1321/etcd tcp6 0 0 :::9353 :::* LISTEN 2058/node-cache udp 0 0 0.0.0.0:37811 0.0.0.0:* 610/dhclient udp 0 0 169.254.25.10:53 0.0.0.0:* 2058/node-cache udp 0 0 0.0.0.0:68 0.0.0.0:* 610/dhclient udp 0 0 0.0.0.0:111 0.0.0.0:* 1/systemd udp 0 0 0.0.0.0:123 0.0.0.0:* 530/chronyd udp 0 0 127.0.0.1:323 0.0.0.0:* 530/chronyd udp 0 0 0.0.0.0:703 0.0.0.0:* 535/rpcbind udp6 0 0 :::35267 :::* 610/dhclient udp6 0 0 :::111 :::* 1/systemd udp6 0 0 ::1:323 :::* 530/chronyd udp6 0 0 :::703 :::* 535/rpcbind -------------------------------------------------内核参考配置:net.ipv4.ip_forward = 1net.bridge.bridge-nf-call-ip6tables = 1net.bridge.bridge-nf-call-iptables = 1net.ipv4.ip_local_reserved_ports = 30000-32767net.bridge.bridge-nf-call-arptables = 1-------------------------------------------------可以看到利用了一个函数来获取系统的信息,主函数将输出利用重定向方式保存到文件中。

Nginx 配置初步(上)

本节的目标是了解 Nginx 的基本配置。关于 Nginx 的配置,主要是以下 5 个方面:初始配置基本语法http 服务配置tcp/udp反向代理每个部分其实有比较多的扩展内容,今天我们会讲解初始配置以及配置文件的基本语法,后续的 http 服务配置、tcp/udp 配置和反向代理配置会在下一节中介绍。

3. Channel 实现类

在 Channel 的类的层次结构图中,我们画出四个常用的实现类如下:FileChannel文件 Channel 类是对磁盘文件的抽象,可以读写磁盘文件数据。需要通过 FileInputStream 的 getChannel 方法创建 FileChannel 的对象,你不可以直接创建 FileChannel 的对象。FileChannel 对象的创建方法如下:FileInputStream inFile = new FileInputStream("D:\\fileChannelTest.txt");ReadableByteChannel fileChannel = inFile.getChannel(); DatagramChannel数据报 Channel 是用于抽象 UDP Socket,可以将 UDP 数据的读写集成到 Selector 机制中。DatagramChannel 对象的创建方法:DatagramChannel ch = DatagramChannel.open(); SocketChannel 是对 TCP 的抽象,用于读写 TCP 数据,用于 TCP 客户端和服务器端ServerSocketChannel 是对 TCP 监听 Socket 的抽象,用于 TCP 服务器的创建。

1. 传输层协议

传输层有 TCP/UDP 两种连接方式,所以对应的 Socket 也有两种不同实现方式,掌握 Socket 的前提是了解清楚这两种协议。

4.4 SO_RCVBUF

SO_RCVBUF 很好理解,用于设置 Socket 的接收缓冲区大小。TCP 一般不需要设置,UDP 可能需要设置。java.net.Socket 类提供了 setReceiveBufferSize 方法可以设置接收缓冲区的大小。sock.setReceiveBufferSize(16384);

Nginx 的反向代理

Nginx 最强大的地方是在于其 HTTP 请求的反向代理,也即常说的七层反向代理。在这一层代理中,通过 Nginx 框架提供的相关配置,我们能在该层将发送过来的 http 协议转换成各种其他的协议比如 fastcgi 协议、uwsgi协议、grpc、http(高版本协议)、websocket协议等。这样使用 Nginx 框架,我们可以支持多种应用服务(java web、python web等)的反向代理。Nginx 从1.9.0开始,新增加了一个 stream 模块,用来实现四层协议( TCP 或 UDP 协议)的转发、代理或者负载均衡。这层比较简单,只是单纯将 TCP 或 UDP 层的流量转发到上游服务器中。接下来,我们将分别介绍这两种反向代理的基本用法。

6. 小结

用 Java 语言编写 UDP 客户端和服务器程序非常简单,你只需要创建一个 java.net.DatagramSocket 实例。如果你构造的是服务器 Socket,需要传入监听的端口号,监听的接口 IP 是可选的,默认是监听通配符 IP。如果你创建的是客户端 Socket,你可以传入绑定的本地 Port 和接口地址,也可以不传入任何参数。对于客户端 UDP Socket 来说,你也可以调用 connect 方法,只是和远端 Socket 绑定,没有类似 TCP 的三次握手过程。示例代码我们采用的是 try-with-resources 写法,对于 Java 7 以后的版本,可以不显式调用 close 方法。如果是非此写法,需要显式调用 close 方法。

3.4 传输层

定义了数据传输的协议和端口,比如是选择可靠的 TCP 还是不可靠的 UDP。在它上层的会话层是不关心它选择什么协议的,只要传输层能够提供传输的服务就行。传输层对于会话层来说是透明的。

4. 小结

本节首先介绍了 java.net.DatagramPacket 类的基本功能,这是 Java UDP Socket 程序进行数据读写的基础类。在调用 receive 方法接收数据之前,首先要创建 DatagramPacket 的实例,同时要为他提供一个介绍数据的字节数组。当 receive 方法成功返回后,你可以调用 DatagramPacket 的 getSocketAddress 方法获取发送主机的源 IP 地址和端口号。在调用 send 方法发送数据之前,首先要创建 DatagramPacket 的实例,将要发送的数据传给他,同时要将接收数据的目标主机的 IP 地址和端口号设置给它。接着我们重点介绍了 UDP 编程中常见的协议格式定义、解析方法,主要是通过 java.io.ByteArrayInputStream 和 java.io.ByteArrayOutputStream 类,以及 java.io.DataInputStream 和 java.io.DataOutputStream 类实现消息的序列化、反序列化功能。我们提供了完整的实现代码,已经序列化、反序列化的具体用法。可以说这一部分内容在实践中经常会遇到,需要好好掌握。

1. 前言

我们知道计算机网络就是将各种设备通过有线或无线连接在一起,这些设备有终端设备,比如 PC、手机、打印机等;还有各种网络核心设备,比如路由器、交换机、网关等。通常把网络设备叫做节点,这些节点都工作在计算机网络的 TCP/IP 参考模型之上。链路层实现节点之间的数据转发。比如以太网协议,包含独立的以太网帧头,帧头中包含了源 MAC 地址、目标 MAC 地址,通过 MAC 地址实现节点之间的数据帧转发。网络层也叫 Internet 协议层,主要职责就是提供端到端的网络传输,比如主机到主机的通信。网络层最重要的一个设备就是路由器,路由器的主要职责是提供路由选择和转发,将分组从源主机转发到目的主机。每台主机和路由器的每个端口都配有 IP 地址,路由器是通过 IP 地址实现分组转发的。分组在路由器之间的转发是一个逐跳转发的过程。网络层不保证分组传输的可靠性。传输层包含两个非常重要的协议:TCP 和 UDP。TCP 是可靠传输协议,面向连接的,可以保证数据段(Segment)顺序。UDP 是不可靠传输协议,无连接的,不保证数据报(Datagram)的顺序。一台主机可以同时运行多个 TCP 或 UDP 应用程序,不同应用程序之间是通过端口号(Port)来识别。

3. 小结

本章节给大家介绍了 TCP 和 UDP 协议的报文格式以及区别,分析了 TCP 建立连接的握手过程,需要大家能够准确画出 TCP 握手每个过程的标志位以及序号、确认号,并且从原理上理解三次握手的必要性,下一章节会继续给大家分析 TCP 四次挥手过程。

2.5 套接字

上述介绍的 IPC 方式都是同一个主机内进程的交互方式,都是本地通信,套接字(Socket)一般用来处理不同主机进程之间的通信,也就是远程通信,是网络通信最常用的方式。Socket 通信需要 TCP 或者 UDP 协议的支持。使用 C 语言创建 Socket 的示例:#include <sys/types.h> #include <sys/socket.h> //引入头文件int socket(int domain, int type, int protocol); //创建一个socket

6. 小结

本节学习了一个底层的网络接口——Socket,它内部实现了计算机网络中最基础的协议和模型,可以让我们不再关心那些繁琐复杂的协议规则,从而轻松的将数据传输出去。首先给大家回顾了 IOS 和 TCP / IP 的几层模型,然后工作在传输层的两个重要通信协议 TCP / UDP,接着按照步骤来分别创建 SocketServer 和 Socket,通过 InputStream 和 OutputStream 进行通信。

1. 前言

前面章节介绍了 Java TCP、UDP Socket 编程方法,按照文中介绍的方法去编写 Socket 程序,是完全可以正常工作的。其实,TCP/IP 协议栈允许你对 Socket 做一些定制,比如设置 Socket 的接收、发送缓冲区的大小,这就是常说的 Socket 选项。本文首先会以 Linux 系统为例,介绍操作系统 Socket 选项的基本概念,然后再介绍 Java 中如何去设置 Socket 选项。

首页上一页12下一页尾页
直播
查看课程详情
微信客服

购课补贴
联系客服咨询优惠详情

帮助反馈 APP下载

慕课网APP
您的移动学习伙伴

公众号

扫描二维码
关注慕课网微信公众号