计算机网络:把分布在不同地理区域的具有独立功能的计算机,通过通信设备与线路 连接起来,由功能完善的软件实现资源共享和信息传递的系统。
什么是Java网络
网络为简单的程序补充了很多力量,通过网络,单个的程序可以重新获得存储在世界任何地方的数百万台计算机中的信息。Java网络是将两个或者多个计算机设备组合在一起以共享资源的概念。所有的Java程序通过网络的通信都是在应用层完成的。java的java.net包中包含执行的低级通讯功能的各种类和接口,使用户能够定制专注于解决问题的程序。
通用网络协议
如上述所述,Java编程语言的java.net包包含各种类的接口,它们提供了一种易于使用的方式来访问网络资源,除了类和接口之外,java.net包还提供对两种众所周知的网络支持。分别为:
- 传输控制协议:TCP——TCP传输控制协议允许不同的应用程序之间的安全通信,TCP是面向连接的协议,这意味着一旦建立连接,数据就可以在两个方向上传输,该协议通过互联网协议使用,因此,TCP也称为TCP/IP。TCP具有内置方法来检查错误并确保发送顺序传输数据,这使其成为传输静态图像,数据文件,和网页等信息的完整协议
- 用户数据报协议:UDP——用户数据报协议是一种无连接协议,允许数据报在不同的应用程序之间的传输,UDP是一种更简单的Internet协议,不需要错误检查和恢复服务。在UDP中,打开连接,维持连接或者终止连接,没有开销,在UDP中,数据会连续的发送给接受者,无论接收者是否收到。
Java网络术语
IP地址
IP地址是区分互联网或者本地网络上的设备的唯一地址。IP代表“互联网协议”。它包含一组管理通过互联网或者本地网络发送的数据格式的规则,IP地址是指可以修改的逻辑地址,IP地址通常使用四个十进制数(每个数的范围为0到255),并由点号分隔开,例如:192.168.1.1。这种格式被称为IPv4地址,是目前互联网上最常用的IP地址格式。
端口号
端口号是一种在连接互联网或者其他网络信息到达服务器时识别特定进程的方法,端口号用于唯一标识不同的应用程序。端口号充当应用程序之间的通讯端点。端口号与IP地址相关联,用于两个应用程序之间的传输和通讯,右65535个端口号,但并非所有端口号每天都使用。
协议
网络协议是一组有组织的命令,定义数据如何在同一网络中的不同设备之间的传输,网络协议是用户可以轻松地与世界各地通讯的原因,因此现在的数字通讯发挥着至关重要的作用,例如,TCP,FTP,POP等。
MAC地址
MAC地址代表媒体访问控制地址。这是分配给NIC(网络接口控制器)的标识,是计算机或设备在网络中的物理地址。每个网络接口都有唯一的MAC地址,用于在局域网中标识设备。MAC地址通常是一个48位的十六进制数,通常以冒号或连字符分隔开,例如:00:1A:2B:3C:4D:5E。MAC地址由网络设备的制造商提前分配,并在生产时固化到设备的网络接口中,因此可以认为它是唯一的并且不可更改的。MAC地址在数据链路层上使用,用于在局域网中的设备之间进行通信和数据传输的寻址。
套接字Socket
套接字是网络上运行的两个应用程序之间双向通信连接的一个端点,套接字机制提供了一种通过设置在其之间发生通信的命名接触点来进行通信(IPC)的方法。套接字与端口号绑定,以便TCP层可以识别数据要发生到的应用程序。
面向连接和无连接协议
在面向连接服务中,用户必须在开始通讯之前建立连接,当连接建立后用户可以发送消息或者信息,之后可以释放连接。然而,在无连接协议中,数据在从源到目的地址的一条路由中传输,而不验证目的地址是否仍然存在或者是是否准备好接收消息,无连接协议中不需要身份验证。
如:面向连接的协议——TCP传输控制协议
面向无连接协议——UDP用户数据报协议
套接字编程
概念
Java Socket编程用于在不同的JRE上运行的应用程序之间进行的通讯,套接字使用TCP实现两台计算机之间的通信工具。JavaSocket编程可以使面向连接的,也可以是无连接的,在套接字编程中Socket和ServerSocket类是为面向连接的套接字编程而管理的,而DatagramSocket和DataPacket类用于无连接套接字编程。
客户端应用程序在其通讯端生成一个套接字,并努力将该套接字与服务器结合起来。当连接建立时,服务器在其通讯短生成一个socket对象。客户端和服务器就可以通过向套接字写入和读取来进行通讯。
Java.net.Socket类描述套接字,而java.net.ServerSocket类实现服务器程序托管客户端并与客户端建立连接的工具。
使用套接字编程在两个计算机设备之间建立TCP连接的步骤
- 步骤一:服务器实例化一个SeverSocket对象,指示将在哪个端口号进行通信。
- 步骤二;实例化SeverSocket对象后,服务器请求ServerSocket类的accept()方法。该程序暂停,直到客户端连接到指定端口上的服务器。
- 步骤三:服务器空闲后,客户端实例化Socket类对象,定义服务器名称和要连接的端口号。
- 步骤四:经过上述步骤后,Socket类的构造函数会努力将客户端连接到指定的服务器和端口号,如果通信经过身份验证,客户端立即拥有一个能够与服务器交互的Socket对象。
- 步骤五:在服务器端,accept()方法返回对服务器上连接到客户端套接字的新套接字的引用。
连接稳定后,可以使用I/O流进行通信。套接字类的每个对象都有一个OutputStream和一个InputStream。客户端的OutputStream和服务器的InputStream相关连,客户端的InputStream与服务器的OutputStream相结合。传输控制协议(TCP)是一种双向通信协议,因此,信息可以在相应的时间通过两个流传输。
套接字类
Socket类用于创建套接字对象,帮助用户实现所有基本套接字操作,用户可以执行各种网络操作,例如发送,读取数据和关闭连接,使用java.net.Socket类创建的每个Socket对象都有一个远程主机 相关。如果用户想要连接到另一台主机,那么他必须构建一个新的套接字对象。
Socket类的方法
在Socket编程中,客户端和服务器端都有一个Socket对象,因此Socket类下的所有方法都可以被客户端和服务器调用,Socket类中有很多方法。
方法 | 描述 | |
---|---|---|
public void connect(SocketAddress host, int timeout) | 此方法用于将套接字连接到特定的主机。 仅当用户应用无参数构造函数实例化 Socket 时才需要此方法 | |
public int getPort() | 此方法用于返回套接字固定在远程计算机上的端口。 | |
public InetAddress getInetAddress() | 此方法用于返回套接字所连接的 另一台计算机的位置 | |
public int getLocalPort() | 该方法用于返回本地计算机上套接字所加入的端口。 | |
public SocketAddress getRemoteSocketAddress() | 该方法返回远程套接字的位置。 | |
public InputStream getInputStream() | 该方法用于返回socket的输入流。 该输入流与远程套接字的输出流组合。 | |
public OutputStream getOutputStream() | 该方法用于返回socket的输出流。 输出流与远程套接字的输入流组合。 | |
public void close() | 该方法用于关闭套接字, 这会导致 Socket 类的对象不再能够再次连接到任何 服务器。 |
服务器套接字类
ServerSocket类用于提供客户端/服务器套接字连接的服务器端口大的系统独立实现。如果ServerSocket类的构造函数无法侦听指定端口,则会发生异常,例如,如果端口已被使用,它会抛出异常。
SeverSocket类的方法:
方法 | 描述 | |
---|---|---|
public int getLocalPort() | 该方法用于返回服务器套接字正在监视的端口。如果用户在构造函数中传递 0 作为端口号并让服务器为他找到端口,则此方法很有用。 | |
public void setSoTimeout(int timeout) | 该方法用于设置在accept()方法期间服务器套接字为客户端暂停的时间的超时值。 | |
public Socket accept() | 此方法等待传入的客户端。考虑到超时值已使用 setSoTimeout() 方法设置,此方法将被阻止,直到客户端在指定端口上与服务器结合或套接字超时。否则,该方法将被无限期地阻止。 | |
public void bind(SocketAddress host, int backlog) | 该方法用于将套接字绑定到 SocketAddress 对象中的特定服务器和端口。如果用户使用无参数构造函数实例化了 ServerSocket,则应使用此方法。 |
Java套接字编程示例
下面的示例说明了一种非常基本的单向客户端和服务器设置,其中客户端连接,向服务器发送消息,服务器使用套接字连接显示它们。
客户端实现
import java.io.*;
import java.net.*;
public class clientSide {
// 初始化 socket 和输入输出流
private Socket socket = null;
private DataInputStream input = null;
private DataOutputStream out = null;
// 构造函数用于设置 IP 地址和端口
public clientSide(String address, int port)
{
// 建立连接
try {
socket = new Socket(address, port);
System.out.println("已连接");
// 从终端获取输入
input = new DataInputStream(System.in);
// 发送输出到 socket
out = new DataOutputStream(
socket.getOutputStream());
}
catch (UnknownHostException u) {
System.out.println(u);
}
catch (IOException i) {
System.out.println(i);
}
// 用于读取输入消息的字符串
String line = "";
// 循环读取直到输入 "End"
while (!line.equals("End")) {
try {
line = input.readLine();
out.writeUTF(line);
}
catch (IOException i) {
System.out.println(i);
}
}
// 关闭连接
try {
input.close();
out.close();
socket.close();
}
catch (IOException i) {
System.out.println(i);
}
}
public static void main(String[] args)
{
clientSide client
= new clientSide("127.0.0.1", 5000);
}
}
代码解释
-
import
语句:引入所需的Java类库。 -
public class clientSide { ... }
:定义一个名为clientSide
的公共类。 -
Socket
、DataInputStream
和DataOutputStream
:这些是Java网络编程中的类,用于处理与服务器的连接、输入和输出。 -
socket
、input
和out
:这些是类中的私有变量,用于存储与服务器的连接、输入流和输出流。 -
构造函数
clientSide(String address, int port)
:这是类的构造函数,接受服务器的IP地址和端口号作为参数。在构造函数中,程序尝试建立与指定服务器的连接,如果成功,则打印"已连接"。 -
在
try-catch
块中,程序尝试建立连接并初始化输入输出流。如果连接失败,则会捕获UnknownHostException
或IOException
异常,并输出异常信息。 -
while
循环:在循环中,程序不断从终端读取输入(使用input.readLine()
),直到输入"End"为止。然后将输入的消息发送到服务器(使用out.writeUTF(line)
)。 -
try-catch
块:在循环外部,程序尝试关闭输入输出流和socket连接,如果关闭失败,则捕获异常并输出异常信息。 -
main
方法:在main
方法中,创建了一个clientSide
对象,并传递服务器的IP地址和端口号作为参数,这样就启动了客户端程序。
服务器端实现
import java.io.*;
import java.net.*;
public class serverSide {
// 初始化 socket 和输入流
private Socket socket = null;
private ServerSocket server = null;
private DataInputStream in = null;
// 构造函数,指定端口号
public serverSide(int port)
{
// 启动服务器并等待连接
try {
server = new ServerSocket(port);
System.out.println("服务器已启动");
System.out.println("等待客户端连接...");
socket = server.accept();
System.out.println("客户端已连接");
// 从客户端 socket 接收输入
in = new DataInputStream(
new BufferedInputStream(
socket.getInputStream()));
String line = "";
// 读取客户端的消息直到收到 "End" 为止
while (!line.equals("End")) {
try {
line = in.readUTF();
System.out.println(line);
}
catch (IOException i) {
System.out.println(i);
}
}
System.out.println("关闭连接");
// 关闭连接
socket.close();
in.close();
}
catch (IOException i) {
System.out.println(i);
}
}
public static void main(String[] args)
{
serverSide server = new serverSide(5000);
}
}
代码解释:
-
import
语句:引入所需的Java类库。 -
public class serverSide { ... }
:定义一个名为serverSide
的公共类。 -
Socket
、ServerSocket
和DataInputStream
:这些是Java网络编程中的类,用于处理与客户端的连接、服务器的监听和输入流。 -
socket
、server
和in
:这些是类中的私有变量,用于存储与客户端的连接、服务器socket和输入流。 -
构造函数
serverSide(int port)
:这是类的构造函数,接受服务器端口号作为参数。在构造函数中,程序尝试启动服务器并等待客户端连接。 -
在
try-catch
块中,程序尝试启动服务器并等待客户端连接。如果启动或连接失败,则会捕获IOException
异常,并输出异常信息。 -
一旦与客户端建立了连接,程序会打印"客户端已连接",然后创建一个输入流,用于从客户端接收消息。
-
while
循环:在循环中,程序不断读取来自客户端的输入流,直到接收到"End"为止。然后程序会打印收到的消息,并关闭与客户端的连接。 -
main
方法:在main
方法中,创建了一个serverSide
对象,并指定服务器的端口号为5000,这样就启动了服务器程序。
打开两个Java运行窗口,一个用于服务器,一个用于客户端。
首先运行服务器程序,它将显示
服务器已启动
等待客户端连接...
然后在另一个运行窗口运行客户端程序,它将显示
已连接
服务器端将显示
服务器已启动
等待客户端连接...
客户端已连接
然后就可以在客户端窗口输入消息,这是输出示例
完毕