我们编写的服务器端程序一共包括四个类,其名称及功能如下:
Server.java:服务器端主程序负责界面,以及服务端主程序ServerThread的启动,服务端主程序ServerThread又产生BroadCaset及ClientThread线程。
BroadCast.java:服务器向客户端广播线程,负责向客户端发送消息。
ClientThread.java:维持服务器与单个客户端的连接线程,负责接收客户端发来的信息。
ServerThread.java:服务器监听端口线程,负责创建服务器端ServerSocket以及监听是否有新客户端连接,并且记录客户端连接以及需要发送的信息。
上节我们设计好了启动和关闭服务器界面,这节我们主要来讲,如何启动和关闭服务器。当Server.java文件被运行时,首先执行main方法中的代码,创建一个Server类,生成了服务器端的界面,当单击界面上得“启动服务器”按钮时,回创建一个ServerThread对象,并执行该对象中run方法的代码,所以在这里我们通过ServerThread线程来启动和关闭服务器。
下面,就来设计该类的实现。
1、 首先看当单击启动服务器按钮后的界面运行效果,截图如下:
从该界面中,我们可以看到,当我们单击“启动服务器”按钮时,文本框中回出现当前的本地连接IP地址及我们设置的端口号。
2、 实现效果代码如下:
package com.wyf.wpf;
import java.io.IOException;
import java.net.InetAddress;
import java.net.ServerSocket;
import java.net.Socket;
import java.net.UnknownHostException;
import java.util.Vector;
/*服务器监听端口线程*/
public class ServerThread extends Thread {
// 指定服务器监听端口常量
private static final int PORT = 8521;
// 声明ServerSocket类对象
ServerSocket serverSocket;
/*
* 创建一个Vector对象,用于存储客户端连接的ClientThread对象。
* ClientThread类维持服务器与单个客户端的连接线程,负责接收客
* 户端发来的信息,这里为什么使用Vector。因为Vector有自动排序递增功能
*/
Vector<ClientThread> clients;
// 创建一个Vector对象,用于存储客户端发送过来的信息
Vector<Object> messages;
// 声明BroadCast类,负责服务器向客户端广播信息
BroadCast broadcast;
// 声明两个变量,用于获取本地连接IP地址
String ip;
InetAddress myIPAddress = null;
public ServerThread() {
/*
* 创建两个恶Vector数组非常重要。clients负责存储所有与服务器建立连接
* 的客户端。message负责存储服务器接收到的未发送出去的全部客户端的信息
*/
clients = new Vector<ClientThread>();
messages = new Vector<Object>();
try {
serverSocket = new ServerSocket(PORT);
} catch (IOException e) {
}
try {
myIPAddress = InetAddress.getLocalHost();
} catch (UnknownHostException e) {
System.out.println(e.toString());
}
// 获取本地连接地址
ip = myIPAddress.getHostAddress();
// 将该地址信息加入到jTextArea中
Sever.jTextArea.append("服务器地址:" + ip + " 端口号:"
+ String.valueOf(serverSocket.getLocalPort() + "\n"));
// 启动播放消息线程,用于向客户端发送消息
broadcast = new BroadCast(this);
broadcast.start();
}
// 运行线程
@Override
public void run() {
// TODO Auto-generated method stub
super.run();
while (true) {
try {
// 在服务端获取客户端socket
Socket socket = serverSocket.accept();
System.out.println(socket.getInetAddress().getHostAddress());
// 创建客户端线程并启动
ClientThread clientThread = new ClientThread(socket, this);
clientThread.start();
// 如果不为空,则将其添加到clients数组中
if (socket != null) {
synchronized (clients) {
clients.addElement(clientThread);
}
}
} catch (IOException E) {
System.out.println("发生异常:" + E);
System.out.println("建立客户端联机失败!");
System.exit(2);
}
}
}
// 关闭服务端socket
public void finalize() {
try {
serverSocket.close();
} catch (IOException E) {
serverSocket = null;
}
}
}
讲解:
当该类的对象被创建之时,首先创建两个数组,分别用来保存ClientThread对象和消息对象。之后创建一个ServerSocket。创建BroadCast对象,并且启动了该对象线程,即调用了该对象的run()方法,用以不断地向客户端发送消息。当该类的线程被开启后,不断获取得新的客户端,并且将客户端封装在ClientThread之中,然后存于数组当中。开启了ClientThread的线程,用以监听客户端是否有消息。