Java网络编程与分布式游戏开发
立即解锁
发布时间: 2025-08-19 00:21:08 阅读量: 2 订阅数: 8 


Java编程入门与实践
### Java 网络编程与分布式游戏开发
#### 1. 套接字与安全
在进行网络编程时,我们需要考虑客户端连接服务器以及服务器监听指定套接字的权限问题。在运行非受信任的应用程序时,安全策略会对其可通信的主机以及是否能监听连接进行限制。若要在安全管理器下运行应用程序,需注意默认的安全管理器会禁止所有网络访问。
为了实现网络连接,我们需要修改策略文件以授予代码相应的权限。以下是一个策略文件片段,它允许在任何非特权端口上与任何主机进行连接、监听和接受连接:
```java
grant {
permission java.net.SocketPermission
"*:1024-", "listen,accept,connect";
};
```
在启动 Java 运行时,可以安装安全管理器并使用该策略文件(假设文件名为 `mysecurity.policy`),命令如下:
```bash
% java -Djava.security.manager \
-Djava.security.policy=mysecurity.policy MyApplication
```
#### 2. DateAtHost 客户端
过去,许多联网计算机在知名端口上运行简单的时间服务,这是更通用的网络时间协议(NTP)的前身。`DateAtHost` 类是 `java.util.Date` 的子类,它可以从远程主机获取时间,而不是从本地时钟初始化。
以下是 `DateAtHost` 类的代码:
```java
//file: DateAtHost.java
import java.net.Socket;
import java.io.*;
public class DateAtHost extends java.util.Date {
static int timePort = 37;
// seconds from start of 20th century to Jan 1, 1970 00:00 GMT
static final long offset = 2208988800L;
public DateAtHost( String host ) throws IOException {
this( host, timePort );
}
public DateAtHost( String host, int port ) throws IOException {
Socket server = new Socket( host, port );
DataInputStream din =
new DataInputStream( server.getInputStream() );
int time = din.readInt();
server.close();
setTime( (((1L << 32) + time) - offset) * 1000 );
}
}
```
`DateAtHost` 类提供了两个构造函数。通常使用第一个构造函数,它仅接受远程主机名作为参数;第二个构造函数则允许指定远程时间服务的主机名和端口号。第二个构造函数负责建立连接并设置时间,第一个构造函数通过 `this()` 调用第二个构造函数并使用默认端口。
以下是使用 `DateAtHost` 类获取远程主机时间的示例:
```java
try {
Date d = new DateAtHost( "time.nist.gov" );
System.out.println( "The time over there is: " + d );
}
catch ( IOException e ) { ... }
```
#### 3. 分布式游戏开发
我们可以利用网络编程技能将苹果投掷游戏扩展为多人游戏。本示例采用客户端/服务器模型,一个用户启动服务器,另一个用户作为客户端连接到该服务器。
##### 3.1 设置用户界面
首先,我们需要为游戏添加一个菜单,包含启动服务器和加入游戏的选项。以下是 `AppleToss` 类中设置网络菜单的代码:
```java
private void setupNetworkMenu() {
JMenu netMenu = new JMenu("Multiplayer");
multiplayerHelper = new Multiplayer();
JMenuItem startItem = new JMenuItem("Start Server");
startItem.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent e) {
multiplayerHelper.startServer();
}
});
netMenu.add(startItem);
JMenuItem joinItem = new JMenuItem("Join Game...");
joinItem.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent e) {
String otherServer = JOptionPane.showInputDialog(AppleToss.this,
"Enter server name or address:");
multiplayerHelper.joinGame(otherServer);
}
});
netMenu.add(joinItem);
JMenuItem quitItem = new JMenuItem("Disconnect");
quitItem.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent e) {
multiplayerHelper.disconnect();
}
});
netMenu.add(quitItem);
// build a JMenuBar for the application
JMenuBar mainBar = new JMenuBar();
mainBar.add(netMenu);
setJMenuBar(mainBar);
}
```
##### 3.2 游戏服务器
游戏服务器需要选择一个端口(这里使用 8677)并设置一个监听套接字。我们在 `Multiplayer` 类中创建一个 `Server` 内部类来驱动一个线程进行网络通信。
```java
class Server implements Runnable {
ServerSocket listener;
public void run() {
Socket socket = null;
try {
listener = new ServerSocket(gamePort);
while (keepListening) {
socket = listener.accept(); // wait for connection
InputStream in = socket.getInputStream();
BufferedReader reader =
new BufferedReader( new InputStreamReader(in) );
OutputStream out = socket.getOutputStream();
PrintWriter writer = new PrintWriter(out, true);
// ... game protocol logic starts here
```
要启动服务器监听,只需创建一个使用 `Server` 类的新线程:
```java
// from Multiplayer
Server server;
// ...
public void startServer() {
keepListening = true;
// ... other game state can go here
server = new Server();
serverThread = new Thread(server);
serverThread.start();
}
```
当用户选择断开连接时,我们需要关闭服务器套接字:
```java
// from Multiplayer
public void disconnect() {
disconnecting = true;
keepListening = false;
// Are we in the middle of a game and regularly checking these flags?
// If not, just close the server socket to interrupt the blocking
// accept() method.
if (server != null && keepPlaying == false) {
server.stopListening();
}
// ... clean up other game state here
}
```
`Server` 内部类的 `stopListening()` 方法如下:
```java
public void stopListening() {
if (listener != n
```
0
0
复制全文
相关推荐










