网络编程
计算机网络基础知识
网络层次划分
为了使不同计算机厂家生产的计算机能够相互通信,以便在更大的范围内建立计算机网络,国际标准化组织(ISO)在1978年提出了"开放系统互联参考模型",即著名的OSI/RM模型(Open System Interconnection/Reference Model)。它将计算机网络体系结构的通信协议划分为七层,自下而上依次为:物理层(Physics Layer)、数据链路层(Data Link Layer)、网络层(Network Layer)、传输层(Transport Layer)、会话层(Session Layer)、表示层(Presentation Layer)、应用层(Application Layer)。其中第四层完成数据传送服务,上面三层面向用户。
除了标准的OSI七层模型以外,常见的网络层次划分还有TCP/IP四层协议它们之间的对应关系如下图所示:
OSI七层网络模型
TCP/IP协议毫无疑问是互联网的基础协议,没有它就根本不可能上网,任何和互联网有关的操作都离不开TCP/IP协议。不管是OSI七层模型还是TCP/IP的四层、五层模型,每一层中都要自己的专属协议,完成自己相应的工作以及与上下层级之间进行沟通。由于OSI七层模型为网络的标准层次划分,所以我们以OSI七层模型为例从下向上进行一一介绍。
TCP/IP 协议族是一个四层协议系统,自底而上分别是数据链路层、网络层、传输层、应用层。每层完成不同的功能,且通过若干协议来实现,上层协议使用下层协议提供的服务。
- 物理层(Physical Layer)
激活、维持、关闭通信端点之间的机械特性、电气特性、功能特性以及过程特性。**该层为上层协议提供了一个传输数据的可靠的物理媒体。简单的说,物理层确保原始的数据可在各种物理媒体上传输。**物理层记住两个重要的设备名称,中继器(Repeater,也叫放大器)和集线器。
- 数据链路层(Data Link Layer)
数据链路层在物理层提供的服务的基础上向网络层提供服务,其最基本的服务是将源自网络层来的数据可靠地传输到相邻节点的目标机网络层。为达到这一目的,数据链路必须具备一系列相应的功能,主要有:如何将数据组合成数据块,在数据链路层中称这种数据块为帧(frame),帧是数据链路层的传送单位;如何控制帧在物理信道上的传输,包括如何处理传输差错,如何调节发送速率以使与接收方相匹配;以及在两个网络实体之间提供数据链路通路的建立、维持和释放的管理。数据链路层在不可靠的物理介质上提供可靠的传输。该层的作用包括:物理地址寻址、数据的成帧、流量控制、数据的检错、重发等。
有关数据链路层的重要知识点:
- 数据链路层为网络层提供可靠的数据传输;
- 基本数据单位为帧;
- 主要的协议:以太网协议;
- 两个重要设备名称:网桥和交换机。
- 网络层(Network Layer)
网络层的目的是实现两个端系统之间的数据透明传送,具体功能包括寻址和路由选择、连接的建立、保持和终止等。它提供的服务使传输层不需要了解网络中的数据传输和交换技术。如果您想用尽量少的词来记住网络层,那就是"路径选择、路由及逻辑寻址"。
网络层中涉及众多的协议,其中包括最重要的协议,也是TCP/IP的核心协议——IP协议。IP协议非常简单,仅仅提供不可靠、无连接的传送服务。IP协议的主要功能有:无连接数据报传输、数据报路由选择和差错控制。与IP协议配套使用实现其功能的还有地址解析协议ARP、逆地址解析协议RARP、因特网报文协议ICMP、因特网组管理协议IGMP。具体的协议我们会在接下来的部分进行总结,有关网络层的重点为:
-
网络层负责对子网间的数据包进行路由选择。此外,网络层还可以实现拥塞控制、网际互连等功能;
-
基本数据单位为IP数据报;
-
包含的主要协议:
-
IP协议(Internet Protocol,因特网互联协议);
-
ICMP协议(Internet Control Message Protocol,因特网控制报文协议);
-
ARP协议(Address Resolution Protocol,地址解析协议);
-
RARP协议(Reverse Address Resolution Protocol,逆地址解析协议)。
-
-
重要的设备:路由器;
- 传输层(Transport Layer)
第一个端到端,即主机到主机的层次。传输层负责将上层数据分段并提供端到端的、可靠的或不可靠的传输。此外,传输层还要处理端到端的差错控制和流量控制问题。 传输层的任务是根据通信子网的特性,最佳的利用网络资源,为两个端系统的会话层之间,提供建立、维护和取消传输连接的功能,负责端到端的可靠数据传输。在这一层,信息传送的协议数据单元称为段或报文。 网络层只是根据网络地址将源结点发出的数据包传送到目的结点,而传输层则负责将数据可靠地传送到相应的端口。 有关网络层的重点:
- 传输层负责将上层数据分段并提供端到端的、可靠的或不可靠的传输以及端到端的差错控制和流量控制问题;
- 包含的主要协议:TCP协议(Transmission Control Protocol,传输控制协议)、UDP协议(User Datagram Protocol,用户数据报协议);
- 重要设备:网关。
- 会话层
会话层管理主机之间的会话进程,即负责建立、管理、终止进程之间的会话。会话层还利用在数据中插入校验点来实现数据的同步。
- 表示层
表示层对上层数据或信息进行变换以保证一个主机应用层信息可以被另一个主机的应用程序理解。表示层的数据转换包括数据的加密、压缩、格式转换等。
- 应用层
为操作系统或网络应用程序提供访问网络服务的接口。
会话层、表示层和应用层重点:
- 数据传输基本单位为报文;
- 包含的主要协议:FTP(文件传送协议)、Telnet(远程登录协议)、DNS(域名解析协议)、SMTP(邮件传送协议),POP3协议(邮局协议),HTTP协议(Hyper Text Transfer Protocol)。
IP地址
-
网络地址
IP地址由网络号(包括子网号)和主机号组成,网络地址的主机号为全0,网络地址代表着整个网络。
-
广播地址
广播地址通常称为直接广播地址,是为了区分受限广播地址。
广播地址与网络地址的主机号正好相反,广播地址中,主机号为全1。当向某个网络的广播地址发送消息时,该网络内的所有主机都能收到该广播消息。
-
组播地址
D类地址就是组播地址。
先回忆下A,B,C,D类地址吧:
A类地址以0开头,第一个字节作为网络号,地址范围为:0.0.0.0~127.255.255.255;(modified @2023.8.15)
B类地址以10开头,前两个字节作为网络号,地址范围是:128.0.0.0~191.255.255.255;
C类地址以110开头,前三个字节作为网络号,地址范围是:192.0.0.0~223.255.255.255。
D类地址以1110开头,地址范围是224.0.0.0~239.255.255.255,D类地址作为组播地址(一对多的通信);
E类地址以1111开头,地址范围是240.0.0.0~255.255.255.255,E类地址为保留地址,供以后使用。
注:只有A,B,C有网络号和主机号之分,D类地址和E类地址没有划分网络号和主机号。
-
255.255.255.255
该IP地址指的是受限的广播地址。受限广播地址与一般广播地址(直接广播地址)的区别在于,受限广播地址只能用于本地网络,路由器不会转发以受限广播地址为目的地址的分组;一般广播地址既可在本地广播,也可跨网段广播。例如:主机192.168.1.1/30上的直接广播数据包后,另外一个网段192.168.1.5/30也能收到该数据报;若发送受限广播数据报,则不能收到。
注:一般的广播地址(直接广播地址)能够通过某些路由器(当然不是所有的路由器),而受限的广播地址不能通过路由器。
-
0.0.0.0
常用于寻找自己的IP地址,例如在我们的RARP,BOOTP和DHCP协议中,若某个未知IP地址的无盘机想要知道自己的IP地址,它就以255.255.255.255为目的地址,向本地范围(具体而言是被各个路由器屏蔽的范围内)的服务器发送IP请求分组。
-
回环地址
127.0.0.0/8被用作回环地址,回环地址表示本机的地址,常用于对本机的测试,用的最多的是127.0.0.1。
-
A、B、C类私有地址
私有地址(private address)也叫专用地址,它们不会在全球使用,只具有本地意义。
A类私有地址:10.0.0.0/8,范围是:10.0.0.0~10.255.255.255
B类私有地址:172.16.0.0/12,范围是:172.16.0.0~172.31.255.255
C类私有地址:192.168.0.0/16,范围是:192.168.0.0~192.168.255.255
子网掩码及网络划分
子网掩码是标志两个IP地址是否同属于一个子网的,也是32位二进制地址,其每一个为1代表该位是网络位,为0代表主机位。它和IP地址一样也是使用点式十进制来表示的。如果两个IP地址在子网掩码的按位与的计算下所得结果相同,即表明它们共属于同一子网中。
在计算子网掩码时,我们要注意IP地址中的保留地址,即" 0"地址和广播地址,它们是指主机地址或网络地址全为" 0"或" 1"时的IP地址,它们代表着本网络地址和广播地址,一般是不能被计算在内的。
ARP/RARP协议
地址解析协议,即ARP(Address Resolution Protocol),是根据IP地址获取物理地址的一个TCP/IP协议。
逆地址解析协议,即RARP,功能和ARP协议相对,其将局域网中某个主机的物理地址转换为IP地址。
路由选择协议
常见的路由选择协议有:RIP协议、OSPF协议。
RIP协议 :底层是贝尔曼福特算法,它选择路由的度量标准(metric)是跳数,最大跳数是15跳,如果大于15跳,它就会丢弃数据包。
OSPF协议 :Open Shortest Path First开放式最短路径优先,底层是迪杰斯特拉算法,是链路状态路由选择协议,它选择路由的度量标准是带宽,延迟。
TCP/IP协议
TCP/IP协议是Internet最基本的协议、Internet国际互联网络的基础,由网络层的IP协议和传输层的TCP协议组成。通俗而言:TCP负责发现传输的问题,一有问题就发出信号,要求重新传输,直到所有数据安全正确地传输到目的地。而IP是给因特网的每一台联网设备规定一个地址。
IP层接收由更低层(网络接口层例如以太网设备驱动程序)发来的数据包,并把该数据包发送到更高层—TCP或UDP层;相反,IP层也把从TCP或UDP层接收来的数据包传送到更低层。IP数据包是不可靠的,因为IP并没有做任何事情来确认数据包是否按顺序发送的或者有没有被破坏,IP数据包中含有发送它的主机的地址(源地址)和接收它的主机的地址(目的地址)。
TCP是面向连接的通信协议,通过三次握手建立连接,通讯完成时要拆除连接,由于TCP是面向连接的所以只能用于端到端的通讯。TCP提供的是一种可靠的数据流服务,采用"带重传的肯定确认"技术来实现传输的可靠性。TCP还采用一种称为"滑动窗口"的方式进行流量控制,所谓窗口实际表示接收能力,用以限制发送方的发送速度。
TCP报文首部格式:
TCP协议的三次握手和四次挥手:
seq:
sequance
序列号;ACK:
acknowledge
确认号;TCP报文段首部中的“ACK字段”,置1时该报文段为确认报文段。ack:
acknowledge
;TCP报文段首部中“确认号字段”的具体数值。ack=x+1说明B希望A下次发来的报文段的第一个数据字节为序号=x+1的字节;ack=y+1说明A希望B下次发来的报文段的第一个数据字节为序号=y+1的字节。SYN:
synchronize
"请求同步标志;FIN:
Finally
结束标志。
TCP连接建立过程:
-
首先Client端发送连接请求报文;
-
Server段接受连接后回复ACK报文,并为这次连接分配资源。
-
Client端接收到ACK报文后也向Server段发生ACK报文,并分配资源,这样TCP连接就建立了。
TCP连接断开过程:
-
假设Client端发起中断连接请求,也就是发送FIN报文。
-
Server端接到FIN报文后,意思是说"我Client端没有数据要发给你了",但是如果你还有数据没有发送完成,则不必急着关闭Socket,可以继续发送数据。所以你先发送ACK,“告诉Client端,你的请求我收到了,但是我还没准备好,请继续你等我的消息”。
-
这个时候Client端就进入FIN_WAIT状态,继续等待Server端的FIN报文。当Server端确定数据已发送完成,则向Client端发送FIN报文,“告诉Client端,好了,我这边数据发完了,准备好关闭连接了”。
-
Client端收到FIN报文后,就知道可以关闭连接了,但是他还是不相信网络,怕Server端不知道要关闭,所以发送ACK后进入TIME_WAIT状态,如果Server端没有收到ACK则可以重传。Server端收到ACK后,就知道可以断开连接了。
Client端等待了2MSL后依然没有收到回复,则证明Server端已正常关闭,那好,我Client端也可以关闭连接了。TCP连接就这样关闭了!
TTL:(Time To Live ) 生存时间,指定数据包被路由器丢弃之前允许通过的网段数量。
MSL是Maximum Segment Lifetime英文的缩写,中文可以译为“报文最大生存时间”,他是任何报文在网络上存在的最长时间,超过这个时间报文将被丢弃。
TTL与MSL是有关系的但不是简单的相等的关系,MSL要大于等于TTL。
为什么客户端要等待2MSL?
主要原因是为了保证客户端发送那个的第一个ACK报文能到到服务器,因为这个ACK报文可能丢失,并且2MSL是任何报文在网络上存在的最长时间,超过这个时间报文将被丢弃,这样新的连接中不会出现旧连接的请求报文。
为什么要三次握手?
在只有两次"握手"的情形下,假设Client想跟Server建立连接,但是却因为中途连接请求的数据报丢失了,故Client端不得不重新发送一遍;这个时候Server端仅收到一个连接请求,因此可以正常的建立连接。但是,有时候Client端重新发送请求不是因为数据报丢失了,而是有可能数据传输过程因为网络并发量很大在某结点被阻塞了,这种情形下Server端将先后收到2次请求,并持续等待两个Client请求向他发送数据…
问题就在这里,Client端实际上只有一次请求,而Server端却有2个响应,极端的情况可能由于Client端多次重新发送请求数据而导致Server端最后建立了N多个响应在等待,因而造成极大的资源浪费!所以,"三次握手"很有必要!
为什么要四次挥手?
试想一下,假如现在你是客户端你想断开跟Server的所有连接该怎么做?
第一步,你自己先停止向Server端发送数据,并等待Server的回复。但事情还没有完,虽然你自身不往Server发送数据了,但是因为你们之前已经建立好平等的连接了,所以此时他也有主动权向你发送数据;故Server端还得终止主动向你发送数据,并等待你的确认。其实,说白了就是保证双方的一个合约的完整执行!
使用TCP的协议:FTP(文件传输协议)、Telnet(远程登录协议)、SMTP(简单邮件传输协议)、POP3(和SMTP相对,用于接收邮件)、HTTP协议等。
UDP协议
UDP用户数据报协议,是面向无连接的通讯协议,UDP数据包括目的端口号和源端口号信息,由于通讯不需要连接,所以可以实现广播发送。
UDP通讯时不需要接收方确认,属于不可靠的传输,可能会出现丢包现象,实际应用中要求程序员编程验证。
UDP与TCP位于同一层,但它不管数据包的顺序、错误或重发。因此,UDP不被应用于那些使用虚电路的面向连接的服务,UDP主要用于那些面向查询—应答的服务,例如NFS。相对于FTP或Telnet,这些服务需要交换的信息量较小。
每个UDP报文分UDP报头和UDP数据区两部分。报头由四个16位长(2字节)字段组成,分别说明该报文的源端口、目的端口、报文长度以及校验值。UDP报头由4个域组成,其中每个域各占用2个字节,具体如下:
- 源端口号;
- 目标端口号;
- 数据报长度;
- 校验值。
使用UDP协议包括:TFTP(简单文件传输协议)、SNMP(简单网络管理协议)、DNS(域名解析协议)、NFS、BOOTP。
TCP 与 UDP **的区别:**TCP是面向连接的,可靠的字节流服务;
UDP是面向无连接的,不可靠的数据报服务。
HTTP协议
超文本传输协议(HTTP,HyperText Transfer Protocol)是互联网上应用最为广泛的一种网络协议。所有的WWW文件都必须遵守这个标准。
HTTP 协议的请求
GET:请求读取由URL所标志的信息。
POST:给服务器添加信息。
PUT:在给定的URL下存储一个文档。
DELETE:删除给定的URL所标志的资源。
HTTP 中, POST 与 GET 的区别
-
Get是从服务器上获取数据,Post是向服务器传送数据。
-
Get是把参数数据队列加到提交表单的Action属性所指向的URL中,值和表单内各个字段一一对应,在URL中可以看到。
-
Get传送的数据量小,不能大于2KB;Post传送的数据量较大,一般被默认为不受限制。
-
根据HTTP规范,GET用于信息获取,而且应该是安全的和幂等的。
-
所谓 安全的 意味着该操作用于获取信息而非修改信息。换句话说,GET请求一般不应产生副作用。就是说,它仅仅是获取资源信息,就像数据库查询一样,不会修改,增加数据,不会影响资源的状态。
-
幂等 的意味着对同一URL的多个请求应该返回同样的结果。
-
序号 | 方法 | 描述 |
---|---|---|
1 | GET | 请求指定的页面信息,并返回实体主体。 |
2 | HEAD | 类似于 GET 请求,只不过返回的响应中没有具体的内容,用于获取报头 |
3 | POST | 向指定资源提交数据进行处理请求(例如提交表单或者上传文件)。数据被包含在请求体中。POST 请求可能会导致新的资源的建立和/或已有资源的修改。 |
4 | PUT | 从客户端向服务器传送的数据取代指定的文档的内容。 |
5 | DELETE | 请求服务器删除指定的页面。 |
6 | CONNECT | HTTP/1.1 协议中预留给能够将连接改为管道方式的代理服务器。 |
7 | OPTIONS | 允许客户端查看服务器的性能。 |
8 | TRACE | 回显服务器收到的请求,主要用于测试或诊断。 |
9 | PATCH | 是对 PUT 方法的补充,用来对已知资源进行局部更新 。 |
TCP网络编程
Socket
套接字(socket)是一个抽象层,应用程序可以通过它发送或接收数据,可对其进行像对文件一样的打开、读写和关闭等操作。套接字允许应用程序将I/O插入到网络中,并与网络中的其他应用程序进行通信。网络套接字是IP地址与端口的组合。
Socket分类:
- 流套接字(stream socket):使用TCP提供可依赖的字节流服务
- 数据报套接字(datagram socket):使用UDP提供“尽力而为”的数据报服务
构造方法
构造器 | 描述 |
---|---|
Socket() | 创建一个未连接的套接字,系统默认类型为SocketImpl。 |
Socket(String host, int port) | 创建流套接字并将其连接到指定主机上的指定端口号。 |
Socket(String host, int port, InetAddress localAddr, int localPort) | 创建套接字并将其连接到指定远程端口上的指定远程主机。 |
Socket(InetAddress address, int port, InetAddress localAddr, int localPort) | 创建套接字并将其连接到指定远程端口上的指定远程地址。 |
方法摘要
变量和类型 | 方法 | 描述 |
---|---|---|
void | bind(SocketAddress bindpoint) | 将套接字绑定到本地地址。 |
void | close() | 关闭此套接字。 |
void | connect(SocketAddress endpoint) | 将此套接字连接到服务器。 |
void | connect(SocketAddress endpoint, int timeout) | 使用指定的超时值将此套接字连接到服务器。 |
InetAddress | getInetAddress() | 返回套接字连接的地址。 |
InetAddress | getLocalAddress() | 获取套接字绑定的本地地址。 |
InputStream | getInputStream() | 返回此套接字的输入流。 |
OutputStream | getOutputStream() | 返回此套接字的输出流。 |
void | shutdownInput() | 将此套接字的输入流放在“流结束”。 |
void | shutdownOutput() | 禁用此套接字的输出流。 |
基于Socket的TCP编程
通信模型
建立Socket连接
首先,服务端初始化ServerSocket,然后对指定的端口进行绑定,接着对端口及进行监听,通过调用accept方法阻塞,此时,如果客户端有一个socket连接到服务端,那么服务端通过监听和accept方法可以与客户端进行连接。
try-with-resources
在try语句之后在括号中打开的资源仅在此处和现在需要。
.close()
在try块中完成工作后,我将立即调用它们的方法。如果在try块中抛出异常,无论如何我都会关闭这些资源。注意:它们以相反的声明顺序关闭,这意味着,在我们的示例中,
scanner
它将在之前关闭writer
Server端示例
public class ServerSocketTest {
public static void main(String[] args) {
BufferedWriter writer = null;
try (ServerSocket server = new ServerSocket(8989)){
System.out.println("Server: 等待Client端连接。。。。。");
Socket socket = server.accept();
System.out.println("Server: 连接建立成功!");
writer = new BufferedWriter(new OutputStreamWriter(socket.getOutputStream()));
writer.write("你好,Client。这里是Server!");
writer.flush();
} catch (IOException e) {
throw new RuntimeException(e);
}finally {
try {
writer.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
Client端示例
public class ClientSocketTest {
public static void main(String[] args) {
String host = "localhost";
int port = 8989;
BufferedReader reader = null;
System.out.println("Client: 请求建立连接。。。");
try (Socket socket = new Socket(host,port)){
System.out.println("Client: 连接建立成功!");
reader = new BufferedReader(new InputStreamReader(socket.getInputStream()));
System.out.println(reader.readLine());
} catch (IOException e) {
throw new RuntimeException(e);
}finally {
try {
reader.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
图片传输测试
Client端(本机)
public class ClientSocketTest {
public static void main(String[] args) {
String host = "192.168.56.71";
int port = 8989;
DataInputStream in = null;
DataOutputStream out = null;
File filePath = new File("tmp");
File file = new File(filePath, "white.png");
System.out.println("Client: 请求建立连接。。。");
try (Socket socket = new Socket(host,port)){
System.out.println("Client: 连接建立成功!");
in = new DataInputStream(new FileInputStream(file));
out = new DataOutputStream(socket.getOutputStream());
System.out.println("开始传输文件。。。");
int l = -1;
byte[] bytes = new byte[1024];
while ((l = in.read(bytes)) != -1){
out.write(bytes,0,l);
}
out.flush();
socket.shutdownOutput();
System.out.println("传输结束。。。");
} catch (IOException e) {
throw new RuntimeException(e);
}finally {
try {
in.close();
} catch (IOException e) {
e.printStackTrace();
}
try {
out.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
Server端
public class ServerSocketTest {
public static void main(String[] args) {
DataInputStream in = null;
DataOutputStream out = null;
File filePath = new File("/root");
File file = new File(filePath,"white.png");
System.out.println(file.getPath());
try (ServerSocket server = new ServerSocket(8989)){
System.out.println("Server: 等待Client端连接。。。。。");
Socket socket = server.accept();
System.out.println("Server: 连接建立成功!");
in = new DataInputStream(socket.getInputStream());
out = new DataOutputStream(new FileOutputStream(file));
System.out.println("开始接收文件。。。");
int l = -1;
byte[] bytes = new byte[1024];
while ((l = in.read(bytes)) != -1){
out.write(bytes,0,l);
}
out.flush();
socket.shutdownOutput();
System.out.println("传输结束。。。");
} catch (IOException e) {
throw new RuntimeException(e);
}finally {
try {
in.close();
} catch (IOException e) {
e.printStackTrace();
}
try {
out.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
UDP网络编程
- DatagramSocket 和 DatagramPacket 实现了基于 UDP 协议网络程序。
- UDP数据报通过数据报套接字 DatagramSocket 发送和接收, 系统不保证UDP数据报一定能够安全送到目的地,也不能确定什么时候可以抵达。
- DatagramPacket 对象封装了UDP数据报,在数据报中包含了发送端的IP地址和端口号以及接收端的IP地址和端口号。
- UDP协议中每个数据报都给出了完整的地址信息,因此无须建立发送方和接收方的连接。 如同发快递包裹一样。
DatagramSocket构造方法
构造器 | 描述 |
---|---|
DatagramSocket() | 构造一个数据报套接字并将其绑定到本地主机上的任何可用端口。 |
DatagramSocket(int port) | 构造一个数据报套接字并将其绑定到本地主机上的指定端口。 |
DatagramSocket(int port, InetAddress laddr) | 创建绑定到指定本地地址的数据报套接字。 |
DatagramSocket(DatagramSocketImpl impl) | 使用指定的DatagramSocketImpl创建未绑定的数据报套接字。 |
DatagramSocket(SocketAddress bindaddr) | 创建绑定到指定本地套接字地址的数据报套接字。 |
方法摘要
变量和类型 | 方法 | 描述 |
---|---|---|
void | bind(SocketAddress addr) | 将此DatagramSocket绑定到特定的地址和端口。 |
void | close() | 关闭此数据报套接字。 |
void | connect(InetAddress address, int port) | 将套接字连接到此套接字的远程地址。 |
void | connect(SocketAddress addr) | 将此套接字连接到远程套接字地址(IP地址+端口号)。 |
void | disconnect() | 断开插座。 |
InetAddress | getInetAddress() | 返回此套接字连接的地址。 |
InetAddress | getLocalAddress() | 获取套接字绑定的本地地址。 |
void | receive(DatagramPacket p) | 从此套接字接收数据报包。 |
void | send(DatagramPacket p) | 从此套接字发送数据报包。 |
DatagramPacket构造方法
构造器 | 描述 |
---|---|
DatagramPacket(byte[] buf, int length) | 构造 DatagramPacket 用于接收长度为 length 数据包。 |
DatagramPacket(byte[] buf, int offset, int length) | 构造 DatagramPacket 用于接收长度为 length 数据包,指定缓冲区的偏移量。 |
DatagramPacket(byte[] buf, int offset, int length, InetAddress address, int port) | 构造一个数据报包,用于将长度为 length 且偏移量为 ioffset 的数据包发送到指定主机上的指定端口号。 |
DatagramPacket方法
变量和类型 | 方法 | 描述 |
---|---|---|
InetAddress | getAddress() | 返回发送此数据报或从中接收数据报的计算机的IP地址。 |
byte[] | getData() | 返回数据缓冲区。 |
int | getLength() | 返回要发送的数据的长度或接收的数据的长度。 |
int | getOffset() | 返回要发送的数据的偏移量或接收数据的偏移量。 |
int | getPort() | 返回发送此数据报或从中接收数据报的远程主机上的端口号。 |
SocketAddress | getSocketAddress() | 获取此数据包发送到或来自的远程主机的SocketAddress(通常是IP地址+端口号)。 |
UDP网络通讯流程:
- DatagramSocket与DatagramPacket
- 建立发送端,接收端
- 建立数据包
- 调用Socket的发送、 接收方法
- 关闭Socket
Server端示例
public class UDPServerTest {
public static void main(String[] args) throws IOException {
DatagramSocket socket = new DatagramSocket(8999);
while (true){
DatagramPacket packet = new DatagramPacket(new byte[1024],1024);
socket.receive(packet);
System.out.println(packet.getAddress()+"-"+packet.getPort()+"-"+new String(packet.getData(),0, packet.getLength()));
}
}
}
Client端示例(输入Q
退出)
public class UDPCustomTest {
public static void main(String[] args) throws IOException {
DatagramSocket socket = new DatagramSocket();
Scanner sc = new Scanner(System.in);
String l = null;
while ((l = sc.nextLine()) != null){
if (l.equals("Q")){
break;
}
DatagramPacket packet = new DatagramPacket(l.getBytes(),l.getBytes().length, InetAddress.getByName("10.11.5.249"),10086);
socket.send(packet);
}
socket.close();
sc.close();
}
}
URL编程
- URL
- URL(Uniform Resource Locator):统一资源定位符,它表示 Internet 上某一资源的地址。
- 它是一种具体的URI,即URL可以用来标识一个资源,而且还指明了如何locate这个资源。
- 通过 URL 我们可以访问 Internet 上的各种网络资源,比如最常见的 www, ftp站点。浏览器通过解析给定的 URL 可以在网络上查找相应的文件或其他资源。
- URL的基本结构由5部分组成:<传输协议>://<主机名>:<端口号>/<文件名>#片段名?参数列表
URL构造器
构造器 | 描述 |
---|---|
URL (String spec) | 通过一个表示URL地址的字符串可以构造一个URL对象。 |
URL(URL context, String spec) | 通过基 URL 和相对 URL 构造一个 URL 对象。 |
URL(String protocol, String host, String file) | / |
URL(String protocol, String host, int port, String file) | / |
URL属性:
- public String getProtocol( ) 获取该URL的协议名
- public String getHost( ) 获取该URL的主机名
- public String getPort( ) 获取该URL的端口号
- public String getPath( ) 获取该URL的文件路径
- public String getFile( ) 获取该URL的文件名
- public String getQuery( ) 获取该URL的查询名
- URLConnection类
-
URLConnection:表示到URL所引用的远程对象的连接。当与一个URL建立连接时,首先要在一个 URL 对象上通过方法 openConnection() 生成对应的 URLConnection对象。如果连接过程失败,将产生IOException.
-
URL netchinaren = new URL (“http://www.baidu.com”);
-
URLConnectonn u = netchinaren.openConnection( );
-
-
通过URLConnection对象获取的输入流和输出流,即可以与现有的CGI程序进行交互。
-
URLConnection:表示到URL所引用的远程对象的连接。当与一个URL建立连接时,首先要在一个 URL 对象上通过方法 openConnection() 生成对应的 URLConnection对象。如果连接过程失败,将产生IOException.
-
URL netchinaren = new URL (“http://www.baidu.com/index.shtml”);
-
URLConnectonn u = netchinaren.openConnection( );
-
通过URLConnection对象获取的输入流和输出流,即可以与现有的CGI程序进行交互。
-
- URI、 URL和URN的区别
URI可以分为URL,URN或同时具备locators 和names特性的一个东西。URN作用就好像一个人的名字,URL就像一个人的地址。换句话说:URN确定了东西的身份,URL提供了找到它的方式。
测试
- 下载安装tomcat
- 拷贝一个图片tomcat安装目录下的
webapps\ROOT\
- 启动tomcat
$ cd `tomcat安装目录`\bin\
$ startup
-
浏览器访问http://localhost:8080/white.png,得到图片
-
代码发送http请求,得到响应
-
http协议, 请求和响应
public class TestURL {
@Test
public void test() throws Exception {
URL url = new URL("http://localhost:8080/white.png");//定位资源
HttpURLConnection connection = (HttpURLConnection) url.openConnection();//打开链接
connection.connect();//建立链接
BufferedInputStream in = new BufferedInputStream(connection.getInputStream());
BufferedOutputStream out = new BufferedOutputStream(new FileOutputStream("S-white.png"));
int l;
byte[] bytes = new byte[1024];
while ((l = in.read(bytes)) != -1){
out.write(bytes,0,l);
}
out.flush();
in.close();
out.close();
connection.disconnect();
}
}
解决tomcat
中文乱码
- 进入tomcat安装目录,找到
conf\logging.properties
; - 使用文本编辑器添加
GBK
设置,并注销UTF-8
设置;