Java 网络
网络编程是指编写程序在多个设备(计算机)上执行,在这些设备上通过网络连接彼此。
J2SE APIs的java.net包含了一组类和接口,提供了低级通信细节的支持,使您能够编写重点解决问题的程序。
java.net包提供了对两种常见网络协议的支持 –
- TCP - TCP代表传输控制协议,允许两个应用程序之间进行可靠的通信。 TCP通常在Internet协议上使用,这称为TCP / IP。
-
UDP - UDP代表用户数据报协议,这是一种无连接的协议,允许数据包在应用程序之间传输。
本章节对以下两个主题进行了很好的说明 –
- 套接字编程 - 这是网络中最常用的概念,并且已经进行了详细解释。
-
URL处理 - 这将分开讨论。点击此处了解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类有四个构造函数−
序号 | 方法和描述 |
---|---|
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地址。对于可能有多个IP地址的服务器,InetAddress用于允许服务器指定要接受客户端请求的IP地址。 |
4 | public ServerSocket() throws IOException 创建一个未绑定的服务器套接字。使用此构造方法时,当准备好绑定服务器套接字时,请使用bind()方法。 |
如果ServerSocket构造函数没有抛出异常,这意味着您的应用程序已成功绑定到指定的端口,并且准备好处理客户端的请求。
以下是ServerSocket类的一些常用方法:
序号 | 方法与描述 |
---|---|
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) 将套接字绑定到指定的服务器和端口。如果您使用无参构造函数实例化了ServerSocket,则使用此方法。 |
当ServerSocket调用accept()方法时,该方法不会返回,直到一个客户端连接。当客户端连接后,ServerSocket会在一个未指定的端口上创建一个新的Socket,并返回对这个新Socket的引用。现在,客户端和服务器之间建立了一个TCP连接,可以开始通信。
Socket类的方法
java.net.Socket 类表示服务器和客户端之间用于通信的socket。客户端通过实例化一个Socket对象来获取它,而服务器通过accept()方法的返回值获取一个Socket对象。
Socket类有五个构造函数可以用于客户端连接服务器:
序号 | 方法与描述 |
---|---|
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对象而不是字符串表示。 |
5 | public Socket() 创建一个未连接的套接字。使用connect()方法将此套接字连接到服务器。 |
当Socket构造函数返回时,它并不只是实例化一个Socket对象,而是尝试连接到指定的服务器和端口。
Socket类中的一些感兴趣的方法如下所示。请注意,客户端和服务器都有一个Socket对象,因此这些方法可以由客户端和服务器调用。
序号 | 方法和描述 |
---|---|
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)地址。以下是在进行套接字编程时需要使用的一些有用方法:
序号 | 方法与描述 |
---|---|
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地址转换为字符串。 |
Socket客户端示例
下面的GreetingClient是一个客户端程序,通过使用套接字连接到服务器并发送问候语,然后等待回应。
示例
// 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();
}
}
}
Socket服务器示例
以下的GreetingServer程序是一个使用Socket类监听由命令行参数指定的端口号上的客户端的服务器应用程序的示例。
示例
// 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...
检查客户端程序如下:
输出
$ 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!