网络(Networking)
术语network programming指的是编写跨多个设备(计算机)执行的程序,其中设备都使用网络彼此连接。
J2SE API的java.net包中包含一组类和接口,它们提供低级别的通信详细信息,允许您编写专注于解决手头问题的程序。
java.net包提供对两种常见网络协议的支持 -
TCP -TCP代表传输控制协议,它允许两个应用程序之间的可靠通信。 TCP通常用于因特网协议,称为TCP/IP。
UDP -UDP代表用户数据报协议,这是一种无连接协议,允许在应用程序之间传输数据包。
本章对以下两个主题有了很好的理解 -
Socket Programming - 这是网络中使用最广泛的概念,它已经过详细解释。
URL Processing - 这将单独介绍。 单击此处以了解Java语言中的URL处理 。
套接字编程
套接字使用TCP提供两台计算机之间的通信机制。 客户端程序在通信的末尾创建一个套接字,并尝试将该套接字连接到服务器。
建立连接后,服务器会在通信结束时创建一个套接字对象。 客户端和服务器现在可以通过写入和读取套接字进行通信。
java.net.Socket类表示一个套接字,java.net.ServerSocket类为服务器程序提供了一种监听客户端并与它们建立连接的机制。
使用套接字在两台计算机之间建立TCP连接时,会发生以下步骤 -
服务器实例化ServerSocket对象,表示要在哪个端口号上进行通信。
服务器调用ServerSocket类的accept()方法。 此方法等待,直到客户端连接到给定端口上的服务器。
服务器等待后,客户端实例化Socket对象,指定要连接的服务器名称和端口号。
Socket类的构造函数尝试将客户端连接到指定的服务器和端口号。 如果建立了通信,则客户端现在具有能够与服务器通信的Socket对象。
在服务器端,accept()方法返回对连接到客户端套接字的服务器上的新套接字的引用。
建立连接后,可以使用I/O流进行通信。 每个套接字都有一个OutputStream和一个InputStream。 客户端的OutputStream连接到服务器的InputStream,客户端的InputStream连接到服务器的OutputStream。
TCP是双向通信协议,因此可以同时跨两个流发送数据。 以下是提供完整套接字实现方法的有用类。
ServerSocket类方法
服务器应用程序使用java.net.ServerSocket类来获取端口并侦听客户端请求。
ServerSocket类有四个构造函数 -
Sr.No. | 方法和描述 |
---|---|
1 | public ServerSocket(int port) throws IOException 尝试创建绑定到指定端口的服务器套接字。 如果端口已被另一个应用程序绑定,则会发生异常。 |
2 | public ServerSocket(int port, int backlog) throws IOException 与前一个构造函数类似,backlog参数指定要在等待队列中存储的传入客户端的数量。 |
3 | public ServerSocket(int port, int backlog, InetAddress address) throws IOException 与前一个构造函数类似,InetAddress参数指定要绑定的本地IP地址。 InetAddress用于可能具有多个IP地址的服务器,允许服务器指定其哪个IP地址接受客户端请求。 |
4 | public ServerSocket() throws IOException 创建未绑定的服务器套接字。 使用此构造函数时,在准备绑定服务器套接字时使用bind()方法。 |
如果ServerSocket构造函数没有抛出异常,则意味着您的应用程序已成功绑定到指定的端口并准备好进行客户端请求。
以下是ServerSocket类的一些常用方法 -
Sr.No. | 方法和描述 |
---|---|
1 | public int getLocalPort() 返回服务器套接字正在侦听的端口。 如果在构造函数中传入0作为端口号并让服务器为您找到端口,则此方法很有用。 |
2 | public Socket accept() throws IOException 等待传入的客户端。 假设已使用setSoTimeout()方法设置超时值,此方法将阻塞,直到客户端连接到指定端口上的服务器或套接字超时。 否则,此方法无限期地阻塞。 |
3 | public void setSoTimeout(int timeout) 设置服务器套接字在accept()期间等待客户端的时间的超时值。 |
4 | public void bind(SocketAddress host, int backlog) 将套接字绑定到SocketAddress对象中的指定服务器和端口。 如果已使用无参数构造函数实例化ServerSocket,请使用此方法。 |
当ServerSocket调用accept()时,该方法在客户端连接之前不会返回。 客户端连接后,ServerSocket在未指定的端口上创建一个新的Socket,并返回对此新Socket的引用。 客户端和服务器之间现在存在TCP连接,可以开始通信。
套接字类方法
java.net.Socket类表示客户端和服务器用于相互通信的套接字。 客户端通过实例化一个来获取Socket对象,而服务器从accept()方法的返回值获取Socket对象。
Socket类有五个构造函数,客户端用它们连接到服务器 -
Sr.No. | 方法和描述 |
---|---|
1 | public Socket(String host, int port) throws UnknownHostException, IOException. 此方法尝试连接到指定端口上的指定服务器。 如果此构造函数未引发异常,则连接成功,客户端连接到服务器。 |
2 | public Socket(InetAddress host, int port) throws IOException 此方法与前一个构造函数相同,只是主机由InetAddress对象表示。 |
3 | public Socket(String host, int port, InetAddress localAddress, int localPort) throws IOException. 连接到指定的主机和端口,在指定地址和端口的本地主机上创建套接字。 |
4 | public Socket(InetAddress host, int port, InetAddress localAddress, int localPort) throws IOException. 此方法与前一个构造函数相同,只是主机由InetAddress对象而不是String表示。 |
5 | public Socket() 创建一个未连接的套接字。 使用connect()方法将此套接字连接到服务器。 |
当Socket构造函数返回时,它不是简单地实例化Socket对象,而是实际上尝试连接到指定的服务器和端口。
此处列出了Socket类中感兴趣的一些方法。 请注意,客户端和服务器都有一个Socket对象,因此客户端和服务器都可以调用这些方法。
Sr.No. | 方法和描述 |
---|---|
1 | public void connect(SocketAddress host, int timeout) throws IOException 此方法将套接字连接到指定的主机。 只有在使用无参数构造函数实例化Socket时才需要此方法。 |
2 | public InetAddress getInetAddress() 此方法返回此套接字连接到的另一台计算机的地址。 |
3 | public int getPort() 返回套接字在远程计算机上绑定的端口。 |
4 | public int getLocalPort() 返回套接字在本地计算机上绑定的端口。 |
5 | public SocketAddress getRemoteSocketAddress() 返回远程套接字的地址。 |
6 | public InputStream getInputStream() throws IOException 返回套接字的输入流。 输入流连接到远程套接字的输出流。 |
7 | public OutputStream getOutputStream() throws IOException 返回套接字的输出流。 输出流连接到远程套接字的输入流。 |
8 | public void close() throws IOException 关闭套接字,这使得此Socket对象不再能够再次连接到任何服务器。 |
InetAddress类方法
此类表示Internet协议(IP)地址。 以下是在执行套接字编程时需要的有用方法 -
Sr.No. | 方法和描述 |
---|---|
1 | static InetAddress getByAddress(byte[] addr) 给定原始IP地址返回InetAddress对象。 |
2 | static InetAddress getByAddress(String host, byte[] addr) 根据提供的主机名和IP地址创建InetAddress。 |
3 | static InetAddress getByName(String host) 根据主机名称确定主机的IP地址。 |
4 | String getHostAddress() 返回文本表示中的IP地址字符串。 |
5 | String getHostName() 获取此IP地址的主机名。 |
6 | static InetAddress InetAddress getLocalHost() 返回本地主机。 |
7 | String toString() 将此IP地址转换为String。 |
套接字客户端示例
以下GreetingClient是一个客户端程序,它通过使用套接字连接到服务器并发送问候语,然后等待响应。
例子 (Example)
// File Name GreetingClient.java
import java.net.*;
import java.io.*;
public class GreetingClient {
public static void main(String [] args) {
String serverName = args[0];
int port = Integer.parseInt(args[1]);
try {
System.out.println("Connecting to " + serverName + " on port " + port);
Socket client = new Socket(serverName, port);
System.out.println("Just connected to " + client.getRemoteSocketAddress());
OutputStream outToServer = client.getOutputStream();
DataOutputStream out = new DataOutputStream(outToServer);
out.writeUTF("Hello from " + client.getLocalSocketAddress());
InputStream inFromServer = client.getInputStream();
DataInputStream in = new DataInputStream(inFromServer);
System.out.println("Server says " + in.readUTF());
client.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
套接字服务器示例
以下GreetingServer程序是服务器应用程序的示例,该应用程序使用Socket类来侦听由命令行参数指定的端口号上的客户端 -
例子 (Example)
// File Name GreetingServer.java
import java.net.*;
import java.io.*;
public class GreetingServer extends Thread {
private ServerSocket serverSocket;
public GreetingServer(int port) throws IOException {
serverSocket = new ServerSocket(port);
serverSocket.setSoTimeout(10000);
}
public void run() {
while(true) {
try {
System.out.println("Waiting for client on port " +
serverSocket.getLocalPort() + "...");
Socket server = serverSocket.accept();
System.out.println("Just connected to " + server.getRemoteSocketAddress());
DataInputStream in = new DataInputStream(server.getInputStream());
System.out.println(in.readUTF());
DataOutputStream out = new DataOutputStream(server.getOutputStream());
out.writeUTF("Thank you for connecting to " + server.getLocalSocketAddress()
+ "\nGoodbye!");
server.close();
} catch (SocketTimeoutException s) {
System.out.println("Socket timed out!");
break;
} catch (IOException e) {
e.printStackTrace();
break;
}
}
}
public static void main(String [] args) {
int port = Integer.parseInt(args[0]);
try {
Thread t = new GreetingServer(port);
t.start();
} catch (IOException e) {
e.printStackTrace();
}
}
}
编译客户端和服务器,然后按如下方式启动服务器 -
$ java GreetingServer 6066
Waiting for client on port 6066...
检查客户端程序如下 -
输出 (Output)
$ java GreetingClient localhost 6066
Connecting to localhost on port 6066
Just connected to localhost/127.0.0.1:6066
Server says Thank you for connecting to /127.0.0.1:6066
Goodbye!